@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.
- package/LICENSE +373 -0
- package/bin/logto +2 -0
- package/lib/commands/connector/add.d.ts +9 -0
- package/lib/commands/connector/add.js +36 -0
- package/lib/commands/connector/index.d.ts +3 -0
- package/lib/commands/connector/index.js +25 -0
- package/lib/commands/connector/list.d.ts +7 -0
- package/lib/commands/connector/list.js +28 -0
- package/lib/commands/connector/remove.d.ts +8 -0
- package/lib/commands/connector/remove.js +47 -0
- package/lib/commands/connector/utils.d.ts +24 -0
- package/lib/commands/connector/utils.js +165 -0
- package/lib/commands/database/alteration/index.d.ts +11 -0
- package/lib/commands/database/alteration/index.js +142 -0
- package/lib/commands/database/alteration/index.test.d.ts +1 -0
- package/lib/commands/database/alteration/index.test.js +87 -0
- package/lib/commands/database/alteration/type.d.ts +4 -0
- package/lib/commands/database/alteration/type.js +2 -0
- package/lib/commands/database/alteration/version.d.ts +2 -0
- package/lib/commands/database/alteration/version.js +69 -0
- package/lib/commands/database/config.d.ts +3 -0
- package/lib/commands/database/config.js +82 -0
- package/lib/commands/database/index.d.ts +3 -0
- package/lib/commands/database/index.js +16 -0
- package/lib/commands/database/seed/index.d.ts +10 -0
- package/lib/commands/database/seed/index.js +138 -0
- package/lib/commands/database/seed/oidc-config.d.ts +12 -0
- package/lib/commands/database/seed/oidc-config.js +77 -0
- package/lib/commands/install/index.d.ts +14 -0
- package/lib/commands/install/index.js +71 -0
- package/lib/commands/install/utils.d.ts +11 -0
- package/lib/commands/install/utils.js +176 -0
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +4 -0
- package/lib/database.d.ts +12 -0
- package/lib/database.js +71 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +56 -0
- package/lib/package-json.d.ts +87 -0
- package/lib/package-json.js +95 -0
- package/lib/queries/logto-config.d.ts +8 -0
- package/lib/queries/logto-config.js +49 -0
- package/lib/queries/logto-config.test.d.ts +1 -0
- package/lib/queries/logto-config.test.js +81 -0
- package/lib/test-utilities.d.ts +7 -0
- package/lib/test-utilities.js +17 -0
- package/lib/utilities.d.ts +35 -0
- package/lib/utilities.js +136 -0
- 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 {};
|
package/lib/utilities.js
ADDED
|
@@ -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
|
+
}
|