0
Fork 0
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:
Gao Sun 2023-01-03 15:41:29 +08:00 committed by GitHub
parent e1d70bc9cf
commit db71cc11ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 189 deletions

View file

@ -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);

View file

@ -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`);
};

View 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.`
);
};

View file

@ -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');

View file

@ -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"
},

View file

@ -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;

View file

@ -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"

View file

@ -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;

View file

@ -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"
},

View file

@ -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;

View file

@ -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'}