@logto/cli 1.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +373 -0
  2. package/bin/logto +2 -0
  3. package/lib/commands/connector/add.d.ts +9 -0
  4. package/lib/commands/connector/add.js +36 -0
  5. package/lib/commands/connector/index.d.ts +3 -0
  6. package/lib/commands/connector/index.js +25 -0
  7. package/lib/commands/connector/list.d.ts +7 -0
  8. package/lib/commands/connector/list.js +28 -0
  9. package/lib/commands/connector/remove.d.ts +8 -0
  10. package/lib/commands/connector/remove.js +47 -0
  11. package/lib/commands/connector/utils.d.ts +24 -0
  12. package/lib/commands/connector/utils.js +165 -0
  13. package/lib/commands/database/alteration/index.d.ts +11 -0
  14. package/lib/commands/database/alteration/index.js +142 -0
  15. package/lib/commands/database/alteration/index.test.d.ts +1 -0
  16. package/lib/commands/database/alteration/index.test.js +87 -0
  17. package/lib/commands/database/alteration/type.d.ts +4 -0
  18. package/lib/commands/database/alteration/type.js +2 -0
  19. package/lib/commands/database/alteration/version.d.ts +2 -0
  20. package/lib/commands/database/alteration/version.js +69 -0
  21. package/lib/commands/database/config.d.ts +3 -0
  22. package/lib/commands/database/config.js +82 -0
  23. package/lib/commands/database/index.d.ts +3 -0
  24. package/lib/commands/database/index.js +16 -0
  25. package/lib/commands/database/seed/index.d.ts +10 -0
  26. package/lib/commands/database/seed/index.js +138 -0
  27. package/lib/commands/database/seed/oidc-config.d.ts +12 -0
  28. package/lib/commands/database/seed/oidc-config.js +77 -0
  29. package/lib/commands/install/index.d.ts +14 -0
  30. package/lib/commands/install/index.js +71 -0
  31. package/lib/commands/install/utils.d.ts +11 -0
  32. package/lib/commands/install/utils.js +176 -0
  33. package/lib/constants.d.ts +1 -0
  34. package/lib/constants.js +4 -0
  35. package/lib/database.d.ts +12 -0
  36. package/lib/database.js +71 -0
  37. package/lib/index.d.ts +1 -0
  38. package/lib/index.js +56 -0
  39. package/lib/package-json.d.ts +87 -0
  40. package/lib/package-json.js +95 -0
  41. package/lib/queries/logto-config.d.ts +8 -0
  42. package/lib/queries/logto-config.js +49 -0
  43. package/lib/queries/logto-config.test.d.ts +1 -0
  44. package/lib/queries/logto-config.test.js +81 -0
  45. package/lib/test-utilities.d.ts +7 -0
  46. package/lib/test-utilities.js +17 -0
  47. package/lib/utilities.d.ts +35 -0
  48. package/lib/utilities.js +136 -0
  49. package/package.json +92 -0
@@ -0,0 +1,87 @@
1
+ export declare const packageJson: {
2
+ name: string;
3
+ version: string;
4
+ description: string;
5
+ author: string;
6
+ homepage: string;
7
+ license: string;
8
+ publishConfig: {
9
+ access: string;
10
+ };
11
+ main: string;
12
+ bin: {
13
+ logto: string;
14
+ };
15
+ files: string[];
16
+ repository: {
17
+ type: string;
18
+ url: string;
19
+ };
20
+ scripts: {
21
+ precommit: string;
22
+ "prepare:package-json": string;
23
+ build: string;
24
+ dev: string;
25
+ start: string;
26
+ "start:dev": string;
27
+ lint: string;
28
+ "lint:report": string;
29
+ test: string;
30
+ "test:ci": string;
31
+ prepack: string;
32
+ };
33
+ engines: {
34
+ node: string;
35
+ };
36
+ bugs: {
37
+ url: string;
38
+ };
39
+ dependencies: {
40
+ "@logto/schemas": string;
41
+ "@logto/shared": string;
42
+ "@silverhand/essentials": string;
43
+ chalk: string;
44
+ decamelize: string;
45
+ dotenv: string;
46
+ "fs-extra": string;
47
+ got: string;
48
+ hpagent: string;
49
+ inquirer: string;
50
+ nanoid: string;
51
+ ora: string;
52
+ "p-retry": string;
53
+ roarr: string;
54
+ semver: string;
55
+ slonik: string;
56
+ "slonik-interceptor-preset": string;
57
+ "slonik-sql-tag-raw": string;
58
+ tar: string;
59
+ yargs: string;
60
+ zod: string;
61
+ };
62
+ devDependencies: {
63
+ "@silverhand/eslint-config": string;
64
+ "@silverhand/jest-config": string;
65
+ "@silverhand/ts-config": string;
66
+ "@types/fs-extra": string;
67
+ "@types/inquirer": string;
68
+ "@types/jest": string;
69
+ "@types/node": string;
70
+ "@types/semver": string;
71
+ "@types/tar": string;
72
+ "@types/yargs": string;
73
+ eslint: string;
74
+ jest: string;
75
+ "lint-staged": string;
76
+ prettier: string;
77
+ rimraf: string;
78
+ "ts-node": string;
79
+ typescript: string;
80
+ };
81
+ eslintConfig: {
82
+ extends: string;
83
+ ignorePatterns: string[];
84
+ };
85
+ prettier: string;
86
+ gitHead: string;
87
+ };
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.packageJson = void 0;
4
+ exports.packageJson = {
5
+ "name": "@logto/cli",
6
+ "version": "1.0.0-beta.11",
7
+ "description": "Logto CLI.",
8
+ "author": "Silverhand Inc. <contact@silverhand.io>",
9
+ "homepage": "https://github.com/logto-io/logto#readme",
10
+ "license": "MPL-2.0",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "main": "lib/index.js",
15
+ "bin": {
16
+ "logto": "bin/logto"
17
+ },
18
+ "files": [
19
+ "bin",
20
+ "lib"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/logto-io/logto.git"
25
+ },
26
+ "scripts": {
27
+ "precommit": "lint-staged",
28
+ "prepare:package-json": "node -p \"'export const packageJson = ' + JSON.stringify(require('./package.json'), undefined, 2) + ';'\" > src/package-json.ts",
29
+ "build": "rimraf lib && pnpm prepare:package-json && tsc -p tsconfig.build.json",
30
+ "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
31
+ "start": "node .",
32
+ "start:dev": "ts-node --files src/index.ts",
33
+ "lint": "eslint --ext .ts src",
34
+ "lint:report": "pnpm lint --format json --output-file report.json",
35
+ "test": "jest",
36
+ "test:ci": "jest",
37
+ "prepack": "pnpm build"
38
+ },
39
+ "engines": {
40
+ "node": "^16.0.0"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/logto-io/logto/issues"
44
+ },
45
+ "dependencies": {
46
+ "@logto/schemas": "^1.0.0-beta.11",
47
+ "@logto/shared": "^1.0.0-beta.11",
48
+ "@silverhand/essentials": "^1.3.0",
49
+ "chalk": "^4.1.2",
50
+ "decamelize": "^5.0.0",
51
+ "dotenv": "^16.0.0",
52
+ "fs-extra": "^10.1.0",
53
+ "got": "^11.8.2",
54
+ "hpagent": "^1.0.0",
55
+ "inquirer": "^8.2.2",
56
+ "nanoid": "^3.3.4",
57
+ "ora": "^5.0.0",
58
+ "p-retry": "^4.6.1",
59
+ "roarr": "^7.11.0",
60
+ "semver": "^7.3.7",
61
+ "slonik": "^30.0.0",
62
+ "slonik-interceptor-preset": "^1.2.10",
63
+ "slonik-sql-tag-raw": "^1.1.4",
64
+ "tar": "^6.1.11",
65
+ "yargs": "^17.6.0",
66
+ "zod": "^3.18.0"
67
+ },
68
+ "devDependencies": {
69
+ "@silverhand/eslint-config": "1.2.0",
70
+ "@silverhand/jest-config": "1.2.2",
71
+ "@silverhand/ts-config": "1.2.1",
72
+ "@types/fs-extra": "^9.0.13",
73
+ "@types/inquirer": "^8.2.1",
74
+ "@types/jest": "^29.1.2",
75
+ "@types/node": "^16.0.0",
76
+ "@types/semver": "^7.3.12",
77
+ "@types/tar": "^6.1.2",
78
+ "@types/yargs": "^17.0.13",
79
+ "eslint": "^8.21.0",
80
+ "jest": "^29.1.2",
81
+ "lint-staged": "^13.0.0",
82
+ "prettier": "^2.7.1",
83
+ "rimraf": "^3.0.2",
84
+ "ts-node": "^10.9.1",
85
+ "typescript": "^4.7.4"
86
+ },
87
+ "eslintConfig": {
88
+ "extends": "@silverhand",
89
+ "ignorePatterns": [
90
+ "src/package-json.ts"
91
+ ]
92
+ },
93
+ "prettier": "@silverhand/eslint-config/.prettierrc",
94
+ "gitHead": "33c10ce21600e048a448d8a598cf51b589854b15"
95
+ };
@@ -0,0 +1,8 @@
1
+ import { LogtoConfig, logtoConfigGuards, LogtoConfigKey } from '@logto/schemas';
2
+ import { DatabasePool, DatabaseTransactionConnection } from 'slonik';
3
+ import { z } from 'zod';
4
+ export declare const doesConfigsTableExist: (pool: DatabasePool) => Promise<boolean>;
5
+ export declare const getRowsByKeys: (pool: DatabasePool | DatabaseTransactionConnection, keys: LogtoConfigKey[]) => Promise<import("slonik").QueryResult<LogtoConfig>>;
6
+ export declare const updateValueByKey: <T extends LogtoConfigKey>(pool: DatabasePool | DatabaseTransactionConnection, key: T, value: z.TypeOf<import("@logto/schemas").LogtoConfigGuard[T]>) => Promise<import("slonik").QueryResult<import("slonik").QueryResultRow>>;
7
+ export declare const getCurrentDatabaseAlterationTimestamp: (pool: DatabasePool) => Promise<number>;
8
+ export declare const updateDatabaseTimestamp: (connection: DatabaseTransactionConnection, timestamp: number) => Promise<import("slonik").QueryResult<import("slonik").QueryResultRow>>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateDatabaseTimestamp = exports.getCurrentDatabaseAlterationTimestamp = exports.updateValueByKey = exports.getRowsByKeys = exports.doesConfigsTableExist = void 0;
4
+ const schemas_1 = require("@logto/schemas");
5
+ const shared_1 = require("@logto/shared");
6
+ const slonik_1 = require("slonik");
7
+ const zod_1 = require("zod");
8
+ const { table, fields } = (0, shared_1.convertToIdentifiers)(schemas_1.LogtoConfigs);
9
+ const doesConfigsTableExist = async (pool) => {
10
+ const { rows } = await pool.query((0, slonik_1.sql) `select to_regclass(${schemas_1.LogtoConfigs.table}) as regclass`);
11
+ return Boolean(rows[0]?.regclass);
12
+ };
13
+ exports.doesConfigsTableExist = doesConfigsTableExist;
14
+ const getRowsByKeys = async (pool, keys) => pool.query((0, slonik_1.sql) `
15
+ select ${slonik_1.sql.join([fields.key, fields.value], (0, slonik_1.sql) `,`)} from ${table}
16
+ where ${fields.key} in (${slonik_1.sql.join(keys, (0, slonik_1.sql) `,`)})
17
+ `);
18
+ exports.getRowsByKeys = getRowsByKeys;
19
+ const updateValueByKey = async (pool, key, value) => pool.query((0, slonik_1.sql) `
20
+ insert into ${table} (${fields.key}, ${fields.value})
21
+ values (${key}, ${slonik_1.sql.jsonb(value)})
22
+ on conflict (${fields.key}) do update set ${fields.value}=excluded.${fields.value}
23
+ `);
24
+ exports.updateValueByKey = updateValueByKey;
25
+ const getCurrentDatabaseAlterationTimestamp = async (pool) => {
26
+ try {
27
+ const result = await pool.maybeOne((0, slonik_1.sql) `select * from ${table} where ${fields.key}=${schemas_1.AlterationStateKey.AlterationState}`);
28
+ const parsed = schemas_1.logtoConfigGuards[schemas_1.AlterationStateKey.AlterationState].safeParse(result?.value);
29
+ return (parsed.success && parsed.data.timestamp) || 0;
30
+ }
31
+ catch (error) {
32
+ const result = zod_1.z.object({ code: zod_1.z.string() }).safeParse(error);
33
+ // Relation does not exist, treat as 0
34
+ // https://www.postgresql.org/docs/14/errcodes-appendix.html
35
+ if (result.success && result.data.code === '42P01') {
36
+ return 0;
37
+ }
38
+ throw error;
39
+ }
40
+ };
41
+ exports.getCurrentDatabaseAlterationTimestamp = getCurrentDatabaseAlterationTimestamp;
42
+ const updateDatabaseTimestamp = async (connection, timestamp) => {
43
+ const value = {
44
+ timestamp,
45
+ updatedAt: new Date().toISOString(),
46
+ };
47
+ return (0, exports.updateValueByKey)(connection, schemas_1.AlterationStateKey.AlterationState, value);
48
+ };
49
+ exports.updateDatabaseTimestamp = updateDatabaseTimestamp;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schemas_1 = require("@logto/schemas");
4
+ const shared_1 = require("@logto/shared");
5
+ const slonik_1 = require("slonik");
6
+ const test_utilities_1 = require("../test-utilities");
7
+ const logto_config_1 = require("./logto-config");
8
+ const mockQuery = jest.fn();
9
+ const pool = (0, slonik_1.createMockPool)({
10
+ query: async (sql, values) => {
11
+ return mockQuery(sql, values);
12
+ },
13
+ });
14
+ const { table, fields } = (0, shared_1.convertToIdentifiers)(schemas_1.LogtoConfigs);
15
+ const timestamp = 1663923776;
16
+ describe('getCurrentDatabaseAlterationTimestamp()', () => {
17
+ it('returns 0 if query failed (table not found)', async () => {
18
+ mockQuery.mockRejectedValueOnce({ code: '42P01' });
19
+ await expect((0, logto_config_1.getCurrentDatabaseAlterationTimestamp)(pool)).resolves.toBe(0);
20
+ });
21
+ it('returns 0 if the row is not found', async () => {
22
+ const expectSql = (0, slonik_1.sql) `
23
+ select * from ${table} where ${fields.key}=$1
24
+ `;
25
+ mockQuery.mockImplementationOnce(async (sql, values) => {
26
+ (0, test_utilities_1.expectSqlAssert)(sql, expectSql.sql);
27
+ expect(values).toEqual([schemas_1.AlterationStateKey.AlterationState]);
28
+ return (0, slonik_1.createMockQueryResult)([]);
29
+ });
30
+ await expect((0, logto_config_1.getCurrentDatabaseAlterationTimestamp)(pool)).resolves.toBe(0);
31
+ });
32
+ it('returns 0 if the value is in bad format', async () => {
33
+ const expectSql = (0, slonik_1.sql) `
34
+ select * from ${table} where ${fields.key}=$1
35
+ `;
36
+ mockQuery.mockImplementationOnce(async (sql, values) => {
37
+ (0, test_utilities_1.expectSqlAssert)(sql, expectSql.sql);
38
+ expect(values).toEqual([schemas_1.AlterationStateKey.AlterationState]);
39
+ return (0, slonik_1.createMockQueryResult)([{ value: 'some_value' }]);
40
+ });
41
+ await expect((0, logto_config_1.getCurrentDatabaseAlterationTimestamp)(pool)).resolves.toBe(0);
42
+ });
43
+ it('returns the timestamp from database', async () => {
44
+ const expectSql = (0, slonik_1.sql) `
45
+ select * from ${table} where ${fields.key}=$1
46
+ `;
47
+ mockQuery.mockImplementationOnce(async (sql, values) => {
48
+ (0, test_utilities_1.expectSqlAssert)(sql, expectSql.sql);
49
+ expect(values).toEqual([schemas_1.AlterationStateKey.AlterationState]);
50
+ // @ts-expect-error createMockQueryResult doesn't support jsonb
51
+ return (0, slonik_1.createMockQueryResult)([{ value: { timestamp, updatedAt: 'now' } }]);
52
+ });
53
+ await expect((0, logto_config_1.getCurrentDatabaseAlterationTimestamp)(pool)).resolves.toEqual(timestamp);
54
+ });
55
+ });
56
+ describe('updateDatabaseTimestamp()', () => {
57
+ const expectSql = (0, slonik_1.sql) `
58
+ insert into ${table} (${fields.key}, ${fields.value})
59
+ values ($1, $2::jsonb)
60
+ on conflict (${fields.key}) do update set ${fields.value}=excluded.${fields.value}
61
+ `;
62
+ const updatedAt = '2022-09-21T06:32:46.583Z';
63
+ beforeAll(() => {
64
+ jest.useFakeTimers();
65
+ jest.setSystemTime(new Date(updatedAt));
66
+ });
67
+ afterAll(() => {
68
+ jest.useRealTimers();
69
+ });
70
+ it('sends upsert sql with timestamp and updatedAt', async () => {
71
+ mockQuery.mockImplementationOnce(async (sql, values) => {
72
+ (0, test_utilities_1.expectSqlAssert)(sql, expectSql.sql);
73
+ expect(values).toEqual([
74
+ schemas_1.AlterationStateKey.AlterationState,
75
+ JSON.stringify({ timestamp, updatedAt }),
76
+ ]);
77
+ return (0, slonik_1.createMockQueryResult)([]);
78
+ });
79
+ await (0, logto_config_1.updateDatabaseTimestamp)(pool, timestamp);
80
+ });
81
+ });
@@ -0,0 +1,7 @@
1
+ import { QueryResult, QueryResultRow } from 'slonik';
2
+ import { PrimitiveValueExpression } from 'slonik/dist/src/types.d';
3
+ export declare type QueryType = (sql: string, values: readonly PrimitiveValueExpression[]) => Promise<QueryResult<QueryResultRow>>;
4
+ /**
5
+ * Slonik Query Mock Utils
6
+ **/
7
+ export declare const expectSqlAssert: (sql: string, expectSql: string) => void;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ // Copied from core
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.expectSqlAssert = void 0;
5
+ /**
6
+ * Slonik Query Mock Utils
7
+ **/
8
+ const expectSqlAssert = (sql, expectSql) => {
9
+ expect(sql
10
+ .split('\n')
11
+ .map((row) => row.trim())
12
+ .filter(Boolean)).toEqual(expectSql
13
+ .split('\n')
14
+ .map((row) => row.trim())
15
+ .filter(Boolean));
16
+ };
17
+ exports.expectSqlAssert = expectSqlAssert;
@@ -0,0 +1,35 @@
1
+ import { Optional } from '@silverhand/essentials';
2
+ import ora from 'ora';
3
+ export declare const safeExecSync: (command: string) => string | undefined;
4
+ declare type Log = Readonly<{
5
+ info: typeof console.log;
6
+ succeed: typeof console.log;
7
+ warn: typeof console.log;
8
+ error: (...args: Parameters<typeof console.log>) => never;
9
+ }>;
10
+ export declare const log: Log;
11
+ export declare const downloadFile: (url: string, destination: string) => Promise<unknown>;
12
+ export declare const getPathInModule: (moduleName: string, relativePath?: string) => string;
13
+ export declare const oraPromise: <T>(promise: PromiseLike<T>, options?: ora.Options, exitOnError?: boolean) => Promise<T>;
14
+ export declare const isTty: () => boolean;
15
+ export declare enum ConfigKey {
16
+ DatabaseUrl = "DB_URL"
17
+ }
18
+ export declare const cliConfig: Map<ConfigKey, Optional<string>>;
19
+ export declare type GetCliConfigWithPrompt = {
20
+ key: ConfigKey;
21
+ readableKey: string;
22
+ comments?: string;
23
+ defaultValue?: string;
24
+ };
25
+ export declare const getCliConfigWithPrompt: ({ key, readableKey, comments, defaultValue, }: GetCliConfigWithPrompt) => Promise<Optional<string>>;
26
+ /**
27
+ * Returns the index of the last element in the array where predicate is true, and -1
28
+ * otherwise.
29
+ * @param array The source array to search in
30
+ * @param predicate find calls predicate once for each element of the array, in descending
31
+ * order, until it finds one where predicate returns true. If such an element is found,
32
+ * findLastIndex immediately returns that element index. Otherwise, findLastIndex returns -1.
33
+ */
34
+ export declare function findLastIndex<T>(array: readonly T[], predicate: (value: T, index: number, object: readonly T[]) => boolean): number;
35
+ export {};
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findLastIndex = exports.getCliConfigWithPrompt = exports.cliConfig = exports.ConfigKey = exports.isTty = exports.oraPromise = exports.getPathInModule = exports.downloadFile = exports.log = exports.safeExecSync = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = require("fs");
9
+ const path_1 = __importDefault(require("path"));
10
+ const essentials_1 = require("@silverhand/essentials");
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const got_1 = __importDefault(require("got"));
13
+ const hpagent_1 = require("hpagent");
14
+ const inquirer_1 = __importDefault(require("inquirer"));
15
+ const ora_1 = __importDefault(require("ora"));
16
+ const safeExecSync = (command) => {
17
+ try {
18
+ return (0, child_process_1.execSync)(command, { encoding: 'utf8', stdio: 'pipe' });
19
+ }
20
+ catch { }
21
+ };
22
+ exports.safeExecSync = safeExecSync;
23
+ exports.log = Object.freeze({
24
+ info: (...args) => {
25
+ console.log(chalk_1.default.blue('[info]'), ...args);
26
+ },
27
+ succeed: (...args) => {
28
+ exports.log.info(chalk_1.default.green('✔'), ...args);
29
+ },
30
+ warn: (...args) => {
31
+ console.warn(chalk_1.default.yellow('[warn]'), ...args);
32
+ },
33
+ error: (...args) => {
34
+ console.error(chalk_1.default.red('[error]'), ...args);
35
+ // eslint-disable-next-line unicorn/no-process-exit
36
+ process.exit(1);
37
+ },
38
+ });
39
+ const downloadFile = async (url, destination) => {
40
+ const { HTTPS_PROXY, HTTP_PROXY, https_proxy, http_proxy } = process.env;
41
+ const file = (0, fs_1.createWriteStream)(destination);
42
+ const proxy = HTTPS_PROXY ?? https_proxy ?? HTTP_PROXY ?? http_proxy;
43
+ const stream = got_1.default.stream(url, {
44
+ ...(proxy && { agent: { https: new hpagent_1.HttpsProxyAgent({ proxy }) } }),
45
+ });
46
+ const spinner = (0, ora_1.default)({
47
+ text: 'Connecting',
48
+ prefixText: chalk_1.default.blue('[info]'),
49
+ }).start();
50
+ stream.pipe(file);
51
+ return new Promise((resolve, reject) => {
52
+ stream.on('downloadProgress', ({ total, percent }) => {
53
+ if (!total) {
54
+ return;
55
+ }
56
+ // eslint-disable-next-line @silverhand/fp/no-mutation
57
+ spinner.text = `${(percent * 100).toFixed(1)}%`;
58
+ });
59
+ file.on('error', (error) => {
60
+ spinner.fail();
61
+ reject(error.message);
62
+ });
63
+ file.on('finish', () => {
64
+ file.close();
65
+ spinner.succeed();
66
+ resolve(file);
67
+ });
68
+ });
69
+ };
70
+ exports.downloadFile = downloadFile;
71
+ const getPathInModule = (moduleName, relativePath = '/') =>
72
+ // https://stackoverflow.com/a/49455609/12514940
73
+ path_1.default.join(
74
+ // Until we migrate to ESM
75
+ // eslint-disable-next-line unicorn/prefer-module
76
+ path_1.default.dirname(require.resolve(`${moduleName}/package.json`)), relativePath);
77
+ exports.getPathInModule = getPathInModule;
78
+ const oraPromise = async (promise, options, exitOnError = false) => {
79
+ const spinner = (0, ora_1.default)(options).start();
80
+ try {
81
+ const result = await promise;
82
+ spinner.succeed();
83
+ return result;
84
+ }
85
+ catch (error) {
86
+ spinner.fail();
87
+ if (exitOnError) {
88
+ exports.log.error(error);
89
+ }
90
+ throw error;
91
+ }
92
+ };
93
+ exports.oraPromise = oraPromise;
94
+ const isTty = () => process.stdin.isTTY;
95
+ exports.isTty = isTty;
96
+ var ConfigKey;
97
+ (function (ConfigKey) {
98
+ ConfigKey["DatabaseUrl"] = "DB_URL";
99
+ })(ConfigKey = exports.ConfigKey || (exports.ConfigKey = {}));
100
+ exports.cliConfig = new Map();
101
+ const getCliConfigWithPrompt = async ({ key, readableKey, comments, defaultValue, }) => {
102
+ if (exports.cliConfig.has(key) || !(0, exports.isTty)()) {
103
+ return exports.cliConfig.get(key);
104
+ }
105
+ const { input } = await inquirer_1.default.prompt({
106
+ type: 'input',
107
+ name: 'input',
108
+ message: `Enter your ${readableKey}${(0, essentials_1.conditionalString)(comments && ' ' + comments)}`,
109
+ default: defaultValue,
110
+ });
111
+ exports.cliConfig.set(key, input);
112
+ return input;
113
+ };
114
+ exports.getCliConfigWithPrompt = getCliConfigWithPrompt;
115
+ // https://stackoverflow.com/a/53187807/12514940
116
+ /**
117
+ * Returns the index of the last element in the array where predicate is true, and -1
118
+ * otherwise.
119
+ * @param array The source array to search in
120
+ * @param predicate find calls predicate once for each element of the array, in descending
121
+ * order, until it finds one where predicate returns true. If such an element is found,
122
+ * findLastIndex immediately returns that element index. Otherwise, findLastIndex returns -1.
123
+ */
124
+ function findLastIndex(array, predicate) {
125
+ // eslint-disable-next-line @silverhand/fp/no-let
126
+ let { length } = array;
127
+ // eslint-disable-next-line @silverhand/fp/no-mutation
128
+ while (length--) {
129
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
130
+ if (predicate(array[length], length, array)) {
131
+ return length;
132
+ }
133
+ }
134
+ return -1;
135
+ }
136
+ exports.findLastIndex = findLastIndex;
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@logto/cli",
3
+ "version": "1.0.0-beta.11",
4
+ "description": "Logto CLI.",
5
+ "author": "Silverhand Inc. <contact@silverhand.io>",
6
+ "homepage": "https://github.com/logto-io/logto#readme",
7
+ "license": "MPL-2.0",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "main": "lib/index.js",
12
+ "bin": {
13
+ "logto": "bin/logto"
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "lib"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/logto-io/logto.git"
22
+ },
23
+ "scripts": {
24
+ "precommit": "lint-staged",
25
+ "prepare:package-json": "node -p \"'export const packageJson = ' + JSON.stringify(require('./package.json'), undefined, 2) + ';'\" > src/package-json.ts",
26
+ "build": "rimraf lib && pnpm prepare:package-json && tsc -p tsconfig.build.json",
27
+ "dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
28
+ "start": "node .",
29
+ "start:dev": "ts-node --files src/index.ts",
30
+ "lint": "eslint --ext .ts src",
31
+ "lint:report": "pnpm lint --format json --output-file report.json",
32
+ "test": "jest",
33
+ "test:ci": "jest",
34
+ "prepack": "pnpm build"
35
+ },
36
+ "engines": {
37
+ "node": "^16.0.0"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/logto-io/logto/issues"
41
+ },
42
+ "dependencies": {
43
+ "@logto/schemas": "^1.0.0-beta.11",
44
+ "@logto/shared": "^1.0.0-beta.11",
45
+ "@silverhand/essentials": "^1.3.0",
46
+ "chalk": "^4.1.2",
47
+ "decamelize": "^5.0.0",
48
+ "dotenv": "^16.0.0",
49
+ "fs-extra": "^10.1.0",
50
+ "got": "^11.8.2",
51
+ "hpagent": "^1.0.0",
52
+ "inquirer": "^8.2.2",
53
+ "nanoid": "^3.3.4",
54
+ "ora": "^5.0.0",
55
+ "p-retry": "^4.6.1",
56
+ "roarr": "^7.11.0",
57
+ "semver": "^7.3.7",
58
+ "slonik": "^30.0.0",
59
+ "slonik-interceptor-preset": "^1.2.10",
60
+ "slonik-sql-tag-raw": "^1.1.4",
61
+ "tar": "^6.1.11",
62
+ "yargs": "^17.6.0",
63
+ "zod": "^3.18.0"
64
+ },
65
+ "devDependencies": {
66
+ "@silverhand/eslint-config": "1.2.0",
67
+ "@silverhand/jest-config": "1.2.2",
68
+ "@silverhand/ts-config": "1.2.1",
69
+ "@types/fs-extra": "^9.0.13",
70
+ "@types/inquirer": "^8.2.1",
71
+ "@types/jest": "^29.1.2",
72
+ "@types/node": "^16.0.0",
73
+ "@types/semver": "^7.3.12",
74
+ "@types/tar": "^6.1.2",
75
+ "@types/yargs": "^17.0.13",
76
+ "eslint": "^8.21.0",
77
+ "jest": "^29.1.2",
78
+ "lint-staged": "^13.0.0",
79
+ "prettier": "^2.7.1",
80
+ "rimraf": "^3.0.2",
81
+ "ts-node": "^10.9.1",
82
+ "typescript": "^4.7.4"
83
+ },
84
+ "eslintConfig": {
85
+ "extends": "@silverhand",
86
+ "ignorePatterns": [
87
+ "src/package-json.ts"
88
+ ]
89
+ },
90
+ "prettier": "@silverhand/eslint-config/.prettierrc",
91
+ "gitHead": "33c10ce21600e048a448d8a598cf51b589854b15"
92
+ }