Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

automerge-repo-solid-primitives

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

automerge-repo-solid-primitives - npm Package Compare versions

Comparing version 1.0.3 to 1.1.0

.assets/automerge.png

263

output/index.js

@@ -1,52 +0,52 @@

import { createContext as W, useContext as x, createResource as p, createEffect as O, on as A, onCleanup as D, $PROXY as s, $TRACK as k, getListener as R, batch as F, createSignal as z, getOwner as H, runWithOwner as L } from "solid-js";
import { fromAutomerge as V, apply as q } from "cabbages";
const M = W(null);
function X() {
const e = x(M);
import { createContext as F, useContext as D, createResource as j, createEffect as p, on as $, onCleanup as _, $PROXY as s, $TRACK as k, getListener as R, batch as q, createSignal as z, getOwner as H, runWithOwner as L } from "solid-js";
import { fromAutomerge as V, apply as M } from "cabbages";
const C = F(null);
function v() {
const e = D(C);
if (!e) throw new Error("Please wrap me in a <RepoContext value={repo}>");
return e;
}
function Y(e) {
let n = X(), [t, { mutate: r }] = p(e, (o) => {
if (!o)
return;
let f = n.find(o);
return f.isReady() ? f : f.whenReady().then(() => f);
function X(e, n) {
let t = D(C);
if (!n?.repo && !t)
throw new Error("use outside <RepoContext> requires options.repo");
let o = n?.repo || t, [r, { mutate: f }] = j(e, (c) => {
if (!c) return;
let i = o.find(c);
return i.isReady() ? i : i.whenReady().then(() => i);
});
return O(
A([e], () => {
e() || r();
})
), t;
return p($(e, (c) => c || f())), r;
}
function ee(e, n) {
let t = Y(e), [r, { refetch: o, mutate: f }] = p(t, (c) => c.doc(), {
initialValue: t()?.docSync(),
storage: n?.storage
let t = X(e, n), [o, { refetch: r, mutate: f }] = j(t, (i) => i.doc(), {
initialValue: t()?.docSync()
});
return O(
A(t, (c) => {
c?.on("change", o), c?.on("delete", o), D(() => {
c?.off("change", o), c?.off("delete", o);
function c() {
f(), r();
}
return p(
$(t, (i) => {
i?.on("change", r), i?.on("delete", c), _(() => {
i?.off("change", r), i?.off("delete", c);
});
})
), O(A(t, (c) => c || f())), O(A(e, (c) => c || f)), [
r,
(c, u) => {
t()?.change(c, u);
), p($(e, (i) => i || f())), [
o,
(i, u) => {
t()?.change(i, u);
}
];
}
const b = Symbol("store-raw"), a = Symbol("store-node"), l = Symbol("store-has"), _ = Symbol("store-self");
function C(e) {
const O = Symbol("store-raw"), a = Symbol("store-node"), l = Symbol("store-has"), x = Symbol("store-self");
function E(e) {
let n = e[s];
if (!n && (Object.defineProperty(e, s, {
value: n = new Proxy(e, I)
value: n = new Proxy(e, G)
}), !Array.isArray(e))) {
const t = Object.keys(e), r = Object.getOwnPropertyDescriptors(e);
for (let o = 0, f = t.length; o < f; o++) {
const c = t[o];
r[c].get && Object.defineProperty(e, c, {
enumerable: r[c].enumerable,
get: r[c].get.bind(n)
const t = Object.keys(e), o = Object.getOwnPropertyDescriptors(e);
for (let r = 0, f = t.length; r < f; r++) {
const c = t[r];
o[c].get && Object.defineProperty(e, c, {
enumerable: o[c].enumerable,
get: o[c].get.bind(n)
});

@@ -61,19 +61,19 @@ }

}
function g(e, n = /* @__PURE__ */ new Set()) {
let t, r, o, f;
if (t = e != null && e[b]) return t;
function y(e, n = /* @__PURE__ */ new Set()) {
let t, o, r, f;
if (t = e != null && e[O]) return t;
if (!d(e) || n.has(e)) return e;
if (Array.isArray(e)) {
Object.isFrozen(e) ? e = e.slice(0) : n.add(e);
for (let c = 0, u = e.length; c < u; c++)
o = e[c], (r = g(o, n)) !== o && (e[c] = r);
for (let c = 0, i = e.length; c < i; c++)
r = e[c], (o = y(r, n)) !== r && (e[c] = o);
} else {
Object.isFrozen(e) ? e = Object.assign({}, e) : n.add(e);
const c = Object.keys(e), u = Object.getOwnPropertyDescriptors(e);
for (let i = 0, $ = c.length; i < $; i++)
f = c[i], !u[f].get && (o = e[f], (r = g(o, n)) !== o && (e[f] = r));
const c = Object.keys(e), i = Object.getOwnPropertyDescriptors(e);
for (let u = 0, P = c.length; u < P; u++)
f = c[u], !i[f].get && (r = e[f], (o = y(r, n)) !== r && (e[f] = o));
}
return e;
}
function P(e, n) {
function A(e, n) {
let t = e[n];

@@ -86,35 +86,35 @@ return t || Object.defineProperty(e, n, {

if (e[n]) return e[n];
const [r, o] = z(t, {
const [o, r] = z(t, {
equals: !1,
internal: !0
});
return r.$ = o, e[n] = r;
return o.$ = r, e[n] = o;
}
function B(e, n) {
function Y(e, n) {
const t = Reflect.getOwnPropertyDescriptor(e, n);
return !t || t.get || !t.configurable || n === s || n === a || (delete t.value, delete t.writable, t.get = () => e[s][n]), t;
}
function E(e) {
R() && h(P(e, a), _)();
function K(e) {
R() && h(A(e, a), x)();
}
function G(e) {
return E(e), Reflect.ownKeys(e);
function B(e) {
return K(e), Reflect.ownKeys(e);
}
const I = {
const G = {
get(e, n, t) {
if (n === b) return e;
if (n === O) return e;
if (n === s) return t;
if (n === k)
return E(e), t;
const r = P(e, a), o = r[n];
let f = o ? o() : e[n];
return K(e), t;
const o = A(e, a), r = o[n];
let f = r ? r() : e[n];
if (n === a || n === l || n === "__proto__") return f;
if (!o) {
if (!r) {
const c = Object.getOwnPropertyDescriptor(e, n);
R() && (typeof f != "function" || e.hasOwnProperty(n)) && !(c && c.get) && (f = h(r, n, f)());
R() && (typeof f != "function" || e.hasOwnProperty(n)) && !(c && c.get) && (f = h(o, n, f)());
}
return d(f) ? C(f) : f;
return d(f) ? E(f) : f;
},
has(e, n) {
return n === b || n === s || n === k || n === a || n === l || n === "__proto__" ? !0 : (R() && h(P(e, l), n)(), n in e);
return n === O || n === s || n === k || n === a || n === l || n === "__proto__" ? !0 : (R() && h(A(e, l), n)(), n in e);
},

@@ -127,93 +127,93 @@ set() {

},
ownKeys: G,
getOwnPropertyDescriptor: B
ownKeys: B,
getOwnPropertyDescriptor: Y
};
function y(e, n, t, r = !1) {
if (!r && e[n] === t) return;
const o = e[n], f = e.length;
t === void 0 ? (delete e[n], e[l] && e[l][n] && o !== void 0 && e[l][n].$()) : (e[n] = t, e[l] && e[l][n] && o === void 0 && e[l][n].$());
let c = P(e, a), u;
if ((u = h(c, n, o)) && u.$(() => t), Array.isArray(e) && e.length !== f) {
for (let i = e.length; i < f; i++) (u = c[i]) && u.$();
(u = h(c, "length", f)) && u.$(e.length);
function g(e, n, t, o = !1) {
if (!o && e[n] === t) return;
const r = e[n], f = e.length;
t === void 0 ? (delete e[n], e[l] && e[l][n] && r !== void 0 && e[l][n].$()) : (e[n] = t, e[l] && e[l][n] && r === void 0 && e[l][n].$());
let c = A(e, a), i;
if ((i = h(c, n, r)) && i.$(() => t), Array.isArray(e) && e.length !== f) {
for (let u = e.length; u < f; u++) (i = c[u]) && i.$();
(i = h(c, "length", f)) && i.$(e.length);
}
(u = c[_]) && u.$();
(i = c[x]) && i.$();
}
function K(e, n) {
function N(e, n) {
const t = Object.keys(n);
for (let r = 0; r < t.length; r += 1) {
const o = t[r];
y(e, o, n[o]);
for (let o = 0; o < t.length; o += 1) {
const r = t[o];
g(e, r, n[r]);
}
}
function J(e, n) {
if (typeof n == "function" && (n = n(e)), n = g(n), Array.isArray(n)) {
function I(e, n) {
if (typeof n == "function" && (n = n(e)), n = y(n), Array.isArray(n)) {
if (e === n) return;
let t = 0, r = n.length;
for (; t < r; t++) {
const o = n[t];
e[t] !== o && y(e, t, o);
let t = 0, o = n.length;
for (; t < o; t++) {
const r = n[t];
e[t] !== r && g(e, t, r);
}
y(e, "length", r);
} else K(e, n);
g(e, "length", o);
} else N(e, n);
}
function w(e, n, t = []) {
let r, o = e;
let o, r = e;
if (n.length > 1) {
r = n.shift();
const c = typeof r, u = Array.isArray(e);
if (Array.isArray(r)) {
for (let i = 0; i < r.length; i++)
w(e, [r[i]].concat(n), t);
o = n.shift();
const c = typeof o, i = Array.isArray(e);
if (Array.isArray(o)) {
for (let u = 0; u < o.length; u++)
w(e, [o[u]].concat(n), t);
return;
} else if (u && c === "function") {
for (let i = 0; i < e.length; i++)
r(e[i], i) && w(e, [i].concat(n), t);
} else if (i && c === "function") {
for (let u = 0; u < e.length; u++)
o(e[u], u) && w(e, [u].concat(n), t);
return;
} else if (u && c === "object") {
} else if (i && c === "object") {
const {
from: i = 0,
to: $ = e.length - 1,
by: T = 1
} = r;
for (let j = i; j <= $; j += T)
w(e, [j].concat(n), t);
from: u = 0,
to: P = e.length - 1,
by: W = 1
} = o;
for (let S = u; S <= P; S += W)
w(e, [S].concat(n), t);
return;
} else if (n.length > 1) {
w(e[r], n, [r].concat(t));
w(e[o], n, [o].concat(t));
return;
}
o = e[r], t = [r].concat(t);
r = e[o], t = [o].concat(t);
}
let f = n[0];
typeof f == "function" && (f = f(o, t), f === o) || r === void 0 && f == null || (f = g(f), r === void 0 || d(o) && d(f) && !Array.isArray(f) ? K(o, f) : y(e, r, f));
typeof f == "function" && (f = f(r, t), f === r) || o === void 0 && f == null || (f = y(f), o === void 0 || d(r) && d(f) && !Array.isArray(f) ? N(r, f) : g(e, o, f));
}
function Q(...[e, n]) {
const t = g(e || {}), r = Array.isArray(t), o = C(t);
function J(...[e, n]) {
const t = y(e || {}), o = Array.isArray(t), r = E(t);
function f(...c) {
F(() => {
r && c.length === 1 ? J(t, c[0]) : w(t, c);
q(() => {
o && c.length === 1 ? I(t, c[0]) : w(t, c);
});
}
return [o, f];
return [r, f];
}
const S = /* @__PURE__ */ new WeakMap(), N = {
const b = /* @__PURE__ */ new WeakMap(), T = {
get(e, n) {
if (n === b) return e;
if (n === O) return e;
const t = e[n];
let r;
return d(t) ? S.get(t) || (S.set(t, r = new Proxy(t, N)), r) : t;
let o;
return d(t) ? b.get(t) || (b.set(t, o = new Proxy(t, T)), o) : t;
},
set(e, n, t) {
return y(e, n, g(t)), !0;
return g(e, n, y(t)), !0;
},
deleteProperty(e, n) {
return y(e, n, void 0, !0), !0;
return g(e, n, void 0, !0), !0;
}
};
function U(e) {
function Q(e) {
return (n) => {
if (d(n)) {
let t;
(t = S.get(n)) || S.set(n, t = new Proxy(n, N)), e(t);
(t = b.get(n)) || b.set(n, t = new Proxy(n, T)), e(t);
}

@@ -223,34 +223,33 @@ return n;

}
function Z(e) {
return U((n) => {
function U(e) {
return Q((n) => {
for (let t of e) {
const [r, o, f] = V(t);
q(r, n, o, f);
const [o, r, f] = V(t);
M(o, n, r, f);
}
});
}
function ne(e, n) {
let t = H(), [r] = p(
function ne(e) {
let n = H(), [t] = j(
e,
async (o) => {
await o.whenReady();
let [f, c] = Q(o.docSync());
function u(i) {
c(Z(i.patches));
let [r, f] = J(o.docSync());
function c(i) {
f(U(i.patches));
}
return o.on("change", u), L(t, () => D(() => o.off("change", u))), f;
return o.on("change", c), L(n, () => _(() => o.off("change", c))), r;
},
{
initialValue: e()?.docSync(),
storage: n?.storage
initialValue: e()?.docSync()
}
);
return r;
return t;
}
export {
M as RepoContext,
C as RepoContext,
ne as createDocumentStore,
ee as useDocument,
Y as useHandle,
X as useRepo
X as useHandle,
v as useRepo
};

@@ -1,8 +0,7 @@

import { AnyDocumentId, ChangeFn, Doc, DocHandle } from '@automerge/automerge-repo/slim';
import { AnyDocumentId, ChangeFn, Doc } from '@automerge/automerge-repo/slim';
import { ChangeOptions } from '@automerge/automerge/slim/next';
import { Resource, ResourceOptions } from 'solid-js';
import { Resource } from 'solid-js';
import { BaseOptions } from './types.ts';
export declare function useDocument<T>(id: () => AnyDocumentId | undefined, options?: {
storage?: ResourceOptions<Doc<T>, DocHandle<T>>["storage"];
}): [
export declare function useDocument<T>(id: () => AnyDocumentId | undefined, options?: BaseOptions): [
Resource<Doc<T> | undefined>,

@@ -9,0 +8,0 @@ (changeFn: ChangeFn<T>, options?: ChangeOptions<T> | undefined) => void

import { AnyDocumentId, DocHandle } from '@automerge/automerge-repo/slim';
import { Resource } from 'solid-js';
import { BaseOptions } from './types.ts';

@@ -9,3 +10,3 @@ /** A hook which returns a {@link DocHandle} identified by a URL.

*/
export declare function useHandle<T>(id: () => AnyDocumentId | undefined): Resource<DocHandle<T> | undefined>;
export declare function useHandle<T>(id: () => AnyDocumentId | undefined, options?: BaseOptions): Resource<DocHandle<T> | undefined>;
//# sourceMappingURL=handle.d.ts.map
import { ChangeFn, Doc, DocHandle } from '@automerge/automerge-repo';
import { Accessor, ResourceOptions } from 'solid-js';
import { Accessor } from 'solid-js';
import { Store } from 'solid-js/store';
export type DocumentStore<T> = [Store<Doc<T>>, (fn: ChangeFn<T>) => void];
export interface DocumentStoreOptions<T> {
storage?: ResourceOptions<Doc<T>, DocHandle<T>>["storage"];
}
export declare function createDocumentStore<T>(handle: Accessor<DocHandle<T> | undefined>, options?: DocumentStoreOptions<T>): import('solid-js').Resource<Doc<T>>;
export declare function createDocumentStore<T>(handle: Accessor<DocHandle<T> | undefined>): import('solid-js').Resource<Doc<T>>;
//# sourceMappingURL=document-store.d.ts.map
{
"name": "automerge-repo-solid-primitives",
"version": "1.0.3",
"version": "1.1.0",
"description": "automerge-repo primitives for your solidjs app",

@@ -17,26 +17,22 @@ "type": "module",

"@automerge/automerge": "^2.2.8",
"@automerge/automerge-repo": "^1.2.1",
"@automerge/automerge-repo-network-broadcastchannel": "^1.2.1",
"@automerge/automerge-repo-network-websocket": "^1.2.1",
"@automerge/automerge-repo-storage-indexeddb": "^1.2.1",
"@automerge/automerge-repo": "2.0.0-alpha.11",
"@solidjs/testing-library": "^0.8.9",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/user-event": "^14.5.2",
"eslint": "^9.8.0",
"eslint-plugin-solid": "^0.14.1",
"eslint": "^9.11.0",
"eslint-plugin-solid": "^0.14.3",
"globals": "^15.9.0",
"jsdom": "^24.1.1",
"jsdom": "^24.1.3",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"solid-js": "^1.8.19",
"typescript": "^5.5.4",
"typescript-eslint": "^8.0.1",
"vite": "^5.3.5",
"solid-js": "^1.8.22",
"typescript": "^5.6.2",
"typescript-eslint": "^8.6.0",
"vite": "^5.4.7",
"vite-plugin-dts": "4.0.0-beta.2",
"vite-plugin-solid": "^2.10.2",
"vite-plugin-wasm": "^3.3.0",
"vitest": "^2.0.5"
"vitest": "^2.1.1"
},
"peerDependencies": {
"@automerge/automerge-repo": "^1.2.1",
"solid-js": "^1.8.19"

@@ -43,0 +39,0 @@ },

# Solid Primitives for Automerge Repo
These hooks are provided as helpers for using Automerge in your SolidJS project.
Helpers for using <a href="https://automerge.org/docs/repositories/">
<img alt="" src=.assets/automerge.png width=22 height=22>
Automerge
</a> with <a href="https://www.solidjs.com/">
<img alt="" src=.assets/solid.png width=22 height=22>
SolidJS
</a>.
## `<RepoProvider repo={Repo}/>`
## RepoContext
Wrapper context required in Automerge-Repo Solid apps
A convenience context for Automerge-Repo Solid apps. Optional: if you prefer you
can pass a repo as an option to `useHandle` or `useDocument`.
## `useRepo(): Repo`
```tsx
<RepoContext.Provider repo={Repo}>
<App />
</RepoContext.Provider>
```
Get a the current repo from the context.
## useRepo
## `useHandle<T>(() => AnyDocumentId): Resource<Handle>`
Get the repo from the [context](#repocontext).
Get a handle from the repo.
```ts
useRepo(): Repo
```
## `useDocument<T>(() => AnyDocumentId): [Resource<T>, (fn: changeFn<T>) => void]`
### e.g.
Get a document and change function from the repo.
```ts
let repo = useRepo()
```
## `createDocumentStore<T>(() => Handle<T>): Resource<Doc<T>>`
## useHandle
Create a store for a handle's document. We subscribe to the handle's changes,
and apply the incoming patches to the precise the fields of the store that have
changed to provide fine-grained reactivity that's consistent across space and
time.
Get a [handle](https://automerge.org/docs/repositories/dochandles/) from the repo as a [resource](https://docs.solidjs.com/reference/basic-reactivity/create-resource).
```ts
useHandle<T>(
() => AnyDocumentId,
options?: {repo: Repo}
): Resource<Handle<T>>
```
### e.g.
```ts
let handle = useHandle(id)
// or
let handle = useHandle(id, {repo})
```
The `repo` option can be left out if you are using [RepoContext](#repocontext).
## useDocument
Get a document and change function from the repo as a [resource](https://docs.solidjs.com/reference/basic-reactivity/create-resource).
```ts
useDocument<T>(
() => AnyDocumentId,
options?: {repo: Repo}
): [Resource<T>, (fn: changeFn<T>) => void]
```
### e.g.
```ts
let [doc, change] = useDocument(id)
// or
let [doc, change] = useDocument(id, {repo})
```
The `repo` option can be left out if you are using [RepoContext](#repocontext).
## createDocumentStore
Create a store for a handle's document. It's subscribed to the handle's changes,
and converts incoming automerge operations to store updates, providing
fine-grained reactivity that's consistent across space and time.
```ts
createDocumentStore<T>(
() => Handle<T>
): Resource<Doc<T>>
```
### e.g.
```ts
let handle = useHandle(id, {repo})
let doc = createDocumentStore(handle)
return <h1>{doc.items[1].title}</h1>
```

@@ -16,10 +16,8 @@ import type {

type Resource,
type ResourceOptions,
} from "solid-js"
import type {BaseOptions} from "./types.ts"
export function useDocument<T>(
id: () => AnyDocumentId | undefined,
options?: {
storage?: ResourceOptions<Doc<T>, DocHandle<T>>["storage"]
}
options?: BaseOptions
): [

@@ -29,3 +27,3 @@ Resource<Doc<T> | undefined>,

] {
let handle = useHandle<T>(id)
let handle = useHandle<T>(id, options)
let [doc, {refetch, mutate}] = createResource<

@@ -36,12 +34,16 @@ Doc<T | undefined>,

initialValue: handle()?.docSync(),
storage: options?.storage,
})
function ondelete() {
mutate()
refetch()
}
createEffect(
on(handle, handle => {
handle?.on("change", refetch)
handle?.on("delete", refetch)
handle?.on("delete", ondelete)
onCleanup(() => {
handle?.off("change", refetch)
handle?.off("delete", refetch)
handle?.off("delete", ondelete)
})

@@ -51,4 +53,3 @@ })

createEffect(on(handle, handle => handle || mutate()))
createEffect(on(id, id => id || mutate))
createEffect(on(id, id => id || mutate()))

@@ -55,0 +56,0 @@ return [

import type {AnyDocumentId, DocHandle} from "@automerge/automerge-repo/slim"
import {useRepo} from "./repo.ts"
import {createEffect, createResource, on, type Resource} from "solid-js"
import {RepoContext} from "./repo.ts"
import {
createEffect,
createResource,
on,
useContext,
type Resource,
} from "solid-js"
import type {BaseOptions} from "./types.ts"
// todo is this complicated for no reason?
// should i just return the result of repo.find(id())?
/** A hook which returns a {@link DocHandle} identified by a URL.

@@ -14,27 +18,18 @@ *

export function useHandle<T>(
id: () => AnyDocumentId | undefined
id: () => AnyDocumentId | undefined,
options?: BaseOptions
): Resource<DocHandle<T> | undefined> {
let repo = useRepo()
let contextRepo = useContext(RepoContext)
if (!options?.repo && !contextRepo) {
throw new Error("use outside <RepoContext> requires options.repo")
}
let repo = (options?.repo || contextRepo)!
let [handle, {mutate}] = createResource(id, id => {
if (!id) {
return
}
if (!id) return
let handle = repo.find<T>(id)
if (handle.isReady()) {
return handle
}
if (handle.isReady()) return handle
return handle.whenReady().then(() => handle)
})
createEffect(
on([id], () => {
if (!id()) {
mutate()
}
})
)
createEffect(on(id, id => id || mutate()))
return handle
}
import {Repo} from "@automerge/automerge-repo/slim"
import {createContext, useContext, type JSXElement} from "solid-js"
import {createContext, useContext} from "solid-js"

@@ -4,0 +4,0 @@ /**

@@ -8,3 +8,3 @@ import {createResource, getOwner, onCleanup, runWithOwner} from "solid-js"

} from "@automerge/automerge-repo"
import type {Accessor, ResourceOptions} from "solid-js"
import type {Accessor} from "solid-js"
import {createStore, produce, type Store} from "solid-js/store"

@@ -25,9 +25,4 @@ import type {Patch} from "@automerge/automerge"

export interface DocumentStoreOptions<T> {
storage?: ResourceOptions<Doc<T>, DocHandle<T>>["storage"]
}
export function createDocumentStore<T>(
handle: Accessor<DocHandle<T> | undefined>,
options?: DocumentStoreOptions<T>
handle: Accessor<DocHandle<T> | undefined>
) {

@@ -40,3 +35,2 @@ let owner = getOwner()

await handle.whenReady()
let [document, update] = createStore(handle.docSync() as Doc<T>)

@@ -47,2 +41,3 @@

}
handle.on("change", patch)

@@ -54,3 +49,2 @@ runWithOwner(owner, () => onCleanup(() => handle.off("change", patch)))

initialValue: handle()?.docSync(),
storage: options?.storage,
}

@@ -57,0 +51,0 @@ )

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc