mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor: connector loader (#2809)
This commit is contained in:
parent
e1d70bc9cf
commit
db71cc11ac
11 changed files with 85 additions and 189 deletions
|
@ -4,7 +4,7 @@ import path from 'path';
|
|||
|
||||
import { connectorDirectory } from '@logto/cli/lib/constants.js';
|
||||
import { getConnectorPackagesFromDirectory } from '@logto/cli/lib/utilities.js';
|
||||
import type { AllConnector, CreateConnector } from '@logto/connector-kit';
|
||||
import type { AllConnector } from '@logto/connector-kit';
|
||||
import { validateConfig } from '@logto/connector-kit';
|
||||
import { findPackage } from '@logto/shared';
|
||||
import chalk from 'chalk';
|
||||
|
@ -15,8 +15,8 @@ import { findAllConnectors } from '#src/queries/connector.js';
|
|||
import { defaultConnectorMethods } from './consts.js';
|
||||
import { metaUrl } from './meta-url.js';
|
||||
import type { ConnectorFactory, LogtoConnector } from './types.js';
|
||||
import { checkConnectorKitVersion } from './utilities/compatibility.js';
|
||||
import { getConnectorConfig, parseMetadata, validateConnectorModule } from './utilities/index.js';
|
||||
import { loadConnector } from './utilities/loader.js';
|
||||
|
||||
const currentDirname = path.dirname(fileURLToPath(metaUrl));
|
||||
|
||||
|
@ -40,17 +40,7 @@ export const loadConnectorFactories = async () => {
|
|||
const connectorFactories = await Promise.all(
|
||||
connectorPackages.map(async ({ path: packagePath, name }) => {
|
||||
try {
|
||||
await checkConnectorKitVersion(packagePath);
|
||||
|
||||
// TODO: fix type and remove `/lib/index.js` suffix once we upgrade all connectors to ESM
|
||||
const {
|
||||
default: { default: createConnector },
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
} = (await import(packagePath + '/lib/index.js')) as {
|
||||
default: {
|
||||
default: CreateConnector<AllConnector>;
|
||||
};
|
||||
};
|
||||
const createConnector = await loadConnector(packagePath);
|
||||
const rawConnector = await createConnector({ getConfig: getConnectorConfig });
|
||||
validateConnectorModule(rawConnector);
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import path from 'path';
|
||||
|
||||
import connectorKitMeta from '@logto/connector-kit/package.json' assert { type: 'json' };
|
||||
import { satisfies } from 'semver';
|
||||
|
||||
const connectorKit = '@logto/connector-kit';
|
||||
const { version: currentVersion } = connectorKitMeta;
|
||||
|
||||
export const checkConnectorKitVersion = async (connectorPath: string) => {
|
||||
const {
|
||||
default: { dependencies },
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
} = (await import(path.join(connectorPath, 'package.json'), {
|
||||
assert: { type: 'json' },
|
||||
})) as { default: Record<string, unknown> };
|
||||
|
||||
if (dependencies !== null && typeof dependencies === 'object' && connectorKit in dependencies) {
|
||||
const value = dependencies[connectorKit];
|
||||
|
||||
if (typeof value === 'string') {
|
||||
if (satisfies(currentVersion, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Connector requires ${connectorKit} to be ${value}, but the version here is ${currentVersion}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Cannot find ${connectorKit} in connector's dependency`);
|
||||
};
|
68
packages/core/src/connectors/utilities/loader.ts
Normal file
68
packages/core/src/connectors/utilities/loader.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import path from 'path';
|
||||
|
||||
import type { AllConnector, CreateConnector } from '@logto/connector-kit';
|
||||
import connectorKitMeta from '@logto/connector-kit/package.json' assert { type: 'json' };
|
||||
import { satisfies } from 'semver';
|
||||
|
||||
const connectorKit = '@logto/connector-kit';
|
||||
const { version: currentVersion } = connectorKitMeta;
|
||||
|
||||
const isKeyInObject = <Key extends string>(
|
||||
object: unknown,
|
||||
key: Key
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
): object is object & Record<Key, unknown> =>
|
||||
object !== null && typeof object === 'object' && key in object;
|
||||
|
||||
const checkConnectorKitVersion = (dependencies: unknown) => {
|
||||
if (isKeyInObject(dependencies, connectorKit)) {
|
||||
const value = dependencies[connectorKit];
|
||||
|
||||
if (typeof value === 'string') {
|
||||
if (satisfies(currentVersion, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Connector requires ${connectorKit} to be ${value}, but the version here is ${currentVersion}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Cannot find ${connectorKit} in connector's dependency`);
|
||||
};
|
||||
|
||||
export const loadConnector = async (
|
||||
connectorPath: string
|
||||
): Promise<CreateConnector<AllConnector>> => {
|
||||
const {
|
||||
default: { dependencies },
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
} = (await import(path.join(connectorPath, 'package.json'), {
|
||||
assert: { type: 'json' },
|
||||
})) as { default: Record<string, unknown> };
|
||||
|
||||
checkConnectorKitVersion(dependencies);
|
||||
|
||||
const loaded: unknown = await import(path.join(connectorPath, 'lib/index.js'));
|
||||
|
||||
if (isKeyInObject(loaded, 'default')) {
|
||||
// CJS pattern
|
||||
if (isKeyInObject(loaded.default, 'default')) {
|
||||
if (typeof loaded.default.default === 'function') {
|
||||
console.log(`[warn] Load connector ${connectorPath} in CJS mode`);
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return loaded.default.default as CreateConnector<AllConnector>;
|
||||
}
|
||||
// ESM pattern
|
||||
} else if (typeof loaded.default === 'function') {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return loaded.default as CreateConnector<AllConnector>;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Cannot load connector from ${connectorPath}, the connector package may be broken.`
|
||||
);
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
import { noop } from '@silverhand/essentials';
|
||||
import Koa from 'koa';
|
||||
|
||||
import { loadConnectorFactories } from './connectors/index.js';
|
||||
import { configDotEnv } from './env-set/dot-env.js';
|
||||
import envSet from './env-set/index.js';
|
||||
import initI18n from './i18n/init.js';
|
||||
|
@ -12,6 +13,7 @@ try {
|
|||
proxy: envSet.values.trustProxyHeader,
|
||||
});
|
||||
await initI18n();
|
||||
await loadConnectorFactories();
|
||||
|
||||
// Import last until init completed
|
||||
const { default: initApp } = await import('./app/init.js');
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
},
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"main": "./lib/index.cjs",
|
||||
"main": "./lib/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/index.js",
|
||||
"require": "./lib/index.cjs"
|
||||
"import": "./lib/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
|
@ -25,7 +25,7 @@
|
|||
"scripts": {
|
||||
"precommit": "lint-staged",
|
||||
"dev": "tsc --watch --preserveWatchOutput --incremental",
|
||||
"build": "rm -rf lib/ && rollup -c && tsc",
|
||||
"build": "rm -rf lib/ && tsc",
|
||||
"build:test": "pnpm build",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"lint:report": "pnpm lint --format json --output-file report.json",
|
||||
|
@ -40,14 +40,12 @@
|
|||
"zod": "^3.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@silverhand/eslint-config": "1.3.0",
|
||||
"@silverhand/ts-config": "1.2.1",
|
||||
"@types/node": "^16.3.1",
|
||||
"eslint": "^8.21.0",
|
||||
"lint-staged": "^13.0.0",
|
||||
"prettier": "^2.8.1",
|
||||
"rollup": "^3.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import typescript from '@rollup/plugin-typescript';
|
||||
|
||||
/**
|
||||
* @type {import('rollup').RollupOptions}
|
||||
*/
|
||||
const configs = [
|
||||
{
|
||||
input: ['src/index.ts'],
|
||||
output: [
|
||||
{
|
||||
dir: 'lib',
|
||||
format: 'cjs',
|
||||
preserveModules: true,
|
||||
entryFileNames: '[name].cjs',
|
||||
},
|
||||
],
|
||||
plugins: [typescript()],
|
||||
},
|
||||
];
|
||||
|
||||
export default configs;
|
|
@ -9,11 +9,11 @@
|
|||
},
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"main": "./lib/index.cjs",
|
||||
"main": "./lib/index.js",
|
||||
"exports": {
|
||||
"default": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/index.js",
|
||||
"require": "./lib/index.cjs"
|
||||
"import": "./lib/index.js"
|
||||
},
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
|
@ -24,7 +24,7 @@
|
|||
"scripts": {
|
||||
"precommit": "lint-staged",
|
||||
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
|
||||
"build": "rm -rf lib/ && rollup -c && tsc -p tsconfig.build.json",
|
||||
"build": "rm -rf lib/ && tsc -p tsconfig.build.json",
|
||||
"build:test": "pnpm build -p tsconfig.test.json --sourcemap",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"lint:report": "pnpm lint --format json --output-file report.json",
|
||||
|
@ -48,7 +48,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@jest/types": "^29.0.3",
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@silverhand/eslint-config": "1.3.0",
|
||||
"@silverhand/eslint-config-react": "1.3.0",
|
||||
"@silverhand/essentials": "2.1.0",
|
||||
|
@ -63,7 +62,6 @@
|
|||
"lint-staged": "^13.0.0",
|
||||
"postcss": "^8.4.6",
|
||||
"prettier": "^2.8.1",
|
||||
"rollup": "^3.6.0",
|
||||
"stylelint": "^14.9.1",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.4"
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import typescript from '@rollup/plugin-typescript';
|
||||
|
||||
/**
|
||||
* @type {import('rollup').RollupOptions}
|
||||
*/
|
||||
const configs = [
|
||||
{
|
||||
input: ['src/index.ts'],
|
||||
output: [
|
||||
{
|
||||
dir: 'lib',
|
||||
format: 'cjs',
|
||||
preserveModules: true,
|
||||
entryFileNames: '[name].cjs',
|
||||
},
|
||||
],
|
||||
plugins: [typescript({ tsconfig: 'tsconfig.build.json' })],
|
||||
},
|
||||
];
|
||||
|
||||
export default configs;
|
|
@ -9,11 +9,11 @@
|
|||
},
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"main": "./lib/index.cjs",
|
||||
"main": "./lib/index.js",
|
||||
"exports": {
|
||||
"default": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/index.js",
|
||||
"require": "./lib/index.cjs"
|
||||
"import": "./lib/index.js"
|
||||
},
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
|
@ -21,7 +21,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"precommit": "lint-staged",
|
||||
"build": "rm -rf lib/ && rollup -c && tsc -p tsconfig.build.json",
|
||||
"build": "rm -rf lib/ && tsc -p tsconfig.build.json",
|
||||
"build:test": "pnpm build -p tsconfig.test.json --sourcemap",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"lint:report": "pnpm lint --format json --output-file report.json",
|
||||
|
@ -39,7 +39,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@jest/types": "^29.0.3",
|
||||
"@rollup/plugin-typescript": "^10.0.1",
|
||||
"@silverhand/eslint-config": "1.3.0",
|
||||
"@silverhand/ts-config": "1.2.1",
|
||||
"@types/jest": "^29.0.3",
|
||||
|
@ -48,7 +47,6 @@
|
|||
"jest": "^29.0.3",
|
||||
"lint-staged": "^13.0.0",
|
||||
"prettier": "^2.8.1",
|
||||
"rollup": "^3.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import typescript from '@rollup/plugin-typescript';
|
||||
|
||||
/**
|
||||
* @type {import('rollup').RollupOptions}
|
||||
*/
|
||||
const configs = [
|
||||
{
|
||||
input: ['src/index.ts'],
|
||||
output: [
|
||||
{
|
||||
dir: 'lib',
|
||||
format: 'cjs',
|
||||
preserveModules: true,
|
||||
entryFileNames: '[name].cjs',
|
||||
},
|
||||
],
|
||||
plugins: [typescript({ tsconfig: 'tsconfig.build.json' })],
|
||||
},
|
||||
];
|
||||
|
||||
export default configs;
|
|
@ -652,7 +652,6 @@ importers:
|
|||
specifiers:
|
||||
'@logto/core-kit': workspace:*
|
||||
'@logto/language-kit': workspace:*
|
||||
'@rollup/plugin-typescript': ^10.0.1
|
||||
'@silverhand/eslint-config': 1.3.0
|
||||
'@silverhand/essentials': 2.1.0
|
||||
'@silverhand/ts-config': 1.2.1
|
||||
|
@ -660,7 +659,6 @@ importers:
|
|||
eslint: ^8.21.0
|
||||
lint-staged: ^13.0.0
|
||||
prettier: ^2.8.1
|
||||
rollup: ^3.6.0
|
||||
tslib: ^2.4.1
|
||||
typescript: ^4.9.4
|
||||
zod: ^3.20.2
|
||||
|
@ -671,14 +669,12 @@ importers:
|
|||
optionalDependencies:
|
||||
zod: 3.20.2
|
||||
devDependencies:
|
||||
'@rollup/plugin-typescript': 10.0.1_ksuudmkloucy44p3irodiuckje
|
||||
'@silverhand/eslint-config': 1.3.0_k3lfx77tsvurbevhk73p7ygch4
|
||||
'@silverhand/ts-config': 1.2.1_typescript@4.9.4
|
||||
'@types/node': 16.11.12
|
||||
eslint: 8.21.0
|
||||
lint-staged: 13.0.0
|
||||
prettier: 2.8.1
|
||||
rollup: 3.7.4
|
||||
tslib: 2.4.1
|
||||
typescript: 4.9.4
|
||||
|
||||
|
@ -686,7 +682,6 @@ importers:
|
|||
specifiers:
|
||||
'@jest/types': ^29.0.3
|
||||
'@logto/language-kit': workspace:*
|
||||
'@rollup/plugin-typescript': ^10.0.1
|
||||
'@silverhand/eslint-config': 1.3.0
|
||||
'@silverhand/eslint-config-react': 1.3.0
|
||||
'@silverhand/essentials': 2.1.0
|
||||
|
@ -703,7 +698,6 @@ importers:
|
|||
nanoid: ^4.0.0
|
||||
postcss: ^8.4.6
|
||||
prettier: ^2.8.1
|
||||
rollup: ^3.6.0
|
||||
stylelint: ^14.9.1
|
||||
tslib: ^2.4.1
|
||||
typescript: ^4.9.4
|
||||
|
@ -716,7 +710,6 @@ importers:
|
|||
zod: 3.20.2
|
||||
devDependencies:
|
||||
'@jest/types': 29.3.1
|
||||
'@rollup/plugin-typescript': 10.0.1_ksuudmkloucy44p3irodiuckje
|
||||
'@silverhand/eslint-config': 1.3.0_k3lfx77tsvurbevhk73p7ygch4
|
||||
'@silverhand/eslint-config-react': 1.3.0_5rwnaekeqjwkki32tn67stomfe
|
||||
'@silverhand/essentials': 2.1.0
|
||||
|
@ -731,7 +724,6 @@ importers:
|
|||
lint-staged: 13.0.0
|
||||
postcss: 8.4.18
|
||||
prettier: 2.8.1
|
||||
rollup: 3.7.4
|
||||
stylelint: 14.9.1
|
||||
tslib: 2.4.1
|
||||
typescript: 4.9.4
|
||||
|
@ -739,7 +731,6 @@ importers:
|
|||
packages/toolkit/language-kit:
|
||||
specifiers:
|
||||
'@jest/types': ^29.0.3
|
||||
'@rollup/plugin-typescript': ^10.0.1
|
||||
'@silverhand/eslint-config': 1.3.0
|
||||
'@silverhand/ts-config': 1.2.1
|
||||
'@types/jest': ^29.0.3
|
||||
|
@ -748,7 +739,6 @@ importers:
|
|||
jest: ^29.0.3
|
||||
lint-staged: ^13.0.0
|
||||
prettier: ^2.8.1
|
||||
rollup: ^3.6.0
|
||||
tslib: ^2.4.1
|
||||
typescript: ^4.9.4
|
||||
zod: ^3.20.2
|
||||
|
@ -756,7 +746,6 @@ importers:
|
|||
zod: 3.20.2
|
||||
devDependencies:
|
||||
'@jest/types': 29.3.1
|
||||
'@rollup/plugin-typescript': 10.0.1_ksuudmkloucy44p3irodiuckje
|
||||
'@silverhand/eslint-config': 1.3.0_k3lfx77tsvurbevhk73p7ygch4
|
||||
'@silverhand/ts-config': 1.2.1_typescript@4.9.4
|
||||
'@types/jest': 29.1.2
|
||||
|
@ -765,7 +754,6 @@ importers:
|
|||
jest: 29.3.1_@types+node@16.11.12
|
||||
lint-staged: 13.0.0
|
||||
prettier: 2.8.1
|
||||
rollup: 3.7.4
|
||||
tslib: 2.4.1
|
||||
typescript: 4.9.4
|
||||
|
||||
|
@ -3331,41 +3319,6 @@ packages:
|
|||
resolution: {integrity: sha512-Yykovind6xzqAqd0t5umrdAGPlGLTE80cy80UkEnbt8Zv5zEYTFzJSNPQ81TY8BSpRreubu1oE54iHBv2UVnTQ==}
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-typescript/10.0.1_ksuudmkloucy44p3irodiuckje:
|
||||
resolution: {integrity: sha512-wBykxRLlX7EzL8BmUqMqk5zpx2onnmRMSw/l9M1sVfkJvdwfxogZQVNUM9gVMJbjRLDR5H6U0OMOrlDGmIV45A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.14.0||^3.0.0
|
||||
tslib: '*'
|
||||
typescript: '>=3.7.0'
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
tslib:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.0.2_rollup@3.7.4
|
||||
resolve: 1.22.1
|
||||
rollup: 3.7.4
|
||||
tslib: 2.4.1
|
||||
typescript: 4.9.4
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils/5.0.2_rollup@3.7.4:
|
||||
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/estree': 1.0.0
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 2.3.1
|
||||
rollup: 3.7.4
|
||||
dev: true
|
||||
|
||||
/@sideway/address/4.1.4:
|
||||
resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
|
||||
dependencies:
|
||||
|
@ -3915,10 +3868,6 @@ packages:
|
|||
'@types/ms': 0.7.31
|
||||
dev: true
|
||||
|
||||
/@types/estree/1.0.0:
|
||||
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
|
||||
dev: true
|
||||
|
||||
/@types/etag/1.8.1:
|
||||
resolution: {integrity: sha512-bsKkeSqN7HYyYntFRAmzcwx/dKW4Wa+KVMTInANlI72PWLQmOpZu96j0OqHZGArW4VQwCmJPteQlXaUDeOB0WQ==}
|
||||
dependencies:
|
||||
|
@ -6853,10 +6802,6 @@ packages:
|
|||
engines: {node: '>=4.0'}
|
||||
dev: true
|
||||
|
||||
/estree-walker/2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
dev: true
|
||||
|
||||
/esutils/2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -13122,14 +13067,6 @@ packages:
|
|||
globalthis: 1.0.2
|
||||
semver-compare: 1.0.0
|
||||
|
||||
/rollup/3.7.4:
|
||||
resolution: {integrity: sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/run-async/2.4.1:
|
||||
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
|
||||
engines: {node: '>=0.12.0'}
|
||||
|
|
Loading…
Reference in a new issue