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

@electric-sql/pglite

Package Overview
Dependencies
Maintainers
3
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@electric-sql/pglite - npm Package Compare versions

Comparing version 0.1.5 to 0.2.0-alpha.0

dist/chunk-MAGDP6ZW.js

348

dist/index.d.ts
/// <reference types="node" />
import { D as DebugLevel, P as PGliteInterface, F as FilesystemType, a as PGliteOptions, Q as QueryOptions, R as Results, T as Transaction, E as ExecProtocolOptions, B as BackendMessage$1, b as ParserOptions } from './interface-Be6LYDxW.js';
export { d as Row, c as RowMode, m as messages } from './interface-Be6LYDxW.js';
import { P as PGliteInterface, F as Filesystem, a as PostgresMod, D as DebugLevel, b as PGliteOptions, Q as QueryOptions, R as Results, T as Transaction, E as ExecProtocolOptions, B as BackendMessage$1, c as PGliteInterfaceExtensions, d as ParserOptions } from './interface-y94vF3S2.js';
export { k as DumpDataDirResult, i as Extension, h as ExtensionSetup, g as ExtensionSetupResult, j as Extensions, e as FilesystemType, l as Row, f as RowMode, m as messages } from './interface-y94vF3S2.js';
/** Based on https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts */
/** Other WebAssembly declarations, for compatibility with older versions of Typescript */
declare namespace WebAssembly {
interface Module {}
}
declare namespace Emscripten {
interface FileSystemType {}
type EnvironmentType = "WEB" | "NODE" | "SHELL" | "WORKER";
type JSType = "number" | "string" | "array" | "boolean";
type TypeCompatibleWithC = number | string | any[] | boolean;
type CIntType = "i8" | "i16" | "i32" | "i64";
type CFloatType = "float" | "double";
type CPointerType =
| "i8*"
| "i16*"
| "i32*"
| "i64*"
| "float*"
| "double*"
| "*";
type CType = CIntType | CFloatType | CPointerType;
type WebAssemblyImports = Array<{
name: string;
kind: string;
}>;
type WebAssemblyExports = Array<{
module: string;
name: string;
kind: string;
}>;
interface CCallOpts {
async?: boolean | undefined;
}
}
interface EmscriptenModule {
print(str: string): void;
printErr(str: string): void;
arguments: string[];
environment: Emscripten.EnvironmentType;
preInit: Array<{ (mod: EmscriptenModule): void }>;
preRun: Array<{ (mod: EmscriptenModule): void }>;
postRun: Array<{ (mod: EmscriptenModule): void }>;
onAbort: { (what: any): void };
onRuntimeInitialized: { (): void };
preinitializedWebGLContext: WebGLRenderingContext;
noInitialRun: boolean;
noExitRuntime: boolean;
logReadFiles: boolean;
filePackagePrefixURL: string;
wasmBinary: ArrayBuffer;
destroy(object: object): void;
getPreloadedPackage(
remotePackageName: string,
remotePackageSize: number
): ArrayBuffer;
instantiateWasm(
imports: Emscripten.WebAssemblyImports,
successCallback: (module: WebAssembly.Module) => void
): Emscripten.WebAssemblyExports;
locateFile(url: string, scriptDirectory: string): string;
onCustomMessage(event: MessageEvent): void;
// USE_TYPED_ARRAYS == 1
HEAP: Int32Array;
IHEAP: Int32Array;
FHEAP: Float64Array;
// USE_TYPED_ARRAYS == 2
HEAP8: Int8Array;
HEAP16: Int16Array;
HEAP32: Int32Array;
HEAPU8: Uint8Array;
HEAPU16: Uint16Array;
HEAPU32: Uint32Array;
HEAPF32: Float32Array;
HEAPF64: Float64Array;
HEAP64: BigInt64Array;
HEAPU64: BigUint64Array;
TOTAL_STACK: number;
TOTAL_MEMORY: number;
FAST_MEMORY: number;
addOnPreRun(cb: () => any): void;
addOnInit(cb: () => any): void;
addOnPreMain(cb: () => any): void;
addOnExit(cb: () => any): void;
addOnPostRun(cb: () => any): void;
preloadedImages: any;
preloadedAudios: any;
_malloc(size: number): number;
_free(ptr: number): void;
}
interface FS {
Lookup: {
path: string;
node: FSNode;
};
FSStream: {};
FSNode: {};
ErrnoError: {};
ignorePermissions: boolean;
trackingDelegate: any;
tracking: any;
genericErrors: any;
filesystems: {
NODEFS: Emscripten.FileSystemType;
MEMFS: Emscripten.FileSystemType;
IDBFS: Emscripten.FileSystemType;
};
//
// paths
//
lookupPath(path: string, opts: any): Lookup;
getPath(node: FSNode): string;
//
// nodes
//
isFile(mode: number): boolean;
isDir(mode: number): boolean;
isLink(mode: number): boolean;
isChrdev(mode: number): boolean;
isBlkdev(mode: number): boolean;
isFIFO(mode: number): boolean;
isSocket(mode: number): boolean;
//
// devices
//
major(dev: number): number;
minor(dev: number): number;
makedev(ma: number, mi: number): number;
registerDevice(dev: number, ops: any): void;
//
// core
//
syncfs(populate: boolean, callback: (e: any) => any): void;
syncfs(callback: (e: any) => any, populate?: boolean): void;
mount(type: Emscripten.FileSystemType, opts: any, mountpoint: string): any;
unmount(mountpoint: string): void;
mkdir(path: string, mode?: number): any;
mkdev(path: string, mode?: number, dev?: number): any;
symlink(oldpath: string, newpath: string): any;
rename(old_path: string, new_path: string): void;
rmdir(path: string): void;
readdir(path: string): any;
unlink(path: string): void;
readlink(path: string): string;
stat(path: string, dontFollow?: boolean): any;
lstat(path: string): any;
chmod(path: string, mode: number, dontFollow?: boolean): void;
lchmod(path: string, mode: number): void;
fchmod(fd: number, mode: number): void;
chown(path: string, uid: number, gid: number, dontFollow?: boolean): void;
lchown(path: string, uid: number, gid: number): void;
fchown(fd: number, uid: number, gid: number): void;
truncate(path: string, len: number): void;
ftruncate(fd: number, len: number): void;
utime(path: string, atime: number, mtime: number): void;
open(
path: string,
flags: string,
mode?: number,
fd_start?: number,
fd_end?: number
): FSStream;
close(stream: FSStream): void;
llseek(stream: FSStream, offset: number, whence: number): any;
read(
stream: FSStream,
buffer: ArrayBufferView,
offset: number,
length: number,
position?: number
): number;
write(
stream: FSStream,
buffer: ArrayBufferView,
offset: number,
length: number,
position?: number,
canOwn?: boolean
): number;
allocate(stream: FSStream, offset: number, length: number): void;
mmap(
stream: FSStream,
buffer: ArrayBufferView,
offset: number,
length: number,
position: number,
prot: number,
flags: number
): any;
ioctl(stream: FSStream, cmd: any, arg: any): any;
readFile(
path: string,
opts: { encoding: "binary"; flags?: string | undefined }
): Uint8Array;
readFile(
path: string,
opts: { encoding: "utf8"; flags?: string | undefined }
): string;
readFile(path: string, opts?: { flags?: string | undefined }): Uint8Array;
writeFile(
path: string,
data: string | ArrayBufferView,
opts?: { flags?: string | undefined }
): void;
//
// module-level FS code
//
cwd(): string;
chdir(path: string): void;
init(
input: null | (() => number | null),
output: null | ((c: number) => any),
error: null | ((c: number) => any)
): void;
createLazyFile(
parent: string | FSNode,
name: string,
url: string,
canRead: boolean,
canWrite: boolean
): FSNode;
createPreloadedFile(
parent: string | FSNode,
name: string,
url: string,
canRead: boolean,
canWrite: boolean,
onload?: () => void,
onerror?: () => void,
dontCreateFile?: boolean,
canOwn?: boolean
): void;
createDataFile(
parent: string | FSNode,
name: string,
data: ArrayBufferView,
canRead: boolean,
canWrite: boolean,
canOwn: boolean
): FSNode;
}
interface EmPostgres extends EmscriptenModule {
FS: FS;
eventTarget: EventTarget;
Event: typeof CustomEvent;
onRuntimeInitialized: (Module: EmPostgres) => Promise<void>;
}
interface Filesystem {
/**
* Returns true if the filesystem was initialized and this is the fun run.
*/
init(debug?: DebugLevel): Promise<boolean>;
/**
* Returns the options to pass to the emscripten module.
*/
emscriptenOpts(opts: Partial<EmPostgres>): Promise<Partial<EmPostgres>>;
/**
* Sync the filesystem to the emscripten filesystem.
*/
syncToFs(mod: FS): Promise<void>;
/**
* Sync the emscripten filesystem to the filesystem.
*/
initialSyncFs(mod: FS): Promise<void>;
}
declare class PGlite implements PGliteInterface {
#private;
fs?: Filesystem;
protected mod?: PostgresMod;
readonly dataDir?: string;
readonly fsType: FilesystemType;
protected fs?: Filesystem;
protected emp?: any;
readonly waitReady: Promise<void>;

@@ -314,2 +21,7 @@ readonly debug: DebugLevel;

/**
* Create a new PGlite instance
* @param options PGlite options including the data directory
*/
constructor(options?: PGliteOptions);
/**
* The ready state of the database

@@ -354,2 +66,40 @@ */

execProtocol(message: Uint8Array, { syncToFs }?: ExecProtocolOptions): Promise<Array<[BackendMessage$1, Uint8Array]>>;
/**
* Listen for a notification
* @param channel The channel to listen on
* @param callback The callback to call when a notification is received
*/
listen(channel: string, callback: (payload: string) => void): Promise<() => Promise<void>>;
/**
* Stop listening for a notification
* @param channel The channel to stop listening on
* @param callback The callback to remove
*/
unlisten(channel: string, callback?: (payload: string) => void): Promise<void>;
/**
* Listen to notifications
* @param callback The callback to call when a notification is received
*/
onNotification(callback: (channel: string, payload: string) => void): () => void;
/**
* Stop listening to notifications
* @param callback The callback to remove
*/
offNotification(callback: (channel: string, payload: string) => void): void;
/**
* Create a new PGlite instance with extensions on the Typescript interface
* (The main constructor does enable extensions, however due to the limitations
* of Typescript, the extensions are not available on the instance interface)
* @param dataDir The directory to store the database files
* Prefix with idb:// to use indexeddb filesystem in the browser
* Use memory:// to use in-memory filesystem
* @param options Optional options
* @returns A new PGlite instance with extensions
*/
static withExtensions<O extends PGliteOptions>(options?: O): PGlite & PGliteInterfaceExtensions<O["extensions"]>;
/**
* Dump the PGDATA dir from the filesystem to a gziped tarball.
* @returns The tarball as a File object where available, and fallback to a Blob
*/
dumpDataDir(): Promise<Blob | File>;
}

@@ -592,3 +342,3 @@

*/
declare function parseResults(messages: Array<BackendMessage$1>, options?: QueryOptions): Array<Results>;
declare function parseResults(messages: Array<BackendMessage$1>, options?: QueryOptions, blob?: Blob): Array<Results>;

@@ -728,2 +478,2 @@ declare const parse$1_parseResults: typeof parseResults;

export { DebugLevel, ExecProtocolOptions, FilesystemType, Mutex, PGlite, PGliteInterface, PGliteOptions, ParserOptions, QueryOptions, Results, Transaction, parse$1 as parse, index as protocol, types$1 as types };
export { DebugLevel, ExecProtocolOptions, Mutex, PGlite, PGliteInterface, PGliteInterfaceExtensions, PGliteOptions, ParserOptions, QueryOptions, Results, Transaction, parse$1 as parse, index as protocol, types$1 as types };

@@ -1,2 +0,2 @@

import{a,b,c,d,e,f}from"./chunk-OVRU7FYL.js";import"./chunk-EKNQE2HU.js";export{a as Mutex,d as PGlite,e as messages,c as parse,f as protocol,b as types};
import{a,b,c,d,e,f}from"./chunk-VGIHPWIO.js";import"./chunk-MAGDP6ZW.js";import"./chunk-TYZHXJCT.js";export{a as Mutex,d as PGlite,e as messages,c as parse,f as protocol,b as types};
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

import { P as PGliteInterface, F as FilesystemType, D as DebugLevel, a as PGliteOptions, Q as QueryOptions, R as Results, B as BackendMessage } from '../interface-Be6LYDxW.js';
import { P as PGliteInterface, e as FilesystemType, D as DebugLevel, b as PGliteOptions, Q as QueryOptions, R as Results, B as BackendMessage } from '../interface-y94vF3S2.js';

@@ -17,4 +17,10 @@ declare class PGliteWorker implements PGliteInterface {

execProtocol(message: Uint8Array): Promise<Array<[BackendMessage, Uint8Array]>>;
listen(channel: string, callback: (payload: string) => void): Promise<() => Promise<void>>;
unlisten(channel: string, callback?: (payload: string) => void): Promise<void>;
onNotification(callback: (channel: string, payload: string) => void): () => void;
offNotification(callback: (channel: string, payload: string) => void): void;
receiveNotification(channel: string, payload: string): void;
dumpDataDir(): Promise<File | Blob>;
}
export { PGliteWorker };

@@ -1,2 +0,2 @@

import{b as d,c as h}from"../chunk-7H7EOSCZ.js";import{d as t,e as i,f as o,g as p,i as m,r as u}from"../chunk-EKNQE2HU.js";m();var k=new URL("./process.js",import.meta.url),a,n,s,y,c,f,g=class{constructor(e,r){i(this,c);this.debug=0;i(this,a,!1);i(this,n,!1);i(this,s,void 0);i(this,y,void 0);let{dataDir:l,fsType:P}=u(e);this.dataDir=l,this.fsType=P,o(this,y,r??{}),this.debug=r?.debug??0,o(this,s,d(new Worker(k,{type:"module"}))),this.waitReady=p(this,c,f).call(this,e)}get ready(){return t(this,a)}get closed(){return t(this,n)}async close(){await t(this,s).close(),o(this,n,!0)}async query(e,r,l){return t(this,s).query(e,r,l)}async exec(e,r){return t(this,s).exec(e,r)}async transaction(e){let r=h(e);return t(this,s).transaction(r)}async execProtocol(e){return t(this,s).execProtocol(e)}};a=new WeakMap,n=new WeakMap,s=new WeakMap,y=new WeakMap,c=new WeakSet,f=async function(e){await t(this,s).init(e,t(this,y)),o(this,a,!0)};export{g as PGliteWorker};
import{b as w,d as g}from"../chunk-UNO2UYXI.js";import{g as P}from"../chunk-MAGDP6ZW.js";import{d as e,e as o,f as d,g as m,i as f,k as h}from"../chunk-TYZHXJCT.js";h();f();var l,c,s,p,r,n,u,T,v=class{constructor(t,i){o(this,u);this.debug=0;o(this,l,!1);o(this,c,!1);o(this,s,void 0);o(this,p,void 0);o(this,r,new Map);o(this,n,new Set);let{dataDir:a,fsType:y}=P(t);this.dataDir=a,this.fsType=y,d(this,p,i??{}),this.debug=i?.debug??0,d(this,s,w(new Worker(new URL("./process.js",import.meta.url),{type:"module"}))),this.waitReady=m(this,u,T).call(this,t)}get ready(){return e(this,l)}get closed(){return e(this,c)}async close(){await e(this,s).close(),d(this,c,!0)}async query(t,i,a){return e(this,s).query(t,i,a)}async exec(t,i){return e(this,s).exec(t,i)}async transaction(t){let i=g(t);return e(this,s).transaction(i)}async execProtocol(t){return e(this,s).execProtocol(t)}async listen(t,i){return e(this,r).has(t)||e(this,r).set(t,new Set),e(this,r).get(t)?.add(i),await this.exec(`LISTEN ${t}`),async()=>{await this.unlisten(t,i)}}async unlisten(t,i){i?e(this,r).get(t)?.delete(i):e(this,r).delete(t),e(this,r).get(t)?.size===0&&await this.exec(`UNLISTEN ${t}`)}onNotification(t){return e(this,n).add(t),()=>{e(this,n).delete(t)}}offNotification(t){e(this,n).delete(t)}receiveNotification(t,i){let a=e(this,r).get(t);if(a)for(let y of a)queueMicrotask(()=>y(i));for(let y of e(this,n))queueMicrotask(()=>y(t,i))}async dumpDataDir(){return e(this,s).dumpDataDir()}};l=new WeakMap,c=new WeakMap,s=new WeakMap,p=new WeakMap,r=new WeakMap,n=new WeakMap,u=new WeakSet,T=async function(t){await e(this,s).init(t,e(this,p),g(this.receiveNotification.bind(this))),d(this,l,!0)};export{v as PGliteWorker};
//# sourceMappingURL=index.js.map

@@ -1,5 +0,5 @@

import { a as PGliteOptions, Q as QueryOptions, R as Results, B as BackendMessage } from '../interface-Be6LYDxW.js';
import { b as PGliteOptions, Q as QueryOptions, R as Results, B as BackendMessage } from '../interface-y94vF3S2.js';
declare const worker: {
init(dataDir?: string, options?: PGliteOptions): Promise<boolean>;
init(dataDir?: string, options?: PGliteOptions, onNotification?: ((channel: string, payload: string) => void) | undefined): Promise<boolean>;
close(): Promise<void>;

@@ -10,2 +10,3 @@ query(query: string, params?: any[], options?: QueryOptions): Promise<Results<unknown>>;

execProtocol(message: Uint8Array): Promise<[BackendMessage, Uint8Array][]>;
dumpDataDir(): Promise<File | Blob>;
};

@@ -12,0 +13,0 @@ type Worker = typeof worker;

@@ -1,2 +0,2 @@

import{d as o}from"../chunk-OVRU7FYL.js";import{a as i,c as a}from"../chunk-7H7EOSCZ.js";import{i as n}from"../chunk-EKNQE2HU.js";n();var e,y={async init(t,r){return e=new o(t,r),await e.waitReady,!0},async close(){await e.close()},async query(t,r,s){return await e.query(t,r,s)},async exec(t,r){return await e.exec(t,r)},async transaction(t){return await e.transaction(r=>t(a(r)))},async execProtocol(t){return await e.execProtocol(t)}};i(y);
import{d as o}from"../chunk-VGIHPWIO.js";import{a as s,c as y,d as c}from"../chunk-UNO2UYXI.js";import"../chunk-MAGDP6ZW.js";import{i as n,k as i}from"../chunk-TYZHXJCT.js";i();n();var t,p={async init(r,e,a){return t=new o(r,e),await t.waitReady,a&&t.onNotification(a),!0},async close(){await t.close()},async query(r,e,a){return await t.query(r,e,a)},async exec(r,e){return await t.exec(r,e)},async transaction(r){return await t.transaction(e=>r(c(e)))},async execProtocol(r){return await t.execProtocol(r)},async dumpDataDir(){let r=await t.dumpDataDir();return y(r,[await r.arrayBuffer()])}};s(p);
//# sourceMappingURL=process.js.map
{
"name": "@electric-sql/pglite",
"version": "0.1.5",
"version": "0.2.0-alpha.0",
"private": false,

@@ -22,3 +22,4 @@ "publishConfig": {

".": "./dist/index.js",
"./worker": "./dist/worker/index.js"
"./worker": "./dist/worker/index.js",
"./vector": "./dist/vector/index.js"
},

@@ -29,2 +30,5 @@ "typesVersions": {

"./dist/worker/index.d.ts"
],
"vector": [
"./dist/vector/index.d.ts"
]

@@ -44,6 +48,9 @@ }

"devDependencies": {
"@types/emscripten": "^1.39.13",
"@types/node": "^20.11.18",
"@types/node-fetch": "^2.6.11",
"async-mutex": "^0.4.1",
"ava": "^6.1.2",
"buffer": "^6.0.3",
"bun": "^1.1.18",
"comlink": "^4.4.1",

@@ -55,2 +62,3 @@ "concurrently": "^8.2.2",

"prettier": "3.2.5",
"tinytar": "^0.1.0",
"tsup": "^8.0.2",

@@ -61,12 +69,9 @@ "tsx": "^4.7.1",

"scripts": {
"test": "rm -rf ./pgdata-test && concurrently --hide 0 --prefix none -k \"npx http-server --port 3334 ./\" \"sleep 2 && ava tests/*.test.js tests/**/*.test.js\"",
"build:configure": "cd ../../postgres/ && make -f ../packages/pglite/Makefile build-configure",
"build:wasm": "cd ../../postgres/ && make -f ../packages/pglite/Makefile build",
"build:sharedir": "cd ../../postgres/ && make -f ../packages/pglite/Makefile sharedir",
"build:clean": "cd ../../postgres/ && make clean",
"test": "rm -rf ./pgdata-test && concurrently -s first --hide 1 --prefix none -k \"sleep 2 && ava tests/*.test.js tests/**/*.test.js\" \"npx http-server --port 3334 ./\"",
"test:quick": "rm -rf ./pgdata-bun-test && ava tests/*.test.js tests/target/node-*.test.js",
"test:bun": "rm -rf ./pgdata-test && npx bun test tests/basic.test.js && npx bun test tests/pgvector.test.js && npx bun test tests/targets/node-fs.test.js",
"build:js": "tsup && tsx scripts/bundle-wasm.ts",
"build:all": "npm run build:wasm && npm run build:sharedir && npm run build:js",
"build": "npm run build:configure && npm run build:all",
"build": "npm run build:js",
"format": "prettier --write ./src"
}
}

@@ -199,2 +199,5 @@ <p align="center">

- `blob: Blob | File`
Attach a `Blob` or `File` object to the query that can used with a `COPY FROM` command by using the virtual `/dev/blob` device, see [importing and exporting](#importing-and-exporting-with-copy-tofrom).
#### `.exec(query: string, options?: QueryOptions): Promise<Array<Results>>`

@@ -266,2 +269,31 @@

#### `.listen(channel: string, callback: (payload: string) => void): Promise<void>`
Subscribe to a [pg_notify](https://www.postgresql.org/docs/current/sql-notify.html) channel. The callback will receive the payload from the notification.
Returns an unsubscribe function to unsubscribe from the channel.
##### Example:
```ts
const unsub = await pg.listen('test', (payload) => {
console.log('Received:', payload);
});
await pg.query("NOTIFY test, 'Hello, world!'");
```
#### `.unlisten(channel: string, callback?: (payload: string) => void): Promise<void>`
Unsubscribe from the channel. If a callback is provided it removes only that callback from the subscription, when no callback is provided is unsubscribes all callbacks for the channel.
#### `onNotification(callback: (channel: string, payload: string) => void): () => void`
Add an event handler for all notifications received from Postgres.
**Note:** This does not subscribe to the notification, you will have to manually subscribe with `LISTEN channel_name`.
#### `offNotification(callback: (channel: string, payload: string) => void): void`
Remove an event handler for all notifications received from Postgres.
### Properties:

@@ -279,3 +311,4 @@

- `affectedRows?: number` - Count of the rows affected by the query. Note this is *not* the count of rows returned, it is the number or rows in the database changed by the query.
- `fields: { name: string; dataTypeID: number }[]` - Field name and Postgres data type ID for each field returned.
- `fields: { name: string; dataTypeID: number }[]` - Field name and Postgres data type ID for each field returned.
- `blob: Blob` - A `Blob` containing the data written to the virtual `/dev/blob/` device by a `COPY TO` command. See [importing and exporting](#importing-and-exporting-with-copy-tofrom).

@@ -307,2 +340,21 @@

### Importing and exporting with `COPY TO/FROM`
PGlite has support importing and exporting via `COPY TO/FROM` by using a virtual `/dev/blob` device.
To import a file pass the `File` or `Blob` in the query options as `blob`, and copy from the `/dev/blob` device.
```ts
await pg.query("COPY my_table FROM '/dev/blob';", [], {
blob: MyBlob
})
```
To export a table or query to a file you just have to write to the `/dev/blob` device, the file will be retied as `blob` on the query results:
```ts
const ret = await pg.query("COPY my_table TO '/dev/blob';")
// ret.blob is a `Blob` object with the data from the copy.
```
## Extensions

@@ -309,0 +361,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

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