@logto/cli 1.0.0-beta.16 → 1.0.0-beta.18

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 (43) hide show
  1. package/bin/logto.js +2 -0
  2. package/lib/commands/connector/add.js +8 -10
  3. package/lib/commands/connector/index.js +9 -14
  4. package/lib/commands/connector/list.js +10 -16
  5. package/lib/commands/connector/remove.js +13 -18
  6. package/lib/commands/connector/utils.d.ts +1 -1
  7. package/lib/commands/connector/utils.js +100 -86
  8. package/lib/commands/database/alteration/index.d.ts +1 -2
  9. package/lib/commands/database/alteration/index.js +36 -98
  10. package/lib/commands/database/alteration/index.test.js +36 -57
  11. package/lib/commands/database/alteration/meta-url.d.ts +1 -0
  12. package/lib/commands/database/alteration/meta-url.js +4 -0
  13. package/lib/commands/database/alteration/type.d.ts +1 -1
  14. package/lib/commands/database/alteration/type.js +1 -2
  15. package/lib/commands/database/alteration/utils.d.ts +4 -0
  16. package/lib/commands/database/alteration/utils.js +39 -0
  17. package/lib/commands/database/alteration/version.d.ts +1 -1
  18. package/lib/commands/database/alteration/version.js +18 -25
  19. package/lib/commands/database/config.js +44 -49
  20. package/lib/commands/database/index.js +7 -12
  21. package/lib/commands/database/seed/index.d.ts +1 -1
  22. package/lib/commands/database/seed/index.js +59 -55
  23. package/lib/commands/database/seed/oidc-config.js +15 -18
  24. package/lib/commands/database/utilities.js +6 -11
  25. package/lib/commands/install/index.d.ts +1 -1
  26. package/lib/commands/install/index.js +14 -28
  27. package/lib/commands/install/utils.d.ts +0 -1
  28. package/lib/commands/install/utils.js +59 -106
  29. package/lib/constants.js +1 -4
  30. package/lib/database.js +33 -43
  31. package/lib/index.js +18 -23
  32. package/lib/meta-url.d.ts +1 -0
  33. package/lib/meta-url.js +4 -0
  34. package/lib/package-json.d.ts +7 -3
  35. package/lib/package-json.js +28 -27
  36. package/lib/queries/logto-config.js +18 -26
  37. package/lib/queries/logto-config.test.js +29 -30
  38. package/lib/test-utilities.d.ts +2 -2
  39. package/lib/test-utilities.js +1 -5
  40. package/lib/utilities.d.ts +5 -5
  41. package/lib/utilities.js +49 -64
  42. package/package.json +27 -23
  43. package/bin/logto +0 -2
@@ -1,102 +1,106 @@
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.seedByPool = void 0;
7
- const promises_1 = require("fs/promises");
8
- const path_1 = __importDefault(require("path"));
9
- const schemas_1 = require("@logto/schemas");
10
- const shared_1 = require("@logto/shared");
11
- const chalk_1 = __importDefault(require("chalk"));
12
- const slonik_1 = require("slonik");
13
- const slonik_sql_tag_raw_1 = require("slonik-sql-tag-raw");
14
- const zod_1 = require("zod");
15
- const database_1 = require("../../../database");
16
- const logto_config_1 = require("../../../queries/logto-config");
17
- const utilities_1 = require("../../../utilities");
18
- const alteration_1 = require("../alteration");
19
- const oidc_config_1 = require("./oidc-config");
1
+ import { readdir, readFile } from 'fs/promises';
2
+ import path from 'path';
3
+ import { generateStandardId } from '@logto/core-kit';
4
+ import { logtoConfigGuards, LogtoOidcConfigKey, managementResource, defaultSignInExperience, createDefaultSetting, createDemoAppApplication, defaultRole, } from '@logto/schemas';
5
+ import { Hooks } from '@logto/schemas/models';
6
+ import chalk from 'chalk';
7
+ import { sql } from 'slonik';
8
+ import { raw } from 'slonik-sql-tag-raw';
9
+ import { z } from 'zod';
10
+ import { createPoolAndDatabaseIfNeeded, insertInto } from '../../../database.js';
11
+ import { getRowsByKeys, doesConfigsTableExist, updateDatabaseTimestamp, updateValueByKey, } from '../../../queries/logto-config.js';
12
+ import { getPathInModule, log, oraPromise } from '../../../utilities.js';
13
+ import { getLatestAlterationTimestamp } from '../alteration/index.js';
14
+ import { getAlterationDirectory } from '../alteration/utils.js';
15
+ import { oidcConfigReaders } from './oidc-config.js';
20
16
  const createTables = async (connection) => {
21
- const tableDirectory = (0, utilities_1.getPathInModule)('@logto/schemas', 'tables');
22
- const directoryFiles = await (0, promises_1.readdir)(tableDirectory);
17
+ const tableDirectory = getPathInModule('@logto/schemas', 'tables');
18
+ const directoryFiles = await readdir(tableDirectory);
23
19
  const tableFiles = directoryFiles.filter((file) => file.endsWith('.sql'));
24
20
  const queries = await Promise.all(tableFiles.map(async (file) => [
25
21
  file,
26
- await (0, promises_1.readFile)(path_1.default.join(tableDirectory, file), 'utf8'),
22
+ await readFile(path.join(tableDirectory, file), 'utf8'),
27
23
  ]));
28
24
  // Await in loop is intended for better error handling
29
25
  for (const [, query] of queries) {
30
26
  // eslint-disable-next-line no-await-in-loop
31
- await connection.query((0, slonik_1.sql) `${(0, slonik_sql_tag_raw_1.raw)(query)}`);
27
+ await connection.query(sql `${raw(query)}`);
28
+ }
29
+ for (const table of [Hooks]) {
30
+ // eslint-disable-next-line no-await-in-loop
31
+ await connection.query(sql `${raw(table.raw)}`);
32
32
  }
33
33
  };
34
- const seedTables = async (connection) => {
35
- const { managementResource, defaultSignInExperience, createDefaultSetting, createDemoAppApplication, defaultRole, } = schemas_1.seeds;
34
+ const seedTables = async (connection, latestTimestamp) => {
36
35
  await Promise.all([
37
- connection.query((0, database_1.insertInto)(managementResource, 'resources')),
38
- connection.query((0, database_1.insertInto)(createDefaultSetting(), 'settings')),
39
- connection.query((0, database_1.insertInto)(defaultSignInExperience, 'sign_in_experiences')),
40
- connection.query((0, database_1.insertInto)(createDemoAppApplication((0, shared_1.buildApplicationSecret)()), 'applications')),
41
- connection.query((0, database_1.insertInto)(defaultRole, 'roles')),
42
- (0, logto_config_1.updateDatabaseTimestamp)(connection, await (0, alteration_1.getLatestAlterationTimestamp)()),
36
+ connection.query(insertInto(managementResource, 'resources')),
37
+ connection.query(insertInto(createDefaultSetting(), 'settings')),
38
+ connection.query(insertInto(defaultSignInExperience, 'sign_in_experiences')),
39
+ connection.query(insertInto(createDemoAppApplication(generateStandardId()), 'applications')),
40
+ connection.query(insertInto(defaultRole, 'roles')),
41
+ updateDatabaseTimestamp(connection, latestTimestamp),
43
42
  ]);
44
43
  };
45
44
  const seedOidcConfigs = async (pool) => {
46
- const configGuard = zod_1.z.object({
47
- key: zod_1.z.nativeEnum(schemas_1.LogtoOidcConfigKey),
48
- value: zod_1.z.unknown(),
45
+ const configGuard = z.object({
46
+ key: z.nativeEnum(LogtoOidcConfigKey),
47
+ value: z.unknown(),
49
48
  });
50
- const { rows } = await (0, logto_config_1.getRowsByKeys)(pool, Object.values(schemas_1.LogtoOidcConfigKey));
49
+ const { rows } = await getRowsByKeys(pool, Object.values(LogtoOidcConfigKey));
51
50
  // Filter out valid keys that hold a valid value
52
51
  const result = await Promise.all(rows.map(async (row) => {
53
52
  try {
54
53
  const { key, value } = await configGuard.parseAsync(row);
55
- await schemas_1.logtoConfigGuards[key].parseAsync(value);
54
+ await logtoConfigGuards[key].parseAsync(value);
56
55
  return key;
57
56
  }
58
57
  catch { }
59
58
  }));
60
59
  const existingKeys = new Set(result.filter(Boolean));
61
- const validOptions = Object.values(schemas_1.LogtoOidcConfigKey).filter((key) => {
60
+ const validOptions = Object.values(LogtoOidcConfigKey).filter((key) => {
62
61
  const included = existingKeys.has(key);
63
62
  if (included) {
64
- utilities_1.log.info(`Key ${chalk_1.default.green(key)} exists, skipping`);
63
+ log.info(`Key ${chalk.green(key)} exists, skipping`);
65
64
  }
66
65
  return !included;
67
66
  });
68
67
  // The awaits in loop is intended since we'd like to log info in sequence
69
68
  /* eslint-disable no-await-in-loop */
70
69
  for (const key of validOptions) {
71
- const { value, fromEnv } = await oidc_config_1.oidcConfigReaders[key]();
70
+ const { value, fromEnv } = await oidcConfigReaders[key]();
72
71
  if (fromEnv) {
73
- utilities_1.log.info(`Read config ${chalk_1.default.green(key)} from env`);
72
+ log.info(`Read config ${chalk.green(key)} from env`);
74
73
  }
75
74
  else {
76
- utilities_1.log.info(`Generated config ${chalk_1.default.green(key)}`);
75
+ log.info(`Generated config ${chalk.green(key)}`);
77
76
  }
78
- await (0, logto_config_1.updateValueByKey)(pool, key, value);
77
+ await updateValueByKey(pool, key, value);
79
78
  }
80
79
  /* eslint-enable no-await-in-loop */
81
- utilities_1.log.succeed('Seed OIDC config');
80
+ log.succeed('Seed OIDC config');
82
81
  };
83
82
  const seedChoices = Object.freeze(['all', 'oidc']);
84
- const seedByPool = async (pool, type) => {
83
+ export const seedByPool = async (pool, type) => {
85
84
  await pool.transaction(async (connection) => {
86
85
  if (type !== 'oidc') {
87
- await (0, utilities_1.oraPromise)(createTables(connection), {
86
+ // Check alteration scripts available in order to insert correct timestamp
87
+ const latestTimestamp = await getLatestAlterationTimestamp();
88
+ if (latestTimestamp < 1) {
89
+ throw new Error(`No alteration script found when seeding the database.\n` +
90
+ `Please check \`${getAlterationDirectory()}\` to see if there are alteration scripts available.\n`);
91
+ }
92
+ await oraPromise(createTables(connection), {
88
93
  text: 'Create tables',
89
- prefixText: chalk_1.default.blue('[info]'),
94
+ prefixText: chalk.blue('[info]'),
90
95
  });
91
- await (0, utilities_1.oraPromise)(seedTables(connection), {
96
+ await oraPromise(seedTables(connection, latestTimestamp), {
92
97
  text: 'Seed data',
93
- prefixText: chalk_1.default.blue('[info]'),
98
+ prefixText: chalk.blue('[info]'),
94
99
  });
95
100
  }
96
101
  await seedOidcConfigs(connection);
97
102
  });
98
103
  };
99
- exports.seedByPool = seedByPool;
100
104
  const seed = {
101
105
  command: 'seed [type]',
102
106
  describe: 'Create database then seed tables and data',
@@ -113,9 +117,9 @@ const seed = {
113
117
  default: 'all',
114
118
  }),
115
119
  handler: async ({ type, swe }) => {
116
- const pool = await (0, database_1.createPoolAndDatabaseIfNeeded)();
117
- if (swe && (await (0, logto_config_1.doesConfigsTableExist)(pool))) {
118
- utilities_1.log.info('Seeding skipped');
120
+ const pool = await createPoolAndDatabaseIfNeeded();
121
+ if (swe && (await doesConfigsTableExist(pool))) {
122
+ log.info('Seeding skipped');
119
123
  await pool.end();
120
124
  return;
121
125
  }
@@ -123,16 +127,16 @@ const seed = {
123
127
  // Cannot avoid `as` since the official type definition of `yargs` doesn't work.
124
128
  // The value of `type` can be ensured, so it's safe to use `as` here.
125
129
  // eslint-disable-next-line no-restricted-syntax
126
- await (0, exports.seedByPool)(pool, type);
130
+ await seedByPool(pool, type);
127
131
  }
128
132
  catch (error) {
129
133
  console.error(error);
130
134
  console.log();
131
- utilities_1.log.warn('Error ocurred during seeding your database.\n\n' +
135
+ log.warn('Error ocurred during seeding your database.\n\n' +
132
136
  ' Nothing has changed since the seeding process was in a transaction.\n' +
133
137
  ' Try to fix the error and seed again.');
134
138
  }
135
139
  await pool.end();
136
140
  },
137
141
  };
138
- exports.default = seed;
142
+ export default seed;
@@ -1,17 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.oidcConfigReaders = void 0;
4
- const promises_1 = require("fs/promises");
5
- const schemas_1 = require("@logto/schemas");
6
- const essentials_1 = require("@silverhand/essentials");
7
- const utilities_1 = require("../utilities");
1
+ import { readFile } from 'fs/promises';
2
+ import { LogtoOidcConfigKey } from '@logto/schemas';
3
+ import { getEnv, getEnvAsStringArray } from '@silverhand/essentials';
4
+ import { generateOidcCookieKey, generateOidcPrivateKey } from '../utilities.js';
8
5
  const isBase64FormatPrivateKey = (key) => !key.includes('-');
9
6
  /**
10
7
  * Each config reader will do the following things in order:
11
8
  * 1. Try to read value from env (mimic the behavior from the original core)
12
9
  * 2. Generate value if #1 doesn't work
13
10
  */
14
- exports.oidcConfigReaders = {
11
+ export const oidcConfigReaders = {
15
12
  /**
16
13
  * Try to read private keys with the following order:
17
14
  *
@@ -22,9 +19,9 @@ exports.oidcConfigReaders = {
22
19
  * @returns The private keys for OIDC provider.
23
20
  * @throws An error when failed to read a private key.
24
21
  */
25
- [schemas_1.LogtoOidcConfigKey.PrivateKeys]: async () => {
22
+ [LogtoOidcConfigKey.PrivateKeys]: async () => {
26
23
  // Direct keys in env
27
- const privateKeys = (0, essentials_1.getEnvAsStringArray)('OIDC_PRIVATE_KEYS');
24
+ const privateKeys = getEnvAsStringArray('OIDC_PRIVATE_KEYS');
28
25
  if (privateKeys.length > 0) {
29
26
  return {
30
27
  value: privateKeys.map((key) => {
@@ -37,26 +34,26 @@ exports.oidcConfigReaders = {
37
34
  };
38
35
  }
39
36
  // Read keys from files
40
- const privateKeyPaths = (0, essentials_1.getEnvAsStringArray)('OIDC_PRIVATE_KEY_PATHS');
37
+ const privateKeyPaths = getEnvAsStringArray('OIDC_PRIVATE_KEY_PATHS');
41
38
  if (privateKeyPaths.length > 0) {
42
39
  return {
43
- value: await Promise.all(privateKeyPaths.map(async (path) => (0, promises_1.readFile)(path, 'utf8'))),
40
+ value: await Promise.all(privateKeyPaths.map(async (path) => readFile(path, 'utf8'))),
44
41
  fromEnv: true,
45
42
  };
46
43
  }
47
44
  return {
48
- value: [await (0, utilities_1.generateOidcPrivateKey)()],
45
+ value: [await generateOidcPrivateKey()],
49
46
  fromEnv: false,
50
47
  };
51
48
  },
52
- [schemas_1.LogtoOidcConfigKey.CookieKeys]: async () => {
49
+ [LogtoOidcConfigKey.CookieKeys]: async () => {
53
50
  const envKey = 'OIDC_COOKIE_KEYS';
54
- const keys = (0, essentials_1.getEnvAsStringArray)(envKey);
55
- return { value: keys.length > 0 ? keys : [(0, utilities_1.generateOidcCookieKey)()], fromEnv: keys.length > 0 };
51
+ const keys = getEnvAsStringArray(envKey);
52
+ return { value: keys.length > 0 ? keys : [generateOidcCookieKey()], fromEnv: keys.length > 0 };
56
53
  },
57
- [schemas_1.LogtoOidcConfigKey.RefreshTokenReuseInterval]: async () => {
54
+ [LogtoOidcConfigKey.RefreshTokenReuseInterval]: async () => {
58
55
  const envKey = 'OIDC_REFRESH_TOKEN_REUSE_INTERVAL';
59
- const raw = Number((0, essentials_1.getEnv)(envKey));
56
+ const raw = Number(getEnv(envKey));
60
57
  const value = Math.max(3, raw || 0);
61
58
  return { value, fromEnv: raw === value };
62
59
  },
@@ -1,11 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateOidcCookieKey = exports.generateOidcPrivateKey = void 0;
4
- const crypto_1 = require("crypto");
5
- const util_1 = require("util");
6
- const nanoid_1 = require("nanoid");
7
- const generateOidcPrivateKey = async () => {
8
- const { privateKey } = await (0, util_1.promisify)(crypto_1.generateKeyPair)('rsa', {
1
+ import { generateKeyPair } from 'crypto';
2
+ import { promisify } from 'util';
3
+ import { nanoid } from 'nanoid';
4
+ export const generateOidcPrivateKey = async () => {
5
+ const { privateKey } = await promisify(generateKeyPair)('rsa', {
9
6
  modulusLength: 4096,
10
7
  publicKeyEncoding: {
11
8
  type: 'spki',
@@ -18,6 +15,4 @@ const generateOidcPrivateKey = async () => {
18
15
  });
19
16
  return privateKey;
20
17
  };
21
- exports.generateOidcPrivateKey = generateOidcPrivateKey;
22
- const generateOidcCookieKey = () => (0, nanoid_1.nanoid)();
23
- exports.generateOidcCookieKey = generateOidcCookieKey;
18
+ export const generateOidcCookieKey = () => nanoid();
@@ -1,5 +1,5 @@
1
1
  import type { CommandModule } from 'yargs';
2
- export declare type InstallArgs = {
2
+ export type InstallArgs = {
3
3
  path?: string;
4
4
  skipSeed: boolean;
5
5
  officialConnectors?: boolean;
@@ -1,41 +1,27 @@
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
- const chalk_1 = __importDefault(require("chalk"));
7
- const database_1 = require("../../database");
8
- const utilities_1 = require("../../utilities");
9
- const utils_1 = require("../connector/utils");
10
- const utils_2 = require("./utils");
1
+ import chalk from 'chalk';
2
+ import { getDatabaseUrlFromConfig } from '../../database.js';
3
+ import { log } from '../../utilities.js';
4
+ import { validateNodeVersion, inquireInstancePath, validateDatabase, downloadRelease, seedDatabase, createEnv, logFinale, decompress, isUrl, } from './utils.js';
11
5
  const installLogto = async ({ path, skipSeed, officialConnectors, downloadUrl }) => {
12
- (0, utils_2.validateNodeVersion)();
6
+ validateNodeVersion();
13
7
  // Get instance path
14
- const instancePath = await (0, utils_2.inquireInstancePath)(path);
8
+ const instancePath = await inquireInstancePath(path);
15
9
  // Validate if user has a valid database
16
- await (0, utils_2.validateDatabase)();
10
+ await validateDatabase();
17
11
  // Download and decompress
18
- const tarPath = !downloadUrl || (0, utils_2.isUrl)(downloadUrl) ? await (0, utils_2.downloadRelease)(downloadUrl) : downloadUrl;
19
- await (0, utils_2.decompress)(instancePath, tarPath);
12
+ const tarPath = !downloadUrl || isUrl(downloadUrl) ? await downloadRelease(downloadUrl) : downloadUrl;
13
+ await decompress(instancePath, tarPath);
20
14
  // Seed database
21
15
  if (skipSeed) {
22
- utilities_1.log.info(`Skipped database seeding.\n\n' + ' You can use the ${chalk_1.default.green('db seed')} command to seed database when ready.\n`);
16
+ log.info(`Skipped database seeding.\n\n' + ' You can use the ${chalk.green('db seed')} command to seed database when ready.\n`);
23
17
  }
24
18
  else {
25
- await (0, utils_2.seedDatabase)(instancePath);
19
+ await seedDatabase(instancePath);
26
20
  }
27
21
  // Save to dot env
28
- await (0, utils_2.createEnv)(instancePath, await (0, database_1.getDatabaseUrlFromConfig)());
29
- // Add official connectors
30
- if (await (0, utils_2.inquireOfficialConnectors)(officialConnectors)) {
31
- await (0, utils_1.addOfficialConnectors)(instancePath);
32
- }
33
- else {
34
- utilities_1.log.info('Skipped adding official connectors.\n\n' +
35
- ` You can use the ${chalk_1.default.green('connector add')} command to add connectors at any time.\n`);
36
- }
22
+ await createEnv(instancePath, await getDatabaseUrlFromConfig());
37
23
  // Finale
38
- (0, utils_2.logFinale)(instancePath);
24
+ logFinale(instancePath);
39
25
  };
40
26
  const install = {
41
27
  command: ['init', 'i', 'install'],
@@ -68,4 +54,4 @@ const install = {
68
54
  await installLogto({ path: p, skipSeed: ss, officialConnectors: oc, downloadUrl: du });
69
55
  },
70
56
  };
71
- exports.default = install;
57
+ export default install;
@@ -7,5 +7,4 @@ export declare const decompress: (toPath: string, tarPath: string) => Promise<vo
7
7
  export declare const seedDatabase: (instancePath: string) => Promise<void>;
8
8
  export declare const createEnv: (instancePath: string, databaseUrl: string) => Promise<void>;
9
9
  export declare const logFinale: (instancePath: string) => void;
10
- export declare const inquireOfficialConnectors: (initialAnswer?: boolean) => Promise<boolean>;
11
10
  export declare const isUrl: (string: string) => boolean;
@@ -1,94 +1,63 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.isUrl = exports.inquireOfficialConnectors = exports.logFinale = exports.createEnv = exports.seedDatabase = exports.decompress = exports.downloadRelease = exports.validateDatabase = exports.inquireInstancePath = exports.validateNodeVersion = exports.defaultPath = void 0;
30
- const child_process_1 = require("child_process");
31
- const fs_1 = require("fs");
32
- const promises_1 = require("fs/promises");
33
- const os_1 = __importDefault(require("os"));
34
- const path_1 = __importDefault(require("path"));
35
- const essentials_1 = require("@silverhand/essentials");
36
- const chalk_1 = __importDefault(require("chalk"));
37
- const fs_extra_1 = require("fs-extra");
38
- const inquirer_1 = __importDefault(require("inquirer"));
39
- const semver = __importStar(require("semver"));
40
- const tar_1 = __importDefault(require("tar"));
41
- const database_1 = require("../../database");
42
- const utilities_1 = require("../../utilities");
43
- const seed_1 = require("../database/seed");
44
- exports.defaultPath = path_1.default.join(os_1.default.homedir(), 'logto');
1
+ import { execSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import fs from 'fs/promises';
4
+ import os from 'os';
5
+ import path from 'path';
6
+ import { assert } from '@silverhand/essentials';
7
+ import chalk from 'chalk';
8
+ import inquirer from 'inquirer';
9
+ import * as semver from 'semver';
10
+ import tar from 'tar';
11
+ import { createPoolAndDatabaseIfNeeded } from '../../database.js';
12
+ import { packageJson } from '../../package-json.js';
13
+ import { cliConfig, ConfigKey, downloadFile, isTty, log, oraPromise, safeExecSync, } from '../../utilities.js';
14
+ import { seedByPool } from '../database/seed/index.js';
15
+ export const defaultPath = path.join(os.homedir(), 'logto');
45
16
  const pgRequired = new semver.SemVer('14.0.0');
46
- const validateNodeVersion = () => {
17
+ export const validateNodeVersion = () => {
47
18
  const required = [new semver.SemVer('16.13.0'), new semver.SemVer('18.12.0')];
48
19
  const requiredVersionString = required.map((version) => '^' + version.version).join(' || ');
49
- const current = new semver.SemVer((0, child_process_1.execSync)('node -v', { encoding: 'utf8', stdio: 'pipe' }));
20
+ const current = new semver.SemVer(execSync('node -v', { encoding: 'utf8', stdio: 'pipe' }));
50
21
  if (required.every((version) => version.major !== current.major)) {
51
- utilities_1.log.error(`Logto requires NodeJS ${requiredVersionString}, but ${current.version} found.`);
22
+ log.error(`Logto requires NodeJS ${requiredVersionString}, but ${current.version} found.`);
52
23
  }
53
24
  if (required.some((version) => version.major === current.major && version.compare(current) > 0)) {
54
- utilities_1.log.warn(`Logto is tested under NodeJS ${requiredVersionString}, but version ${current.version} found.`);
25
+ log.warn(`Logto is tested under NodeJS ${requiredVersionString}, but version ${current.version} found.`);
55
26
  }
56
27
  };
57
- exports.validateNodeVersion = validateNodeVersion;
58
- const validatePath = (value) => (0, fs_1.existsSync)(path_1.default.resolve(value))
59
- ? `The path ${chalk_1.default.green(value)} already exists, please try another.`
28
+ const validatePath = (value) => existsSync(path.resolve(value))
29
+ ? `The path ${chalk.green(value)} already exists, please try another.`
60
30
  : true;
61
- const inquireInstancePath = async (initialPath) => {
62
- if (!(0, utilities_1.isTty)()) {
63
- (0, essentials_1.assert)(initialPath, new Error('Path is missing'));
31
+ export const inquireInstancePath = async (initialPath) => {
32
+ if (!isTty()) {
33
+ assert(initialPath, new Error('Path is missing'));
64
34
  return initialPath;
65
35
  }
66
- const { instancePath } = await inquirer_1.default.prompt({
36
+ const { instancePath } = await inquirer.prompt({
67
37
  name: 'instancePath',
68
38
  message: 'Where should we create your Logto instance?',
69
39
  type: 'input',
70
- default: exports.defaultPath,
40
+ default: defaultPath,
71
41
  filter: (value) => value.trim(),
72
42
  validate: validatePath,
73
43
  }, { instancePath: initialPath });
74
44
  // Validate for initialPath
75
45
  const validated = validatePath(instancePath);
76
46
  if (validated !== true) {
77
- utilities_1.log.error(validated);
47
+ log.error(validated);
78
48
  }
79
49
  return instancePath;
80
50
  };
81
- exports.inquireInstancePath = inquireInstancePath;
82
- const validateDatabase = async () => {
83
- if (utilities_1.cliConfig.has(utilities_1.ConfigKey.DatabaseUrl) || !(0, utilities_1.isTty)()) {
51
+ export const validateDatabase = async () => {
52
+ if (cliConfig.has(ConfigKey.DatabaseUrl) || !isTty()) {
84
53
  return;
85
54
  }
86
- const { hasPostgresUrl } = await inquirer_1.default.prompt({
55
+ const { hasPostgresUrl } = await inquirer.prompt({
87
56
  name: 'hasPostgresUrl',
88
57
  message: `Logto requires PostgreSQL >=${pgRequired.version} but cannot find in the current environment.\n Do you have a remote PostgreSQL instance ready?`,
89
58
  type: 'confirm',
90
59
  when: () => {
91
- const pgOutput = (0, utilities_1.safeExecSync)('postgres --version') ?? '';
60
+ const pgOutput = safeExecSync('postgres --version') ?? '';
92
61
  // Filter out all brackets in the output since Homebrew will append `(Homebrew)`.
93
62
  const pgArray = pgOutput.split(' ').filter((value) => !value.startsWith('('));
94
63
  const pgCurrent = semver.coerce(pgArray[pgArray.length - 1]);
@@ -96,74 +65,59 @@ const validateDatabase = async () => {
96
65
  },
97
66
  });
98
67
  if (hasPostgresUrl === false) {
99
- utilities_1.log.error('Logto requires a Postgres instance to run.');
68
+ log.error('Logto requires a Postgres instance to run.');
100
69
  }
101
70
  };
102
- exports.validateDatabase = validateDatabase;
103
- const downloadRelease = async (url) => {
104
- const tarFilePath = path_1.default.resolve(os_1.default.tmpdir(), './logto.tar.gz');
105
- utilities_1.log.info(`Download Logto to ${tarFilePath}`);
106
- await (0, utilities_1.downloadFile)(url ?? 'https://github.com/logto-io/logto/releases/latest/download/logto.tar.gz', tarFilePath);
71
+ export const downloadRelease = async (url) => {
72
+ const tarFilePath = path.resolve(os.tmpdir(), './logto.tar.gz');
73
+ const from = url ??
74
+ `https://github.com/logto-io/logto/releases/download/v${packageJson.version}/logto.tar.gz`;
75
+ log.info(`Download Logto from ${from}`);
76
+ log.info(`Target ${tarFilePath}`);
77
+ await downloadFile(from, tarFilePath);
107
78
  return tarFilePath;
108
79
  };
109
- exports.downloadRelease = downloadRelease;
110
- const decompress = async (toPath, tarPath) => {
80
+ export const decompress = async (toPath, tarPath) => {
111
81
  const run = async () => {
112
82
  try {
113
- await (0, promises_1.mkdir)(toPath);
114
- await tar_1.default.extract({ file: tarPath, cwd: toPath, strip: 1 });
83
+ await fs.mkdir(toPath);
84
+ await tar.extract({ file: tarPath, cwd: toPath, strip: 1 });
115
85
  }
116
86
  catch (error) {
117
- utilities_1.log.error(error);
87
+ log.error(error);
118
88
  }
119
89
  };
120
- return (0, utilities_1.oraPromise)(run(), {
90
+ return oraPromise(run(), {
121
91
  text: `Decompress to ${toPath}`,
122
- prefixText: chalk_1.default.blue('[info]'),
92
+ prefixText: chalk.blue('[info]'),
123
93
  }, true);
124
94
  };
125
- exports.decompress = decompress;
126
- const seedDatabase = async (instancePath) => {
95
+ export const seedDatabase = async (instancePath) => {
127
96
  try {
128
- const pool = await (0, database_1.createPoolAndDatabaseIfNeeded)();
129
- await (0, seed_1.seedByPool)(pool, 'all');
97
+ const pool = await createPoolAndDatabaseIfNeeded();
98
+ await seedByPool(pool, 'all');
130
99
  await pool.end();
131
100
  }
132
101
  catch (error) {
133
102
  console.error(error);
134
- await (0, utilities_1.oraPromise)((0, fs_extra_1.remove)(instancePath), {
103
+ await oraPromise(fs.rm(instancePath, { force: true, recursive: true }), {
135
104
  text: 'Clean up',
136
- prefixText: chalk_1.default.blue('[info]'),
105
+ prefixText: chalk.blue('[info]'),
137
106
  });
138
- utilities_1.log.error('Error occurred during seeding your Logto database. Nothing has changed since the seeding process was in a transaction.\n\n' +
139
- ` To skip the database seeding, append ${chalk_1.default.green('--skip-seed')} to the command options.`);
107
+ log.error('Error occurred during seeding your Logto database. Nothing has changed since the seeding process was in a transaction.\n\n' +
108
+ ` To skip the database seeding, append ${chalk.green('--skip-seed')} to the command options.`);
140
109
  }
141
110
  };
142
- exports.seedDatabase = seedDatabase;
143
- const createEnv = async (instancePath, databaseUrl) => {
144
- const dotEnvPath = path_1.default.resolve(instancePath, '.env');
145
- await (0, fs_extra_1.writeFile)(dotEnvPath, `DB_URL=${databaseUrl}`, {
146
- encoding: 'utf8',
147
- });
148
- utilities_1.log.info(`Saved database URL to ${chalk_1.default.blue(dotEnvPath)}`);
111
+ export const createEnv = async (instancePath, databaseUrl) => {
112
+ const dotEnvPath = path.resolve(instancePath, '.env');
113
+ await fs.writeFile(dotEnvPath, `DB_URL=${databaseUrl}`, 'utf8');
114
+ log.info(`Saved database URL to ${chalk.blue(dotEnvPath)}`);
149
115
  };
150
- exports.createEnv = createEnv;
151
- const logFinale = (instancePath) => {
116
+ export const logFinale = (instancePath) => {
152
117
  const startCommand = `cd ${instancePath} && npm start`;
153
- utilities_1.log.info(`Use the command below to start Logto. Happy hacking!\n\n ${chalk_1.default.green(startCommand)}`);
154
- };
155
- exports.logFinale = logFinale;
156
- const inquireOfficialConnectors = async (initialAnswer) => {
157
- const { value } = await inquirer_1.default.prompt({
158
- name: 'value',
159
- message: 'Do you want to add official connectors?',
160
- type: 'confirm',
161
- default: true,
162
- }, { value: initialAnswer });
163
- return value;
118
+ log.info(`Use the command below to start Logto. Happy hacking!\n\n ${chalk.green(startCommand)}`);
164
119
  };
165
- exports.inquireOfficialConnectors = inquireOfficialConnectors;
166
- const isUrl = (string) => {
120
+ export const isUrl = (string) => {
167
121
  try {
168
122
  // On purpose to test
169
123
  // eslint-disable-next-line no-new
@@ -174,4 +128,3 @@ const isUrl = (string) => {
174
128
  return false;
175
129
  }
176
130
  };
177
- exports.isUrl = isUrl;
package/lib/constants.js CHANGED
@@ -1,4 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.connectorDirectory = void 0;
4
- exports.connectorDirectory = 'connectors';
1
+ export const connectorDirectory = 'connectors';