New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@elastic/search-ui

Package Overview
Dependencies
Maintainers
71
Versions
100
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@elastic/search-ui - npm Package Compare versions

Comparing version 1.18.0 to 1.18.1

16

lib/cjs/__tests__/SearchDriver.test.js

@@ -645,2 +645,18 @@ "use strict";

}));
describe("SearchDriver Routing Options", () => {
it("should allow overrides to urlManager", () => {
const initialState = {};
const routingOptions = {
readUrl: jest.fn(() => {
return "?q=override";
}),
writeUrl: jest.fn()
};
(0, helpers_1.setupDriver)({
initialState,
routingOptions: routingOptions
});
expect(MockedURLManager).toBeCalledWith(routingOptions);
});
});
describe("SearchDriver hooks", () => {

@@ -647,0 +663,0 @@ it("onSearch Hook", () => {

51

lib/cjs/__tests__/URLManager.test.js

@@ -7,4 +7,4 @@ "use strict";

const URLManager_1 = __importDefault(require("../URLManager"));
function createManager() {
const manager = new URLManager_1.default();
function createManager(options) {
const manager = new URLManager_1.default(options);
return manager;

@@ -100,3 +100,3 @@ }

manager.pushStateToURL(basicParameterState);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?q=node&size=n_20_n&filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D=value&filters%5B0%5D%5Btype%5D=all&filters%5B1%5D%5Bfield%5D=node&filters%5B1%5D%5Bvalues%5D%5B0%5D=value&filters%5B1%5D%5Btype%5D=all&sort-field=name&sort-direction=asc");

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

manager.pushStateToURL(parameterStateWithRangeFilters);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bfrom%5D=n_12_n&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bname%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bto%5D=n_4000_n&filters%5B0%5D%5Btype%5D=all");

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

manager.pushStateToURL(parameterStateWithSortList);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?size=n_20_n&sort%5B0%5D%5Bdirection%5D=asc&sort%5B0%5D%5Bfield%5D=name&sort%5B1%5D%5Bdirection%5D=desc&sort%5B1%5D%5Bfield%5D=title");

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

manager.pushStateToURL(basicParameterState, { replaceUrl: true });
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?q=node&size=n_20_n&filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D=value&filters%5B0%5D%5Btype%5D=all&filters%5B1%5D%5Bfield%5D=node&filters%5B1%5D%5Bvalues%5D%5B0%5D=value&filters%5B1%5D%5Btype%5D=all&sort-field=name&sort-direction=asc");

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

manager.pushStateToURL(state);
return pushSpy.mock.calls[0][0].search;
return pushSpy.mock.calls[0][0];
}

@@ -222,1 +222,38 @@ function simulateBrowserHistoryEvent(newUrl) {

});
describe("routing options overrides", () => {
const routingOptions = {
readUrl: jest.fn(() => {
return "/search/tvs?query=samsung";
}),
writeUrl: jest.fn(),
stateToUrl: jest.fn((state) => {
const categoryFilter = state.filters.find((filter) => filter.field === "category");
const category = categoryFilter ? categoryFilter.values[0] : "all";
return `/search/${category}?query=${state.searchTerm}`;
}),
urlToState: jest.fn((url) => {
const match = url.match(/\/search\/(\w+)\?query=(\w+)/);
if (!match)
return {};
return {
searchTerm: match[2],
filters: [{ field: "category", values: [match[1]], type: "all" }]
};
})
};
it("should write correct url", () => {
const manager = createManager(routingOptions);
manager.pushStateToURL({
searchTerm: "samsung",
filters: [{ field: "category", values: ["gaming"], type: "all" }]
});
expect(routingOptions.writeUrl).toHaveBeenCalledWith("/search/gaming?query=samsung", { replaceUrl: false });
});
it("should read correct url", () => {
const manager = createManager(routingOptions);
expect(manager.getStateFromURL()).toEqual({
searchTerm: "samsung",
filters: [{ field: "category", values: ["tvs"], type: "all" }]
});
});
});

5

lib/cjs/SearchDriver.d.ts

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

import URLManager from "./URLManager";
import URLManager, { RoutingHandlerOptions } from "./URLManager";
import RequestSequencer from "./RequestSequencer";

@@ -25,2 +25,3 @@ import DebounceManager from "./DebounceManager";

trackUrlState?: boolean;
routingOptions?: RoutingHandlerOptions;
urlPushDebounceLength?: number;

@@ -54,3 +55,3 @@ hasA11yNotifications?: boolean;

apiConnector?: APIConnector;
constructor({ apiConnector, autocompleteQuery, plugins, debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery, trackUrlState, urlPushDebounceLength, hasA11yNotifications, a11yNotificationMessages, alwaysSearchOnInitialLoad }: SearchDriverOptions);
constructor({ apiConnector, autocompleteQuery, plugins, debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery, trackUrlState, routingOptions, urlPushDebounceLength, hasA11yNotifications, a11yNotificationMessages, alwaysSearchOnInitialLoad }: SearchDriverOptions);
/**

@@ -57,0 +58,0 @@ * This method is used to update state and trigger a new autocomplete search.

@@ -100,3 +100,3 @@ "use strict";

class SearchDriver {
constructor({ apiConnector, autocompleteQuery = {}, plugins = [], debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery = {}, trackUrlState = true, urlPushDebounceLength = 500, hasA11yNotifications = false, a11yNotificationMessages = {}, alwaysSearchOnInitialLoad = false }) {
constructor({ apiConnector, autocompleteQuery = {}, plugins = [], debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery = {}, trackUrlState = true, routingOptions = {}, urlPushDebounceLength = 500, hasA11yNotifications = false, a11yNotificationMessages = {}, alwaysSearchOnInitialLoad = false }) {
this.state = exports.DEFAULT_STATE;

@@ -285,3 +285,3 @@ /**

if (trackUrlState) {
this.URLManager = new URLManager_1.default();
this.URLManager = new URLManager_1.default(routingOptions);
urlState = this.URLManager.getStateFromURL();

@@ -288,0 +288,0 @@ this.URLManager.onURLStateChange((urlState) => {

@@ -20,2 +20,13 @@ import { History } from "history";

*/
interface RoutingHandler {
readUrl: () => string;
writeUrl: (url: string, { replaceUrl }: {
replaceUrl: boolean;
}) => void;
urlToState: (url: string) => RequestState;
stateToUrl: (state: RequestState) => string;
routeChangeHandler: (handler: (url?: string) => void) => () => void;
}
export declare type RoutingHandlerOptions = Partial<RoutingHandler>;
declare type RoutingChangeCallback = (state: RequestState) => void;
export default class URLManager {

@@ -25,3 +36,11 @@ history: History;

unlisten?: () => void;
constructor();
overrides: any;
routingOptions: RoutingHandler;
constructor(routingOptions?: RoutingHandlerOptions);
readUrl(): string;
writeUrl(url: string, { replaceUrl }?: {
replaceUrl?: boolean;
}): void;
urlToState(url: string): RequestState;
stateToUrl(state: RequestState): string;
/**

@@ -52,4 +71,6 @@ * Parse the current URL into application state

*/
onURLStateChange(callback: (state: RequestState) => void): void;
onURLStateChange(callback: RoutingChangeCallback): void;
routeChangeHandler(callback: any): import("history").UnregisterCallback;
tearDown(): void;
}
export {};

@@ -84,21 +84,11 @@ "use strict";

}
/**
* The URL Manager is responsible for synchronizing state between
* SearchDriver and the URL. There are 3 main cases we handle when
* synchronizing:
*
* 1. When the app loads, SearchDriver will need to
* read the current state from the URL, in order to perform the search
* expressed by the query string. `getStateFromURL` is used for this case.
*
* 2. When the URL changes as a result of `pushState` or `replaceState`,
* SearchDriver will need to be notified and given the updated state, so that
* it can re-run the current search. `onURLStateChange` is used for this case.
*
* 3. When state changes internally in the SearchDriver, as a result of an
* Action, it will need to notify the URLManager of the change. `pushStateToURL`
* is used for this case.
*/
class URLManager {
constructor() {
constructor(routingOptions = {}) {
this.routingOptions = {
readUrl: routingOptions.readUrl || this.readUrl.bind(this),
writeUrl: routingOptions.writeUrl || this.writeUrl.bind(this),
urlToState: routingOptions.urlToState || this.urlToState.bind(this),
stateToUrl: routingOptions.stateToUrl || this.stateToUrl.bind(this),
routeChangeHandler: routingOptions.routeChangeHandler || this.routeChangeHandler.bind(this)
};
this.history =

@@ -108,2 +98,29 @@ typeof window !== "undefined" ? (0, history_1.createBrowserHistory)() : (0, history_1.createMemoryHistory)();

}
/*
* These functions are used to read and write the URL
* Its designed to be overriden by the developer for their own 3rd party routing needs.
* For example developers override this function to use next.js
*
**/
readUrl() {
return this.history ? this.history.location.search : "";
}
writeUrl(url, { replaceUrl = false } = {}) {
const navigationFunction = replaceUrl
? this.history.replace
: this.history.push;
navigationFunction(`?${url}`);
}
/*
* This function is used to convert a URL into a state object and vice versa
* the state is stored as a search string in the URL.
* Developers own implementations of this function should be able to handle full urls
* and not just the search string.
**/
urlToState(url) {
return paramsToState(queryString_1.default.parse(url));
}
stateToUrl(state) {
return `${stateToQueryString(state)}`;
}
/**

@@ -115,4 +132,3 @@ * Parse the current URL into application state

getStateFromURL() {
const searchString = this.history ? this.history.location.search : "";
return paramsToState(queryString_1.default.parse(searchString));
return this.routingOptions.urlToState(this.routingOptions.readUrl());
}

@@ -128,10 +144,5 @@ /**

pushStateToURL(state, { replaceUrl = false } = {}) {
const searchString = stateToQueryString(state);
this.lastPushSearchString = searchString;
const navigationFunction = replaceUrl
? this.history.replace
: this.history.push;
navigationFunction({
search: `?${searchString}`
});
const url = this.routingOptions.stateToUrl(state);
this.lastPushSearchString = url;
this.routingOptions.writeUrl(url, { replaceUrl });
}

@@ -147,6 +158,4 @@ /**

onURLStateChange(callback) {
this.unlisten = this.history.listen((location) => {
// If this URL is updated as a result of a pushState request, we don't
// want to notify that the URL changed.
if (`?${this.lastPushSearchString}` === location.search)
const handler = (url) => {
if (`?${this.lastPushSearchString}` === url)
return;

@@ -156,5 +165,12 @@ // Once we've decided to return based on lastPushSearchString, reset

this.lastPushSearchString = "";
callback(paramsToState(queryString_1.default.parse(location.search)));
});
callback(this.routingOptions.urlToState(url));
};
this.unlisten = this.routingOptions.routeChangeHandler(handler.bind(this));
}
routeChangeHandler(callback) {
const handler = (location) => {
callback(location.search);
};
return this.history.listen(handler);
}
tearDown() {

@@ -161,0 +177,0 @@ this.unlisten();

@@ -621,2 +621,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

}));
describe("SearchDriver Routing Options", () => {
it("should allow overrides to urlManager", () => {
const initialState = {};
const routingOptions = {
readUrl: jest.fn(() => {
return "?q=override";
}),
writeUrl: jest.fn()
};
setupDriver({
initialState,
routingOptions: routingOptions
});
expect(MockedURLManager).toBeCalledWith(routingOptions);
});
});
describe("SearchDriver hooks", () => {

@@ -623,0 +639,0 @@ it("onSearch Hook", () => {

import URLManager from "../URLManager";
function createManager() {
const manager = new URLManager();
function createManager(options) {
const manager = new URLManager(options);
return manager;

@@ -94,3 +94,3 @@ }

manager.pushStateToURL(basicParameterState);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?q=node&size=n_20_n&filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D=value&filters%5B0%5D%5Btype%5D=all&filters%5B1%5D%5Bfield%5D=node&filters%5B1%5D%5Bvalues%5D%5B0%5D=value&filters%5B1%5D%5Btype%5D=all&sort-field=name&sort-direction=asc");

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

manager.pushStateToURL(parameterStateWithRangeFilters);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bfrom%5D=n_12_n&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bname%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D%5Bto%5D=n_4000_n&filters%5B0%5D%5Btype%5D=all");

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

manager.pushStateToURL(parameterStateWithSortList);
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?size=n_20_n&sort%5B0%5D%5Bdirection%5D=asc&sort%5B0%5D%5Bfield%5D=name&sort%5B1%5D%5Bdirection%5D=desc&sort%5B1%5D%5Bfield%5D=title");

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

manager.pushStateToURL(basicParameterState, { replaceUrl: true });
const queryString = spy.mock.calls[0][0].search;
const queryString = spy.mock.calls[0][0];
expect(queryString).toEqual("?q=node&size=n_20_n&filters%5B0%5D%5Bfield%5D=test&filters%5B0%5D%5Bvalues%5D%5B0%5D=value&filters%5B0%5D%5Btype%5D=all&filters%5B1%5D%5Bfield%5D=node&filters%5B1%5D%5Bvalues%5D%5B0%5D=value&filters%5B1%5D%5Btype%5D=all&sort-field=name&sort-direction=asc");

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

manager.pushStateToURL(state);
return pushSpy.mock.calls[0][0].search;
return pushSpy.mock.calls[0][0];
}

@@ -216,1 +216,38 @@ function simulateBrowserHistoryEvent(newUrl) {

});
describe("routing options overrides", () => {
const routingOptions = {
readUrl: jest.fn(() => {
return "/search/tvs?query=samsung";
}),
writeUrl: jest.fn(),
stateToUrl: jest.fn((state) => {
const categoryFilter = state.filters.find((filter) => filter.field === "category");
const category = categoryFilter ? categoryFilter.values[0] : "all";
return `/search/${category}?query=${state.searchTerm}`;
}),
urlToState: jest.fn((url) => {
const match = url.match(/\/search\/(\w+)\?query=(\w+)/);
if (!match)
return {};
return {
searchTerm: match[2],
filters: [{ field: "category", values: [match[1]], type: "all" }]
};
})
};
it("should write correct url", () => {
const manager = createManager(routingOptions);
manager.pushStateToURL({
searchTerm: "samsung",
filters: [{ field: "category", values: ["gaming"], type: "all" }]
});
expect(routingOptions.writeUrl).toHaveBeenCalledWith("/search/gaming?query=samsung", { replaceUrl: false });
});
it("should read correct url", () => {
const manager = createManager(routingOptions);
expect(manager.getStateFromURL()).toEqual({
searchTerm: "samsung",
filters: [{ field: "category", values: ["tvs"], type: "all" }]
});
});
});

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

import URLManager from "./URLManager";
import URLManager, { RoutingHandlerOptions } from "./URLManager";
import RequestSequencer from "./RequestSequencer";

@@ -25,2 +25,3 @@ import DebounceManager from "./DebounceManager";

trackUrlState?: boolean;
routingOptions?: RoutingHandlerOptions;
urlPushDebounceLength?: number;

@@ -54,3 +55,3 @@ hasA11yNotifications?: boolean;

apiConnector?: APIConnector;
constructor({ apiConnector, autocompleteQuery, plugins, debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery, trackUrlState, urlPushDebounceLength, hasA11yNotifications, a11yNotificationMessages, alwaysSearchOnInitialLoad }: SearchDriverOptions);
constructor({ apiConnector, autocompleteQuery, plugins, debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery, trackUrlState, routingOptions, urlPushDebounceLength, hasA11yNotifications, a11yNotificationMessages, alwaysSearchOnInitialLoad }: SearchDriverOptions);
/**

@@ -57,0 +58,0 @@ * This method is used to update state and trigger a new autocomplete search.

@@ -75,3 +75,3 @@ var __rest = (this && this.__rest) || function (s, e) {

class SearchDriver {
constructor({ apiConnector, autocompleteQuery = {}, plugins = [], debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery = {}, trackUrlState = true, urlPushDebounceLength = 500, hasA11yNotifications = false, a11yNotificationMessages = {}, alwaysSearchOnInitialLoad = false }) {
constructor({ apiConnector, autocompleteQuery = {}, plugins = [], debug, initialState, onSearch, onAutocomplete, onResultClick, onAutocompleteResultClick, searchQuery = {}, trackUrlState = true, routingOptions = {}, urlPushDebounceLength = 500, hasA11yNotifications = false, a11yNotificationMessages = {}, alwaysSearchOnInitialLoad = false }) {
this.state = DEFAULT_STATE;

@@ -260,3 +260,3 @@ /**

if (trackUrlState) {
this.URLManager = new URLManager();
this.URLManager = new URLManager(routingOptions);
urlState = this.URLManager.getStateFromURL();

@@ -263,0 +263,0 @@ this.URLManager.onURLStateChange((urlState) => {

@@ -20,2 +20,13 @@ import { History } from "history";

*/
interface RoutingHandler {
readUrl: () => string;
writeUrl: (url: string, { replaceUrl }: {
replaceUrl: boolean;
}) => void;
urlToState: (url: string) => RequestState;
stateToUrl: (state: RequestState) => string;
routeChangeHandler: (handler: (url?: string) => void) => () => void;
}
export declare type RoutingHandlerOptions = Partial<RoutingHandler>;
declare type RoutingChangeCallback = (state: RequestState) => void;
export default class URLManager {

@@ -25,3 +36,11 @@ history: History;

unlisten?: () => void;
constructor();
overrides: any;
routingOptions: RoutingHandler;
constructor(routingOptions?: RoutingHandlerOptions);
readUrl(): string;
writeUrl(url: string, { replaceUrl }?: {
replaceUrl?: boolean;
}): void;
urlToState(url: string): RequestState;
stateToUrl(state: RequestState): string;
/**

@@ -52,4 +71,6 @@ * Parse the current URL into application state

*/
onURLStateChange(callback: (state: RequestState) => void): void;
onURLStateChange(callback: RoutingChangeCallback): void;
routeChangeHandler(callback: any): import("history").UnregisterCallback;
tearDown(): void;
}
export {};

@@ -79,21 +79,11 @@ import { createBrowserHistory as createHistory, createMemoryHistory } from "history";

}
/**
* The URL Manager is responsible for synchronizing state between
* SearchDriver and the URL. There are 3 main cases we handle when
* synchronizing:
*
* 1. When the app loads, SearchDriver will need to
* read the current state from the URL, in order to perform the search
* expressed by the query string. `getStateFromURL` is used for this case.
*
* 2. When the URL changes as a result of `pushState` or `replaceState`,
* SearchDriver will need to be notified and given the updated state, so that
* it can re-run the current search. `onURLStateChange` is used for this case.
*
* 3. When state changes internally in the SearchDriver, as a result of an
* Action, it will need to notify the URLManager of the change. `pushStateToURL`
* is used for this case.
*/
export default class URLManager {
constructor() {
constructor(routingOptions = {}) {
this.routingOptions = {
readUrl: routingOptions.readUrl || this.readUrl.bind(this),
writeUrl: routingOptions.writeUrl || this.writeUrl.bind(this),
urlToState: routingOptions.urlToState || this.urlToState.bind(this),
stateToUrl: routingOptions.stateToUrl || this.stateToUrl.bind(this),
routeChangeHandler: routingOptions.routeChangeHandler || this.routeChangeHandler.bind(this)
};
this.history =

@@ -103,2 +93,29 @@ typeof window !== "undefined" ? createHistory() : createMemoryHistory();

}
/*
* These functions are used to read and write the URL
* Its designed to be overriden by the developer for their own 3rd party routing needs.
* For example developers override this function to use next.js
*
**/
readUrl() {
return this.history ? this.history.location.search : "";
}
writeUrl(url, { replaceUrl = false } = {}) {
const navigationFunction = replaceUrl
? this.history.replace
: this.history.push;
navigationFunction(`?${url}`);
}
/*
* This function is used to convert a URL into a state object and vice versa
* the state is stored as a search string in the URL.
* Developers own implementations of this function should be able to handle full urls
* and not just the search string.
**/
urlToState(url) {
return paramsToState(queryString.parse(url));
}
stateToUrl(state) {
return `${stateToQueryString(state)}`;
}
/**

@@ -110,4 +127,3 @@ * Parse the current URL into application state

getStateFromURL() {
const searchString = this.history ? this.history.location.search : "";
return paramsToState(queryString.parse(searchString));
return this.routingOptions.urlToState(this.routingOptions.readUrl());
}

@@ -123,10 +139,5 @@ /**

pushStateToURL(state, { replaceUrl = false } = {}) {
const searchString = stateToQueryString(state);
this.lastPushSearchString = searchString;
const navigationFunction = replaceUrl
? this.history.replace
: this.history.push;
navigationFunction({
search: `?${searchString}`
});
const url = this.routingOptions.stateToUrl(state);
this.lastPushSearchString = url;
this.routingOptions.writeUrl(url, { replaceUrl });
}

@@ -142,6 +153,4 @@ /**

onURLStateChange(callback) {
this.unlisten = this.history.listen((location) => {
// If this URL is updated as a result of a pushState request, we don't
// want to notify that the URL changed.
if (`?${this.lastPushSearchString}` === location.search)
const handler = (url) => {
if (`?${this.lastPushSearchString}` === url)
return;

@@ -151,5 +160,12 @@ // Once we've decided to return based on lastPushSearchString, reset

this.lastPushSearchString = "";
callback(paramsToState(queryString.parse(location.search)));
});
callback(this.routingOptions.urlToState(url));
};
this.unlisten = this.routingOptions.routeChangeHandler(handler.bind(this));
}
routeChangeHandler(callback) {
const handler = (location) => {
callback(location.search);
};
return this.history.listen(handler);
}
tearDown() {

@@ -156,0 +172,0 @@ this.unlisten();

{
"name": "@elastic/search-ui",
"version": "1.18.0",
"version": "1.18.1",
"description": "A Headless Search UI library",

@@ -48,3 +48,3 @@ "license": "Apache-2.0",

},
"gitHead": "09e05a411ce80922d81a2fbddd66d5869104ce7c"
"gitHead": "263b5630928ce5573b0d9fb3705b75ff74bd4b8b"
}
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