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

@stencil/react-output-target

Package Overview
Dependencies
Maintainers
11
Versions
113
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@stencil/react-output-target - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

100

dist/index.cjs.js

@@ -15,3 +15,13 @@ 'use strict';

const readFile = util.promisify(fs__default['default'].readFile);
/**
* Send a string to lowercase
* @param str the string to lowercase
* @returns the lowercased string
*/
const toLowerCase = (str) => str.toLowerCase();
/**
* Convert a string using dash-case to PascalCase
* @param str the string to convert to PascalCase
* @returns the PascalCased string
*/
const dashToPascalCase = (str) => toLowerCase(str)

@@ -21,2 +31,8 @@ .split('-')

.join('');
/**
* Sorts a provided array by a property belonging to an item that exists on each item in the array
* @param array the array to sort
* @param prop a function to look up a field on an entry in the provided array
* @returns a shallow copy of the array, sorted by the property resolved by `prop`
*/
function sortBy(array, prop) {

@@ -33,2 +49,7 @@ return array.slice().sort((a, b) => {

}
/**
* Normalize a path
* @param str the path to normalize
* @returns the normalized path
*/
function normalizePath(str) {

@@ -61,2 +82,9 @@ // Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar

}
/**
* Generate the relative import from `pathFrom` to `pathTo`
* @param pathFrom the path that shall be used as the origin in determining the relative path
* @param pathTo the path that shall be used as the destination in determining the relative path
* @param ext an extension to remove from the final path
* @returns the derived relative import
*/
function relativeImport(pathFrom, pathTo, ext) {

@@ -72,2 +100,7 @@ let relativePath = path__default['default'].relative(path__default['default'].dirname(pathFrom), path__default['default'].dirname(pathTo));

}
/**
* Attempts to read a `package.json` file at the provided directory.
* @param rootDir the directory to search for the `package.json` file to read
* @returns the read and parsed `package.json` file
*/
async function readPackageJson(rootDir) {

@@ -95,2 +128,9 @@ const pkgJsonPath = path__default['default'].join(rootDir, 'package.json');

/**
* Generate and write the Stencil-React bindings to disc
* @param config the Stencil configuration associated with the project
* @param compilerCtx the compiler context of the current Stencil build
* @param outputTarget the output target configuration for generating the React wrapper
* @param components the components to generate the bindings for
*/
async function reactProxyOutput(config, compilerCtx, outputTarget, components) {

@@ -104,5 +144,20 @@ const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);

}
/**
* Removes all components from the provided `cmps` list that exist in the provided `excludedComponents` list
* @param excludeComponents the list of components that should be removed from the provided `cmps` list
* @param cmps a list of components
* @returns the filtered list of components
*/
function getFilteredComponents(excludeComponents = [], cmps) {
return sortBy(cmps, (cmp) => cmp.tagName).filter((c) => !excludeComponents.includes(c.tagName) && !c.internal);
}
/**
* Generate the code that will be responsible for creating the Stencil-React bindings
* @param config the Stencil configuration associated with the project
* @param components the Stencil components to generate wrappers for
* @param pkgData `package.json` data for the Stencil project
* @param outputTarget the output target configuration used to generate the Stencil-React bindings
* @param rootDir the directory of the Stencil project
* @returns the generated code to create the Stencil-React bindings
*/
function generateProxies(config, components, pkgData, outputTarget, rootDir) {

@@ -134,6 +189,5 @@ const distTypesDir = path__default['default'].dirname(pkgData.types);

/**
* Build an array of Custom Elements build imports and namespace them
* so that they do not conflict with the React wrapper names. For example,
* IonButton would be imported as IonButtonCmp so as to not conflict with the
* IonButton React Component that takes in the Web Component as a parameter.
* Build an array of Custom Elements build imports and namespace them so that they do not conflict with the React
* wrapper names. For example, IonButton would be imported as IonButtonCmp to not conflict with the IonButton React
* Component that takes in the Web Component as a parameter.
*/

@@ -166,10 +220,7 @@ if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {

/**
* Defines the React component that developers will import
* to use in their applications.
* @param cmpMeta: Meta data for a single Web Component
* @param includeCustomElement: If `true`, the Web Component instance
* will be passed in to createReactComponent to be registered
* with the Custom Elements Registry.
* @returns An array where each entry is a string version
* of the React component definition.
* Defines the React component that developers will import to use in their applications.
* @param cmpMeta Meta data for a single Web Component
* @param includeCustomElement If `true`, the Web Component instance will be passed in to createReactComponent to be
* registered with the Custom Elements Registry.
* @returns An array where each entry is a string version of the React component definition.
*/

@@ -187,2 +238,9 @@ function createComponentDefinition(cmpMeta, includeCustomElement = false) {

}
/**
* Copy resources used to generate the Stencil-React bindings. The resources copied here are not specific a project's
* Stencil components, but rather the logic used to do the actual component generation.
* @param config the Stencil configuration associated with the project
* @param outputTarget the output target configuration for generating the Stencil-React bindings
* @returns The results of performing the copy
*/
async function copyResources(config, outputTarget) {

@@ -203,2 +261,8 @@ if (!config.sys || !config.sys.copy || !config.sys.glob) {

}
/**
* Derive the path to the loader
* @param config the Stencil configuration for the project
* @param outputTarget the output target used for generating the Stencil-React bindings
* @returns the derived loader path
*/
function getPathToCorePackageLoader(config, outputTarget) {

@@ -223,2 +287,7 @@ var _a;

/**
* Creates an output target for binding Stencil components to be used in a React context
* @param outputTarget the user-defined output target defined in a Stencil configuration file
* @returns an output target that can be used by the Stencil compiler
*/
const reactOutputTarget = (outputTarget) => ({

@@ -236,2 +305,9 @@ type: 'custom',

});
/**
* Normalizes the structure of a provided output target and verifies a Stencil configuration
* associated with the wrapper is valid
* @param config the configuration to validate
* @param outputTarget the output target to normalize
* @returns an output target that's been normalized
*/
function normalizeOutputTarget(config, outputTarget) {

@@ -238,0 +314,0 @@ var _a, _b;

@@ -6,3 +6,13 @@ import path from 'path';

const readFile = promisify(fs.readFile);
/**
* Send a string to lowercase
* @param str the string to lowercase
* @returns the lowercased string
*/
const toLowerCase = (str) => str.toLowerCase();
/**
* Convert a string using dash-case to PascalCase
* @param str the string to convert to PascalCase
* @returns the PascalCased string
*/
const dashToPascalCase = (str) => toLowerCase(str)

@@ -12,2 +22,8 @@ .split('-')

.join('');
/**
* Sorts a provided array by a property belonging to an item that exists on each item in the array
* @param array the array to sort
* @param prop a function to look up a field on an entry in the provided array
* @returns a shallow copy of the array, sorted by the property resolved by `prop`
*/
function sortBy(array, prop) {

@@ -24,2 +40,7 @@ return array.slice().sort((a, b) => {

}
/**
* Normalize a path
* @param str the path to normalize
* @returns the normalized path
*/
function normalizePath(str) {

@@ -52,2 +73,9 @@ // Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar

}
/**
* Generate the relative import from `pathFrom` to `pathTo`
* @param pathFrom the path that shall be used as the origin in determining the relative path
* @param pathTo the path that shall be used as the destination in determining the relative path
* @param ext an extension to remove from the final path
* @returns the derived relative import
*/
function relativeImport(pathFrom, pathTo, ext) {

@@ -63,2 +91,7 @@ let relativePath = path.relative(path.dirname(pathFrom), path.dirname(pathTo));

}
/**
* Attempts to read a `package.json` file at the provided directory.
* @param rootDir the directory to search for the `package.json` file to read
* @returns the read and parsed `package.json` file
*/
async function readPackageJson(rootDir) {

@@ -86,2 +119,9 @@ const pkgJsonPath = path.join(rootDir, 'package.json');

/**
* Generate and write the Stencil-React bindings to disc
* @param config the Stencil configuration associated with the project
* @param compilerCtx the compiler context of the current Stencil build
* @param outputTarget the output target configuration for generating the React wrapper
* @param components the components to generate the bindings for
*/
async function reactProxyOutput(config, compilerCtx, outputTarget, components) {

@@ -95,5 +135,20 @@ const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);

}
/**
* Removes all components from the provided `cmps` list that exist in the provided `excludedComponents` list
* @param excludeComponents the list of components that should be removed from the provided `cmps` list
* @param cmps a list of components
* @returns the filtered list of components
*/
function getFilteredComponents(excludeComponents = [], cmps) {
return sortBy(cmps, (cmp) => cmp.tagName).filter((c) => !excludeComponents.includes(c.tagName) && !c.internal);
}
/**
* Generate the code that will be responsible for creating the Stencil-React bindings
* @param config the Stencil configuration associated with the project
* @param components the Stencil components to generate wrappers for
* @param pkgData `package.json` data for the Stencil project
* @param outputTarget the output target configuration used to generate the Stencil-React bindings
* @param rootDir the directory of the Stencil project
* @returns the generated code to create the Stencil-React bindings
*/
function generateProxies(config, components, pkgData, outputTarget, rootDir) {

@@ -125,6 +180,5 @@ const distTypesDir = path.dirname(pkgData.types);

/**
* Build an array of Custom Elements build imports and namespace them
* so that they do not conflict with the React wrapper names. For example,
* IonButton would be imported as IonButtonCmp so as to not conflict with the
* IonButton React Component that takes in the Web Component as a parameter.
* Build an array of Custom Elements build imports and namespace them so that they do not conflict with the React
* wrapper names. For example, IonButton would be imported as IonButtonCmp to not conflict with the IonButton React
* Component that takes in the Web Component as a parameter.
*/

@@ -157,10 +211,7 @@ if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {

/**
* Defines the React component that developers will import
* to use in their applications.
* @param cmpMeta: Meta data for a single Web Component
* @param includeCustomElement: If `true`, the Web Component instance
* will be passed in to createReactComponent to be registered
* with the Custom Elements Registry.
* @returns An array where each entry is a string version
* of the React component definition.
* Defines the React component that developers will import to use in their applications.
* @param cmpMeta Meta data for a single Web Component
* @param includeCustomElement If `true`, the Web Component instance will be passed in to createReactComponent to be
* registered with the Custom Elements Registry.
* @returns An array where each entry is a string version of the React component definition.
*/

@@ -178,2 +229,9 @@ function createComponentDefinition(cmpMeta, includeCustomElement = false) {

}
/**
* Copy resources used to generate the Stencil-React bindings. The resources copied here are not specific a project's
* Stencil components, but rather the logic used to do the actual component generation.
* @param config the Stencil configuration associated with the project
* @param outputTarget the output target configuration for generating the Stencil-React bindings
* @returns The results of performing the copy
*/
async function copyResources(config, outputTarget) {

@@ -194,2 +252,8 @@ if (!config.sys || !config.sys.copy || !config.sys.glob) {

}
/**
* Derive the path to the loader
* @param config the Stencil configuration for the project
* @param outputTarget the output target used for generating the Stencil-React bindings
* @returns the derived loader path
*/
function getPathToCorePackageLoader(config, outputTarget) {

@@ -214,2 +278,7 @@ var _a;

/**
* Creates an output target for binding Stencil components to be used in a React context
* @param outputTarget the user-defined output target defined in a Stencil configuration file
* @returns an output target that can be used by the Stencil compiler
*/
const reactOutputTarget = (outputTarget) => ({

@@ -227,2 +296,9 @@ type: 'custom',

});
/**
* Normalizes the structure of a provided output target and verifies a Stencil configuration
* associated with the wrapper is valid
* @param config the configuration to validate
* @param outputTarget the output target to normalize
* @returns an output target that's been normalized
*/
function normalizeOutputTarget(config, outputTarget) {

@@ -229,0 +305,0 @@ var _a, _b;

41

dist/output-react.d.ts
import type { OutputTargetReact, PackageJSON } from './types';
import type { CompilerCtx, ComponentCompilerMeta, Config } from '@stencil/core/internal';
export declare function reactProxyOutput(config: Config, compilerCtx: CompilerCtx, outputTarget: OutputTargetReact, components: ComponentCompilerMeta[]): Promise<void>;
export declare function generateProxies(config: Config, components: ComponentCompilerMeta[], pkgData: PackageJSON, outputTarget: OutputTargetReact, rootDir: string): string;
/**
* Defines the React component that developers will import
* to use in their applications.
* @param cmpMeta: Meta data for a single Web Component
* @param includeCustomElement: If `true`, the Web Component instance
* will be passed in to createReactComponent to be registered
* with the Custom Elements Registry.
* @returns An array where each entry is a string version
* of the React component definition.
* Generate and write the Stencil-React bindings to disc
* @param config the Stencil configuration associated with the project
* @param compilerCtx the compiler context of the current Stencil build
* @param outputTarget the output target configuration for generating the React wrapper
* @param components the components to generate the bindings for
*/
export declare function createComponentDefinition(cmpMeta: ComponentCompilerMeta, includeCustomElement?: boolean): string[];
export declare function reactProxyOutput(config: Config, compilerCtx: CompilerCtx, outputTarget: OutputTargetReact, components: ReadonlyArray<ComponentCompilerMeta>): Promise<void>;
/**
* Generate the code that will be responsible for creating the Stencil-React bindings
* @param config the Stencil configuration associated with the project
* @param components the Stencil components to generate wrappers for
* @param pkgData `package.json` data for the Stencil project
* @param outputTarget the output target configuration used to generate the Stencil-React bindings
* @param rootDir the directory of the Stencil project
* @returns the generated code to create the Stencil-React bindings
*/
export declare function generateProxies(config: Config, components: ReadonlyArray<ComponentCompilerMeta>, pkgData: PackageJSON, outputTarget: OutputTargetReact, rootDir: string): string;
/**
* Defines the React component that developers will import to use in their applications.
* @param cmpMeta Meta data for a single Web Component
* @param includeCustomElement If `true`, the Web Component instance will be passed in to createReactComponent to be
* registered with the Custom Elements Registry.
* @returns An array where each entry is a string version of the React component definition.
*/
export declare function createComponentDefinition(cmpMeta: ComponentCompilerMeta, includeCustomElement?: boolean): ReadonlyArray<string>;
/**
* Derive the path to the loader
* @param config the Stencil configuration for the project
* @param outputTarget the output target used for generating the Stencil-React bindings
* @returns the derived loader path
*/
export declare function getPathToCorePackageLoader(config: Config, outputTarget: OutputTargetReact): string;
export declare const GENERATED_DTS = "components.d.ts";
import path from 'path';
import { dashToPascalCase, normalizePath, readPackageJson, relativeImport, sortBy } from './utils';
/**
* Generate and write the Stencil-React bindings to disc
* @param config the Stencil configuration associated with the project
* @param compilerCtx the compiler context of the current Stencil build
* @param outputTarget the output target configuration for generating the React wrapper
* @param components the components to generate the bindings for
*/
export async function reactProxyOutput(config, compilerCtx, outputTarget, components) {

@@ -11,5 +18,20 @@ const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);

}
/**
* Removes all components from the provided `cmps` list that exist in the provided `excludedComponents` list
* @param excludeComponents the list of components that should be removed from the provided `cmps` list
* @param cmps a list of components
* @returns the filtered list of components
*/
function getFilteredComponents(excludeComponents = [], cmps) {
return sortBy(cmps, (cmp) => cmp.tagName).filter((c) => !excludeComponents.includes(c.tagName) && !c.internal);
}
/**
* Generate the code that will be responsible for creating the Stencil-React bindings
* @param config the Stencil configuration associated with the project
* @param components the Stencil components to generate wrappers for
* @param pkgData `package.json` data for the Stencil project
* @param outputTarget the output target configuration used to generate the Stencil-React bindings
* @param rootDir the directory of the Stencil project
* @returns the generated code to create the Stencil-React bindings
*/
export function generateProxies(config, components, pkgData, outputTarget, rootDir) {

@@ -41,6 +63,5 @@ const distTypesDir = path.dirname(pkgData.types);

/**
* Build an array of Custom Elements build imports and namespace them
* so that they do not conflict with the React wrapper names. For example,
* IonButton would be imported as IonButtonCmp so as to not conflict with the
* IonButton React Component that takes in the Web Component as a parameter.
* Build an array of Custom Elements build imports and namespace them so that they do not conflict with the React
* wrapper names. For example, IonButton would be imported as IonButtonCmp to not conflict with the IonButton React
* Component that takes in the Web Component as a parameter.
*/

@@ -73,10 +94,7 @@ if (outputTarget.includeImportCustomElements && outputTarget.componentCorePackage !== undefined) {

/**
* Defines the React component that developers will import
* to use in their applications.
* @param cmpMeta: Meta data for a single Web Component
* @param includeCustomElement: If `true`, the Web Component instance
* will be passed in to createReactComponent to be registered
* with the Custom Elements Registry.
* @returns An array where each entry is a string version
* of the React component definition.
* Defines the React component that developers will import to use in their applications.
* @param cmpMeta Meta data for a single Web Component
* @param includeCustomElement If `true`, the Web Component instance will be passed in to createReactComponent to be
* registered with the Custom Elements Registry.
* @returns An array where each entry is a string version of the React component definition.
*/

@@ -94,2 +112,9 @@ export function createComponentDefinition(cmpMeta, includeCustomElement = false) {

}
/**
* Copy resources used to generate the Stencil-React bindings. The resources copied here are not specific a project's
* Stencil components, but rather the logic used to do the actual component generation.
* @param config the Stencil configuration associated with the project
* @param outputTarget the output target configuration for generating the Stencil-React bindings
* @returns The results of performing the copy
*/
async function copyResources(config, outputTarget) {

@@ -110,2 +135,8 @@ if (!config.sys || !config.sys.copy || !config.sys.glob) {

}
/**
* Derive the path to the loader
* @param config the Stencil configuration for the project
* @param outputTarget the output target used for generating the Stencil-React bindings
* @returns the derived loader path
*/
export function getPathToCorePackageLoader(config, outputTarget) {

@@ -112,0 +143,0 @@ var _a;

import type { Config, OutputTargetCustom } from '@stencil/core/internal';
import type { OutputTargetReact } from './types';
/**
* Creates an output target for binding Stencil components to be used in a React context
* @param outputTarget the user-defined output target defined in a Stencil configuration file
* @returns an output target that can be used by the Stencil compiler
*/
export declare const reactOutputTarget: (outputTarget: OutputTargetReact) => OutputTargetCustom;
/**
* Normalizes the structure of a provided output target and verifies a Stencil configuration
* associated with the wrapper is valid
* @param config the configuration to validate
* @param outputTarget the output target to normalize
* @returns an output target that's been normalized
*/
export declare function normalizeOutputTarget(config: Config, outputTarget: any): OutputTargetReact;
import { normalizePath } from './utils';
import { reactProxyOutput } from './output-react';
import path from 'path';
/**
* Creates an output target for binding Stencil components to be used in a React context
* @param outputTarget the user-defined output target defined in a Stencil configuration file
* @returns an output target that can be used by the Stencil compiler
*/
export const reactOutputTarget = (outputTarget) => ({

@@ -16,2 +21,9 @@ type: 'custom',

});
/**
* Normalizes the structure of a provided output target and verifies a Stencil configuration
* associated with the wrapper is valid
* @param config the configuration to validate
* @param outputTarget the output target to normalize
* @returns an output target that's been normalized
*/
export function normalizeOutputTarget(config, outputTarget) {

@@ -18,0 +30,0 @@ var _a, _b;

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

/**
* An output target configuration interface used to configure Stencil to properly generate the bindings necessary to use
* Stencil components in a React application
*/
export interface OutputTargetReact {

@@ -11,4 +15,7 @@ componentCorePackage?: string;

}
/**
* Describes the fields of a package.json file necessary to generate the Stencil-React bindings
*/
export interface PackageJSON {
types: string;
}
import type { PackageJSON } from './types';
/**
* Send a string to lowercase
* @param str the string to lowercase
* @returns the lowercased string
*/
export declare const toLowerCase: (str: string) => string;
/**
* Convert a string using dash-case to PascalCase
* @param str the string to convert to PascalCase
* @returns the PascalCased string
*/
export declare const dashToPascalCase: (str: string) => string;
/**
* Flattens a two-dimensional array into a one dimensional array
* @param array the array to flatten
* @returns the flattened array
*/
export declare function flatOne<T>(array: T[][]): T[];
export declare function sortBy<T>(array: T[], prop: (item: T) => string): T[];
/**
* Sorts a provided array by a property belonging to an item that exists on each item in the array
* @param array the array to sort
* @param prop a function to look up a field on an entry in the provided array
* @returns a shallow copy of the array, sorted by the property resolved by `prop`
*/
export declare function sortBy<T>(array: ReadonlyArray<T>, prop: (item: T) => string): ReadonlyArray<T>;
/**
* Normalize a path
* @param str the path to normalize
* @returns the normalized path
*/
export declare function normalizePath(str: string): string;
/**
* Generate the relative import from `pathFrom` to `pathTo`
* @param pathFrom the path that shall be used as the origin in determining the relative path
* @param pathTo the path that shall be used as the destination in determining the relative path
* @param ext an extension to remove from the final path
* @returns the derived relative import
*/
export declare function relativeImport(pathFrom: string, pathTo: string, ext?: string): string;
/**
* Attempts to read a `package.json` file at the provided directory.
* @param rootDir the directory to search for the `package.json` file to read
* @returns the read and parsed `package.json` file
*/
export declare function readPackageJson(rootDir: string): Promise<PackageJSON>;

@@ -5,3 +5,13 @@ import path from 'path';

const readFile = promisify(fs.readFile);
/**
* Send a string to lowercase
* @param str the string to lowercase
* @returns the lowercased string
*/
export const toLowerCase = (str) => str.toLowerCase();
/**
* Convert a string using dash-case to PascalCase
* @param str the string to convert to PascalCase
* @returns the PascalCased string
*/
export const dashToPascalCase = (str) => toLowerCase(str)

@@ -11,2 +21,8 @@ .split('-')

.join('');
// TODO(STENCIL-356): Investigate removing this unused function
/**
* Flattens a two-dimensional array into a one dimensional array
* @param array the array to flatten
* @returns the flattened array
*/
export function flatOne(array) {

@@ -21,2 +37,8 @@ if (array.flat) {

}
/**
* Sorts a provided array by a property belonging to an item that exists on each item in the array
* @param array the array to sort
* @param prop a function to look up a field on an entry in the provided array
* @returns a shallow copy of the array, sorted by the property resolved by `prop`
*/
export function sortBy(array, prop) {

@@ -33,2 +55,7 @@ return array.slice().sort((a, b) => {

}
/**
* Normalize a path
* @param str the path to normalize
* @returns the normalized path
*/
export function normalizePath(str) {

@@ -61,2 +88,9 @@ // Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar

}
/**
* Generate the relative import from `pathFrom` to `pathTo`
* @param pathFrom the path that shall be used as the origin in determining the relative path
* @param pathTo the path that shall be used as the destination in determining the relative path
* @param ext an extension to remove from the final path
* @returns the derived relative import
*/
export function relativeImport(pathFrom, pathTo, ext) {

@@ -72,2 +106,7 @@ let relativePath = path.relative(path.dirname(pathFrom), path.dirname(pathTo));

}
/**
* Attempts to read a `package.json` file at the provided directory.
* @param rootDir the directory to search for the `package.json` file to read
* @returns the read and parsed `package.json` file
*/
export async function readPackageJson(rootDir) {

@@ -74,0 +113,0 @@ const pkgJsonPath = path.join(rootDir, 'package.json');

{
"name": "@stencil/react-output-target",
"version": "0.2.1",
"version": "0.3.0",
"description": "React output target for @stencil/core components.",

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

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