Socket
Socket
Sign inDemoInstall

@wixc3/patterns

Package Overview
Dependencies
Maintainers
64
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wixc3/patterns - npm Package Compare versions

Comparing version 14.0.0 to 14.1.0

dist/cjs/disposables/safe-disposable.d.ts

2

dist/cjs/disposables/create-disposables.d.ts

@@ -90,3 +90,3 @@ import { GroupConstraints } from './constraints';

*/
dispose: () => Promise<void>;
dispose(): Promise<void>;
/**

@@ -93,0 +93,0 @@ *

@@ -57,11 +57,2 @@ "use strict";

this.constrains = [];
/**
* Disposes all disposables in all groups one at the time,
* order based on constraints
*/
this.dispose = async () => {
for (const { disposables } of this.groups) {
await disposables.dispose();
}
};
this.groups.push(...initialGroups.map(createGroup));

@@ -130,2 +121,11 @@ }

/**
* Disposes all disposables in all groups one at the time,
* order based on constraints
*/
async dispose() {
for (const { disposables } of this.groups) {
await disposables.dispose();
}
}
/**
*

@@ -132,0 +132,0 @@ * @returns a serialized list of groups and their disposables and constraints

@@ -8,2 +8,3 @@ import { Disposables } from '.';

/**
* @deprecated
* A base class for disposable objects

@@ -10,0 +11,0 @@ * @example

@@ -14,2 +14,3 @@ "use strict";

/**
* @deprecated
* A base class for disposable objects

@@ -16,0 +17,0 @@ * @example

export * from './create-disposables';
export * from './disposable';
export * from './safe-disposable';
export type { DisposableItem } from './disposables-group';
export { DisposalGroup, GroupConstraints } from './constraints';
//# sourceMappingURL=index.d.ts.map

@@ -19,2 +19,3 @@ "use strict";

__exportStar(require("./disposable"), exports);
__exportStar(require("./safe-disposable"), exports);
//# sourceMappingURL=index.js.map
import { Signal } from './signal';
/**
* A simple event emitter
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -5,0 +26,0 @@ export declare class EventEmitter<Events extends object, EventId extends keyof Events = keyof Events> {

@@ -6,3 +6,24 @@ "use strict";

/**
* A simple event emitter
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -9,0 +30,0 @@ class EventEmitter {

@@ -34,2 +34,3 @@ export type Listener<T> = (data: T) => void;

export declare class Signal<T> extends Set<Listener<T>> {
private onceHandlers;
/**

@@ -39,3 +40,4 @@ * Subscribe a notification callback

*/
subscribe: (handler: Listener<T>) => void;
subscribe: (handler: Listener<T>) => () => void;
once: (handler: Listener<T>) => () => void;
/**

@@ -49,27 +51,4 @@ * Unsubscribe an existing callback

notify: (data: T) => void;
clear(): void;
}
/**
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/
//# sourceMappingURL=signal.d.ts.map

@@ -38,2 +38,3 @@ "use strict";

super(...arguments);
this.onceHandlers = new Set();
/**

@@ -45,3 +46,8 @@ * Subscribe a notification callback

this.add(handler);
return () => this.unsubscribe(handler);
};
this.once = (handler) => {
this.onceHandlers.add(handler);
return () => this.unsubscribe(handler);
};
/**

@@ -51,2 +57,3 @@ * Unsubscribe an existing callback

this.unsubscribe = (handler) => {
this.onceHandlers.delete(handler);
this.delete(handler);

@@ -61,30 +68,14 @@ };

}
for (const handler of this.onceHandlers) {
handler(data);
this.onceHandlers.delete(handler);
}
};
}
clear() {
super.clear();
this.onceHandlers.clear();
}
}
exports.Signal = Signal;
/**
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/
//# sourceMappingURL=signal.js.map

@@ -90,3 +90,3 @@ import { GroupConstraints } from './constraints';

*/
dispose: () => Promise<void>;
dispose(): Promise<void>;
/**

@@ -93,0 +93,0 @@ *

@@ -53,11 +53,2 @@ import { getGroupConstrainedIndex, normalizeConstraints } from './constraints';

this.constrains = [];
/**
* Disposes all disposables in all groups one at the time,
* order based on constraints
*/
this.dispose = async () => {
for (const { disposables } of this.groups) {
await disposables.dispose();
}
};
this.groups.push(...initialGroups.map(createGroup));

@@ -126,2 +117,11 @@ }

/**
* Disposes all disposables in all groups one at the time,
* order based on constraints
*/
async dispose() {
for (const { disposables } of this.groups) {
await disposables.dispose();
}
}
/**
*

@@ -128,0 +128,0 @@ * @returns a serialized list of groups and their disposables and constraints

@@ -8,2 +8,3 @@ import { Disposables } from '.';

/**
* @deprecated
* A base class for disposable objects

@@ -10,0 +11,0 @@ * @example

@@ -11,2 +11,3 @@ import { defaults, noop } from '@wixc3/common';

/**
* @deprecated
* A base class for disposable objects

@@ -13,0 +14,0 @@ * @example

export * from './create-disposables';
export * from './disposable';
export * from './safe-disposable';
export type { DisposableItem } from './disposables-group';
export { DisposalGroup, GroupConstraints } from './constraints';
//# sourceMappingURL=index.d.ts.map
export * from './create-disposables';
export * from './disposable';
export * from './safe-disposable';
//# sourceMappingURL=index.js.map
import { Signal } from './signal';
/**
* A simple event emitter
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -5,0 +26,0 @@ export declare class EventEmitter<Events extends object, EventId extends keyof Events = keyof Events> {

import { Signal } from './signal';
/**
* A simple event emitter
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -5,0 +26,0 @@ export class EventEmitter {

@@ -34,2 +34,3 @@ export type Listener<T> = (data: T) => void;

export declare class Signal<T> extends Set<Listener<T>> {
private onceHandlers;
/**

@@ -39,3 +40,4 @@ * Subscribe a notification callback

*/
subscribe: (handler: Listener<T>) => void;
subscribe: (handler: Listener<T>) => () => void;
once: (handler: Listener<T>) => () => void;
/**

@@ -49,27 +51,4 @@ * Unsubscribe an existing callback

notify: (data: T) => void;
clear(): void;
}
/**
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/
//# sourceMappingURL=signal.d.ts.map

@@ -35,2 +35,3 @@ /**

super(...arguments);
this.onceHandlers = new Set();
/**

@@ -42,3 +43,8 @@ * Subscribe a notification callback

this.add(handler);
return () => this.unsubscribe(handler);
};
this.once = (handler) => {
this.onceHandlers.add(handler);
return () => this.unsubscribe(handler);
};
/**

@@ -48,2 +54,3 @@ * Unsubscribe an existing callback

this.unsubscribe = (handler) => {
this.onceHandlers.delete(handler);
this.delete(handler);

@@ -58,29 +65,13 @@ };

}
for (const handler of this.onceHandlers) {
handler(data);
this.onceHandlers.delete(handler);
}
};
}
clear() {
super.clear();
this.onceHandlers.clear();
}
}
/**
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/
//# sourceMappingURL=signal.js.map
{
"name": "@wixc3/patterns",
"version": "14.0.0",
"version": "14.1.0",
"description": "A utility for saving objects to be disposed",

@@ -21,5 +21,5 @@ "main": "dist/cjs/index.js",

"dependencies": {
"@wixc3/common": "^14.0.0",
"@wixc3/common": "^14.1.0",
"promise-assist": "^2.0.1"
}
}

@@ -37,3 +37,7 @@ import { deferred } from 'promise-assist';

*/
constructor(private cb: T, private waitTime: number, private maxWaitTime: number) {}
constructor(
private cb: T,
private waitTime: number,
private maxWaitTime: number,
) {}

@@ -40,0 +44,0 @@ private execute() {

@@ -37,3 +37,3 @@ import type { DisposablesGroup } from './disposables-group';

throw new Error(
`Invalid constraints: ${existingGroups[lastAfter]?.name} runs after ${existingGroups[firstBefore]?.name}, which contradicts prior constraints`
`Invalid constraints: ${existingGroups[lastAfter]?.name} runs after ${existingGroups[firstBefore]?.name}, which contradicts prior constraints`,
);

@@ -48,3 +48,3 @@ }

name: string,
groups: DisposalGroup[]
groups: DisposalGroup[],
) => {

@@ -51,0 +51,0 @@ const _constraints: GroupConstraints[] = Array.isArray(constraints) ? constraints : [constraints];

@@ -75,3 +75,6 @@ import { DisposalGroup, getGroupConstrainedIndex, GroupConstraints, normalizeConstraints } from './constraints';

private readonly constrains: GroupConstraints[] = [];
constructor(private name: string, initialGroups: string[] = []) {
constructor(
private name: string,
initialGroups: string[] = [],
) {
this.groups.push(...initialGroups.map(createGroup));

@@ -115,3 +118,3 @@ }

throw new Error(
`Invalid disposable: must be a function or object with a dispose method got ${disposable}`
`Invalid disposable: must be a function or object with a dispose method got ${disposable}`,
);

@@ -150,7 +153,7 @@ }

*/
dispose = async () => {
async dispose() {
for (const { disposables } of this.groups) {
await disposables.dispose();
}
};
}

@@ -157,0 +160,0 @@ /**

@@ -12,2 +12,3 @@ import { defaults, noop } from '@wixc3/common';

/**
* @deprecated
* A base class for disposable objects

@@ -102,3 +103,3 @@ * @example

async: never;
} & Partial<typeof DISPOSAL_GUARD_DEFAULTS>
} & Partial<typeof DISPOSAL_GUARD_DEFAULTS>,
): () => void;

@@ -105,0 +106,0 @@ disposalGuard(): () => void;

@@ -17,3 +17,3 @@ import { timeout } from 'promise-assist';

details.timeout,
`Disposal timed out: "${details.name}" after ${details.timeout}ms`
`Disposal timed out: "${details.name}" after ${details.timeout}ms`,
);

@@ -20,0 +20,0 @@ } catch (e) {

export * from './create-disposables';
export * from './disposable';
export * from './safe-disposable';
export type { DisposableItem } from './disposables-group';
export { DisposalGroup, GroupConstraints } from './constraints';
import { Signal } from './signal';
/**
* A simple event emitter
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -6,0 +27,0 @@ export class EventEmitter<Events extends object, EventId extends keyof Events = keyof Events> {

@@ -35,2 +35,3 @@ export type Listener<T> = (data: T) => void;

export class Signal<T> extends Set<Listener<T>> {
private onceHandlers = new Set<Listener<T>>();
/**

@@ -42,3 +43,9 @@ * Subscribe a notification callback

this.add(handler);
return () => this.unsubscribe(handler);
};
once = (handler: Listener<T>) => {
this.onceHandlers.add(handler);
return () => this.unsubscribe(handler);
};
/**

@@ -48,2 +55,3 @@ * Unsubscribe an existing callback

unsubscribe = (handler: Listener<T>) => {
this.onceHandlers.delete(handler);
this.delete(handler);

@@ -58,28 +66,12 @@ };

}
for (const handler of this.onceHandlers) {
handler(data);
this.onceHandlers.delete(handler);
}
};
override clear(): void {
super.clear();
this.onceHandlers.clear();
}
}
/**
* Basic type safe event emitter
* @example
* ```ts
* const ms = new EventEmitter<{ onChange: { id: 'onChange' }; onDelete: { id: 'onDelete' } }>();
* ms.subscribe('onChange', (event) => {
* event.id; // 'onChange'
* });
* ms.subscribe('onDelete', (event) => {
* event.id; // 'onDelete'
* });
*
* ms.notify('onChange', { id: 'onChange' }); // event is type safe
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onChange', { id: 'onDelete' }); // ERROR!!!
* ```
* @example <caption>payload type mismatch</caption>
* ```ts
* ms.notify('onSomethingElse', { id: 'onDelete' }); // ERROR!!!
* ```
*/

@@ -37,3 +37,3 @@ import { expect } from 'chai';

expect(() => disposable.disposalGuard({ async: false, usedWhileDisposing: true })).to.throw(
'Instance was disposed'
'Instance was disposed',
);

@@ -40,0 +40,0 @@ });

@@ -53,3 +53,3 @@ import { expect, use } from 'chai';

await expect(disposables.dispose()).to.be.rejectedWith(
/Disposal failed: "\[test\]: disposing with error"\nError: failed!/
/Disposal failed: "\[test\]: disposing with error"\nError: failed!/,
);

@@ -83,3 +83,3 @@ });

expect(() => groups.registerGroup('group1', { before: 'group2' })).to.throw(
`Invalid constraint: "before: group2" - group not found`
`Invalid constraint: "before: group2" - group not found`,
);

@@ -90,3 +90,3 @@ });

expect(() => groups.registerGroup('group1', [])).to.throw(
`Invalid disposal group: must have at least one constraint`
`Invalid disposal group: must have at least one constraint`,
);

@@ -100,3 +100,3 @@ });

expect(() => groups.registerGroup('invalid', { before: 'before', after: 'after' })).to.throw(
'Invalid constraints: after runs after before, which contradicts prior constraints'
'Invalid constraints: after runs after before, which contradicts prior constraints',
);

@@ -107,3 +107,3 @@ });

expect(() => groups.registerGroup('default', { before: 'default' })).to.throw(
`Invalid group: "default" already exists`
`Invalid group: "default" already exists`,
);

@@ -110,0 +110,0 @@ });

@@ -8,27 +8,84 @@ import chai, { expect } from 'chai';

chai.use(sinonChai);
interface ChangeEvent {
a: string;
b: number;
}
describe('Signal', () => {
it('should subscribe to accept events and unsubscribe to stop accepting event', () => {
interface ChangeEvent {
a: string;
b: number;
}
const signal = new Signal<ChangeEvent>();
const onChange = stub();
let signal: Signal<ChangeEvent>;
let listener = stub();
beforeEach(() => {
signal = new Signal<ChangeEvent>();
listener = stub();
});
it(`doesn't call listeners before "notify(...)"`, () => {
signal.subscribe(listener);
expect(listener.callCount, 'not calls before event dispatch').to.eql(0);
});
it('calls listeners after "notify(...)"', () => {
signal.subscribe(listener);
signal.notify({ a: 'value', b: 5 });
signal.subscribe(onChange);
expect(listener.callCount, 'calls listeners').to.eql(1);
expect(listener.lastCall.args[0], 'event value').to.eql({ a: 'value', b: 5 });
});
it('ignores double subscriptions', () => {
signal.subscribe(listener);
signal.subscribe(listener);
signal.subscribe(listener);
expect(onChange.callCount, 'not calls before event dispatch').to.eql(0);
signal.notify({ a: 'value', b: 5 });
expect(onChange.callCount, 'not calls before event dispatch').to.eql(1);
expect(onChange.lastCall.args[0], 'event value').to.eql({ a: 'value', b: 5 });
expect(listener.callCount, 'ignore double subscriptions').to.eql(1);
});
describe('once', () => {
it('calls "once" listeners only one time', () => {
signal.once(listener);
signal.notify({ a: 'value', b: 5 });
signal.notify({ a: 'value', b: 6 });
signal.unsubscribe(onChange);
expect(listener.callCount, 'is called only once').to.eql(1);
expect(listener.lastCall.args[0], 'with the first event').to.eql({ a: 'value', b: 5 });
});
it('ignores double "once" subscriptions', () => {
signal.once(listener);
signal.once(listener);
signal.once(listener);
signal.notify({ a: 'other-value', b: 10 });
signal.notify({ a: 'value', b: 5 });
expect(onChange.callCount, 'no new calls after unsubscribe').to.eql(1);
expect(listener.callCount, 'ignore double subscriptions').to.eql(1);
});
it(`doesn't call listeners after "unsubscribe"`, () => {
signal.once(listener);
signal.unsubscribe(listener);
signal.notify({ a: 'value', b: 5 });
expect(listener.callCount, 'no new calls after unsubscribe').to.eql(0);
});
});
it(`doesn't call listeners after "unsubscribe"`, () => {
signal.subscribe(listener);
signal.unsubscribe(listener);
signal.notify({ a: 'value', b: 5 });
expect(listener.callCount, 'no new calls after unsubscribe').to.eql(0);
});
it(`doesn't call listeners after unsubscribing using subscribe return value`, () => {
const unsubscribe = signal.subscribe(listener);
unsubscribe();
signal.notify({ a: 'value', b: 5 });
expect(listener.callCount, 'no new calls after unsubscribe').to.eql(0);
});
describe('clear', () => {
it('removes all listeners', () => {
signal.subscribe(listener);
signal.clear();
signal.notify({ a: 'value', b: 5 });
expect(listener.callCount, 'no new calls after clear').to.eql(0);
});
it('removes all "once" listeners', () => {
signal.once(listener);
signal.clear();
signal.notify({ a: 'value', b: 5 });
expect(listener.callCount, 'no new calls after clear').to.eql(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

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

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

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

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