@nocobase/cli 2.1.0-beta.35 → 2.1.0-beta.36

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.
@@ -33,6 +33,7 @@ const INIT_ENV_ADD_FLAG_NAMES = [
33
33
  'auth-type',
34
34
  'access-token',
35
35
  'token',
36
+ 'skip-auth',
36
37
  ];
37
38
  const initText = (key, values) => localeText(`commands.init.${key}`, values);
38
39
  function withExtraHidden(def, extraHidden) {
@@ -285,6 +286,19 @@ Prompt modes:
285
286
  rootPassword: newInstallOnly(Install.rootUserPrompts.rootPassword),
286
287
  rootNickname: newInstallOnly(Install.rootUserPrompts.rootNickname),
287
288
  };
289
+ buildPromptCatalog(flags) {
290
+ if (!flags['skip-auth']) {
291
+ return Init.prompts;
292
+ }
293
+ const accessTokenPrompt = {
294
+ ...EnvAdd.prompts.accessToken,
295
+ hidden: () => true,
296
+ };
297
+ return {
298
+ ...Init.prompts,
299
+ accessToken: existingAppOnly(accessTokenPrompt),
300
+ };
301
+ }
288
302
  parsedFlagsForPromptSeeds;
289
303
  static flags = {
290
304
  yes: Flags.boolean({
@@ -330,6 +344,10 @@ Prompt modes:
330
344
  if (normalizedFlags.ui && normalizedFlags.yes) {
331
345
  this.error('--ui cannot be used with --yes.');
332
346
  }
347
+ if (normalizedFlags['skip-auth']
348
+ && (normalizedFlags['access-token'] !== undefined || normalizedFlags.token !== undefined)) {
349
+ this.error('--skip-auth cannot be used with --access-token or --token.');
350
+ }
333
351
  if (normalizedFlags.ui && normalizedFlags.resume) {
334
352
  this.error('--ui cannot be used with --resume.');
335
353
  }
@@ -397,9 +415,10 @@ Prompt modes:
397
415
  }
398
416
  }
399
417
  const dynamicInitialValues = await Init.buildDynamicInitialValuesForInstall(normalizedFlags, presetValues);
418
+ const promptCatalog = this.buildPromptCatalog(normalizedFlags);
400
419
  if (useBrowserUi) {
401
420
  presetValues = await runPromptCatalogWebUI({
402
- stages: Init.buildWebUiStages(),
421
+ stages: Init.buildWebUiStages(promptCatalog),
403
422
  values: {
404
423
  ...dynamicInitialValues,
405
424
  ...presetValues,
@@ -418,7 +437,7 @@ Prompt modes:
418
437
  },
419
438
  });
420
439
  }
421
- const results = await runPromptCatalog(Init.prompts, {
440
+ const results = await runPromptCatalog(promptCatalog, {
422
441
  initialValues: dynamicInitialValues,
423
442
  values: presetValues,
424
443
  yes: normalizedFlags.yes || useBrowserUi || !interactive,
@@ -434,9 +453,13 @@ Prompt modes:
434
453
  },
435
454
  command: this,
436
455
  });
437
- const hasNocobase = results.hasNocobase === 'yes';
456
+ const normalizedResults = {
457
+ ...results,
458
+ ...pickKeys(presetValues, ['dbSchema', 'dbTablePrefix', 'dbUnderscored', 'skipAuth']),
459
+ };
460
+ const hasNocobase = normalizedResults.hasNocobase === 'yes';
438
461
  const existingEnv = !hasNocobase
439
- ? await getEnv(String(results.appName ?? '').trim(), { scope: resolveDefaultConfigScope() })
462
+ ? await getEnv(String(normalizedResults.appName ?? '').trim(), { scope: resolveDefaultConfigScope() })
440
463
  : undefined;
441
464
  if (existingEnv && Boolean(normalizedFlags.force)) {
442
465
  printWarning(`Reconfiguring existing env ${pc.cyan(pc.bold(`"${existingEnv.name}"`))} from the global config because ${pc.bold('--force')} was set. The env config will be updated before install starts, then refreshed again after install succeeds.`);
@@ -450,15 +473,15 @@ Prompt modes:
450
473
  if (hasNocobase) {
451
474
  logInitStage('Connecting to the env');
452
475
  printVerbose('Running nb env add');
453
- await this.config.runCommand('env:add', this.buildEnvAddArgv(results));
476
+ await this.config.runCommand('env:add', this.buildEnvAddArgv(normalizedResults));
454
477
  }
455
478
  else {
456
479
  logInitStage('Saving env config');
457
- await this.persistManagedEnvConfig(results, normalizedFlags);
458
- managedInstallResults = results;
459
- printInfo(`Saved env config for "${String(results.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME}".`);
480
+ await this.persistManagedEnvConfig(normalizedResults, normalizedFlags);
481
+ managedInstallResults = normalizedResults;
482
+ printInfo(`Saved env config for "${String(normalizedResults.appName ?? DEFAULT_INIT_APP_NAME).trim() || DEFAULT_INIT_APP_NAME}".`);
460
483
  printVerbose('Running nb init');
461
- await this.config.runCommand('install', this.buildInstallArgv(results, normalizedFlags));
484
+ await this.config.runCommand('install', this.buildInstallArgv(normalizedResults, normalizedFlags));
462
485
  }
463
486
  }
464
487
  catch (error) {
@@ -505,8 +528,7 @@ Prompt modes:
505
528
  }
506
529
  return out;
507
530
  }
508
- static buildWebUiStages() {
509
- const c = Init.prompts;
531
+ static buildWebUiStages(c = Init.prompts) {
510
532
  return [
511
533
  {
512
534
  sectionTitle: initText('webUi.gettingStarted.title'),
@@ -599,6 +621,9 @@ Prompt modes:
599
621
  if (flags['auth-type'] !== undefined && String(flags['auth-type']).trim() !== '') {
600
622
  preset.authType = String(flags['auth-type']).trim();
601
623
  }
624
+ if (flags['skip-auth']) {
625
+ preset.skipAuth = true;
626
+ }
602
627
  const accessToken = String(flags['access-token'] ?? flags.token ?? '');
603
628
  if (flags['access-token'] !== undefined || flags.token !== undefined) {
604
629
  preset.accessToken = accessToken;
@@ -649,6 +674,15 @@ Prompt modes:
649
674
  if (flags['db-password'] !== undefined) {
650
675
  preset.dbPassword = String(flags['db-password'] ?? '');
651
676
  }
677
+ if (flags['db-schema'] !== undefined && String(flags['db-schema']).trim() !== '') {
678
+ preset.dbSchema = String(flags['db-schema']).trim();
679
+ }
680
+ if (flags['db-table-prefix'] !== undefined && String(flags['db-table-prefix']).trim() !== '') {
681
+ preset.dbTablePrefix = String(flags['db-table-prefix']).trim();
682
+ }
683
+ if (argvHasToken(argv, ['--db-underscored', '--no-db-underscored'])) {
684
+ preset.dbUnderscored = Boolean(flags['db-underscored']);
685
+ }
652
686
  if (argvHasToken(argv, ['--fetch-source'])) {
653
687
  preset.fetchSource = Boolean(flags['fetch-source']);
654
688
  }
@@ -748,6 +782,8 @@ Prompt modes:
748
782
  const dbDatabase = String(results.dbDatabase ?? '').trim();
749
783
  const dbUser = String(results.dbUser ?? '').trim();
750
784
  const dbPassword = String(results.dbPassword ?? '');
785
+ const dbSchema = String(results.dbSchema ?? '').trim();
786
+ const dbTablePrefix = String(results.dbTablePrefix ?? '').trim();
751
787
  const apiBaseUrl = String(results.apiBaseUrl ?? '').trim();
752
788
  const authType = String(results.authType ?? '').trim() || 'oauth';
753
789
  const accessToken = String(results.accessToken ?? '');
@@ -765,6 +801,7 @@ Prompt modes:
765
801
  ? { kind: 'http' }
766
802
  : {}),
767
803
  ...(apiBaseUrl ? { apiBaseUrl } : appPort ? { apiBaseUrl: `http://127.0.0.1:${appPort}/api` } : {}),
804
+ ...(authType ? { authType } : {}),
768
805
  ...(authType === 'token' && accessToken ? { accessToken } : {}),
769
806
  ...(source ? { source } : {}),
770
807
  ...(version ? { downloadVersion: version } : {}),
@@ -786,6 +823,9 @@ Prompt modes:
786
823
  ...(dbDatabase ? { dbDatabase } : {}),
787
824
  ...(dbUser ? { dbUser } : {}),
788
825
  ...(dbPassword ? { dbPassword } : {}),
826
+ ...(dbSchema ? { dbSchema } : {}),
827
+ ...(dbTablePrefix ? { dbTablePrefix } : {}),
828
+ ...(results.dbUnderscored !== undefined ? { dbUnderscored: Boolean(results.dbUnderscored) } : {}),
789
829
  }, { scope: resolveDefaultConfigScope() });
790
830
  }
791
831
  buildEnvAddArgv(results) {
@@ -793,8 +833,12 @@ Prompt modes:
793
833
  argv.push('--no-intro');
794
834
  argv.push('--api-base-url', String(results.apiBaseUrl ?? DEFAULT_INIT_API_BASE_URL));
795
835
  argv.push('--auth-type', String(results.authType ?? 'oauth'));
796
- if (results.authType === 'token') {
797
- argv.push('--access-token', String(results.accessToken ?? ''));
836
+ const accessToken = String(results.accessToken ?? '');
837
+ if (results.skipAuth === true) {
838
+ argv.push('--skip-auth');
839
+ }
840
+ else if (results.authType === 'token' && accessToken) {
841
+ argv.push('--access-token', accessToken);
798
842
  }
799
843
  return argv;
800
844
  }
@@ -824,6 +868,9 @@ Prompt modes:
824
868
  if (authType) {
825
869
  argv.push('--auth-type', authType);
826
870
  }
871
+ if (Boolean(flags['skip-auth']) || results.skipAuth === true) {
872
+ argv.push('--skip-auth');
873
+ }
827
874
  if (authType === 'token' && accessToken) {
828
875
  argv.push('--access-token', accessToken);
829
876
  }
@@ -935,6 +982,17 @@ Prompt modes:
935
982
  if (dbPassword) {
936
983
  argv.push('--db-password', dbPassword);
937
984
  }
985
+ const dbSchema = String(results.dbSchema ?? '').trim();
986
+ if (dbSchema) {
987
+ argv.push('--db-schema', dbSchema);
988
+ }
989
+ const dbTablePrefix = String(results.dbTablePrefix ?? '').trim();
990
+ if (dbTablePrefix) {
991
+ argv.push('--db-table-prefix', dbTablePrefix);
992
+ }
993
+ if (results.dbUnderscored !== undefined) {
994
+ argv.push(Boolean(results.dbUnderscored) ? '--db-underscored' : '--no-db-underscored');
995
+ }
938
996
  const rootUsername = String(results.rootUsername ?? '').trim();
939
997
  if (rootUsername) {
940
998
  argv.push('--root-username', rootUsername);
@@ -136,6 +136,17 @@ const INSTALL_LANGUAGE_OPTIONS = Object.entries(INSTALL_LANGUAGE_CODES).map(([va
136
136
  label: `${label} (${value})`,
137
137
  }));
138
138
  const installText = (key, values) => localeText(`commands.install.${key}`, values);
139
+ function formatDeferredAuthMessage(envName, authType) {
140
+ const normalizedAuthType = String(authType ?? '').trim();
141
+ const nextStep = `Authentication was skipped for env "${envName}". Run \`nb env auth ${envName}\` to finish setup.`;
142
+ if (normalizedAuthType === 'token') {
143
+ return `${nextStep} You will be prompted for an access token.`;
144
+ }
145
+ if (normalizedAuthType === 'oauth') {
146
+ return `${nextStep} A browser sign-in flow will be started.`;
147
+ }
148
+ return nextStep;
149
+ }
139
150
  function argvHasToken(argv, tokens) {
140
151
  return tokens.some((t) => argv.includes(t));
141
152
  }
@@ -259,6 +270,40 @@ async function commandOutput(command, args, options) {
259
270
  });
260
271
  });
261
272
  }
273
+ function optionalEnvString(value) {
274
+ const text = String(value ?? '').trim();
275
+ return text || undefined;
276
+ }
277
+ function optionalEnvBoolean(value) {
278
+ if (value === undefined || value === null) {
279
+ return undefined;
280
+ }
281
+ return Boolean(value);
282
+ }
283
+ function pushOptionalEnvArg(args, key, value) {
284
+ if (typeof value === 'string') {
285
+ if (!value) {
286
+ return;
287
+ }
288
+ args.push('-e', `${key}=${value}`);
289
+ return;
290
+ }
291
+ if (typeof value === 'boolean') {
292
+ args.push('-e', `${key}=${String(value)}`);
293
+ }
294
+ }
295
+ function setOptionalEnvVar(out, key, value) {
296
+ if (typeof value === 'string') {
297
+ if (!value) {
298
+ return;
299
+ }
300
+ out[key] = value;
301
+ return;
302
+ }
303
+ if (typeof value === 'boolean') {
304
+ out[key] = String(value);
305
+ }
306
+ }
262
307
  export default class Install extends Command {
263
308
  ensuredDockerNetworks = new Set();
264
309
  logStage(title) {
@@ -322,6 +367,10 @@ export default class Install extends Command {
322
367
  aliases: ['token'],
323
368
  description: 'API key or access token when using --auth-type token',
324
369
  }),
370
+ 'skip-auth': Flags.boolean({
371
+ description: 'Save the env auth mode now and finish authentication later with `nb env auth`',
372
+ default: false,
373
+ }),
325
374
  lang: Flags.string({ description: 'Language for the installed NocoBase app', char: 'l', required: false }),
326
375
  force: Flags.boolean({
327
376
  description: 'Reconfigure an existing env and replace conflicting runtime resources when needed',
@@ -380,6 +429,17 @@ export default class Install extends Command {
380
429
  'db-password': Flags.string({
381
430
  description: 'Database password for the app',
382
431
  }),
432
+ 'db-schema': Flags.string({
433
+ description: 'Database schema for the app',
434
+ }),
435
+ 'db-table-prefix': Flags.string({
436
+ description: 'Database table prefix for the app',
437
+ }),
438
+ 'db-underscored': Flags.boolean({
439
+ allowNo: true,
440
+ description: 'Use underscored database naming for the app',
441
+ default: false,
442
+ }),
383
443
  'fetch-source': Flags.boolean({
384
444
  description: 'Download NocoBase app files or pull a Docker image before installing',
385
445
  default: false,
@@ -621,6 +681,9 @@ export default class Install extends Command {
621
681
  preset.authType = authType;
622
682
  }
623
683
  }
684
+ if (flags['skip-auth']) {
685
+ preset.skipAuth = true;
686
+ }
624
687
  if (flags['access-token'] !== undefined || flags.token !== undefined) {
625
688
  preset.accessToken = String(flags['access-token'] ?? flags.token ?? '');
626
689
  }
@@ -709,6 +772,21 @@ export default class Install extends Command {
709
772
  if (flags['db-password'] !== undefined) {
710
773
  preset.dbPassword = String(flags['db-password'] ?? '');
711
774
  }
775
+ if (flags['db-schema'] !== undefined) {
776
+ const v = String(flags['db-schema'] ?? '').trim();
777
+ if (v) {
778
+ preset.dbSchema = v;
779
+ }
780
+ }
781
+ if (flags['db-table-prefix'] !== undefined) {
782
+ const v = String(flags['db-table-prefix'] ?? '').trim();
783
+ if (v) {
784
+ preset.dbTablePrefix = v;
785
+ }
786
+ }
787
+ if (argvHasToken(argv, ['--db-underscored', '--no-db-underscored'])) {
788
+ preset.dbUnderscored = flags['db-underscored'];
789
+ }
712
790
  return preset;
713
791
  }
714
792
  static buildAppPresetValuesFromFlags(flags) {
@@ -731,6 +809,9 @@ export default class Install extends Command {
731
809
  'dbDatabase',
732
810
  'dbUser',
733
811
  'dbPassword',
812
+ 'dbSchema',
813
+ 'dbTablePrefix',
814
+ 'dbUnderscored',
734
815
  ]);
735
816
  }
736
817
  static buildRootPresetValuesFromFlags(flags) {
@@ -748,6 +829,27 @@ export default class Install extends Command {
748
829
  'accessToken',
749
830
  ]);
750
831
  }
832
+ buildEnvAddPromptsForInstall(parsed) {
833
+ const apiBaseUrlPrompt = {
834
+ ...EnvAdd.prompts.apiBaseUrl,
835
+ validate: undefined,
836
+ };
837
+ const prompts = {
838
+ ...EnvAdd.prompts,
839
+ apiBaseUrl: apiBaseUrlPrompt,
840
+ };
841
+ if (!parsed['skip-auth']) {
842
+ return prompts;
843
+ }
844
+ const accessTokenPrompt = {
845
+ ...EnvAdd.prompts.accessToken,
846
+ hidden: () => true,
847
+ };
848
+ return {
849
+ ...prompts,
850
+ accessToken: accessTokenPrompt,
851
+ };
852
+ }
751
853
  static toOptionalPromptString(value) {
752
854
  if (value === undefined || value === null) {
753
855
  return undefined;
@@ -917,12 +1019,16 @@ export default class Install extends Command {
917
1019
  const dbDatabase = Install.toOptionalPromptString(config.dbDatabase);
918
1020
  const dbUser = Install.toOptionalPromptString(config.dbUser);
919
1021
  const dbPassword = Install.toOptionalPromptString(config.dbPassword);
1022
+ const dbSchema = Install.toOptionalPromptString(config.dbSchema);
1023
+ const dbTablePrefix = Install.toOptionalPromptString(config.dbTablePrefix);
1024
+ const dbUnderscored = typeof config.dbUnderscored === 'boolean' ? config.dbUnderscored : undefined;
920
1025
  const builtinDbImage = Install.toOptionalPromptString(config.builtinDbImage);
921
1026
  const rootUsername = Install.toOptionalPromptString(config.rootUsername);
922
1027
  const rootEmail = Install.toOptionalPromptString(config.rootEmail);
923
1028
  const rootPassword = Install.toOptionalPromptString(config.rootPassword);
924
1029
  const rootNickname = Install.toOptionalPromptString(config.rootNickname);
925
1030
  const auth = config.auth;
1031
+ const savedAuthType = Install.toOptionalPromptString(config.authType) ?? Install.toOptionalPromptString(auth?.type);
926
1032
  const appPreset = {
927
1033
  ...(appRootPath ? { appRootPath } : {}),
928
1034
  ...(appPort ? { appPort } : {}),
@@ -962,6 +1068,9 @@ export default class Install extends Command {
962
1068
  ...(dbDatabase ? { dbDatabase } : {}),
963
1069
  ...(dbUser ? { dbUser } : {}),
964
1070
  ...(dbPassword ? { dbPassword } : {}),
1071
+ ...(dbSchema ? { dbSchema } : {}),
1072
+ ...(dbTablePrefix ? { dbTablePrefix } : {}),
1073
+ ...(dbUnderscored !== undefined ? { dbUnderscored } : {}),
965
1074
  };
966
1075
  const rootPreset = {
967
1076
  ...(rootUsername ? { rootUsername } : {}),
@@ -970,13 +1079,13 @@ export default class Install extends Command {
970
1079
  ...(rootNickname ? { rootNickname } : {}),
971
1080
  };
972
1081
  const envAddPreset = {};
973
- if (auth?.type === 'token') {
1082
+ if (savedAuthType === 'token') {
974
1083
  envAddPreset.authType = 'token';
975
1084
  if (Install.toOptionalPromptString(auth.accessToken)) {
976
1085
  envAddPreset.accessToken = String(auth.accessToken);
977
1086
  }
978
1087
  }
979
- else if (auth?.type === 'oauth') {
1088
+ else if (savedAuthType === 'oauth') {
980
1089
  envAddPreset.authType = 'oauth';
981
1090
  }
982
1091
  return {
@@ -1596,6 +1705,9 @@ export default class Install extends Command {
1596
1705
  || DEFAULT_INSTALL_DB_DATABASE;
1597
1706
  const dbUser = String(params.dbResults.dbUser ?? DEFAULT_INSTALL_DB_USER).trim() || DEFAULT_INSTALL_DB_USER;
1598
1707
  const dbPassword = String(params.dbResults.dbPassword ?? DEFAULT_INSTALL_DB_PASSWORD) || DEFAULT_INSTALL_DB_PASSWORD;
1708
+ const dbSchema = optionalEnvString(params.dbResults.dbSchema);
1709
+ const dbTablePrefix = optionalEnvString(params.dbResults.dbTablePrefix);
1710
+ const dbUnderscored = optionalEnvBoolean(params.dbResults.dbUnderscored);
1599
1711
  const appKey = crypto.randomBytes(32).toString('hex');
1600
1712
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
1601
1713
  const containerName = Install.buildDockerAppContainerName(params.envName, params.dockerContainerPrefix ?? params.workspaceName);
@@ -1623,7 +1735,11 @@ export default class Install extends Command {
1623
1735
  for (const [key, value] of Object.entries(initEnvVars)) {
1624
1736
  args.push('-e', `${key}=${value}`);
1625
1737
  }
1626
- args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:/app/nocobase/storage`, imageRef);
1738
+ args.push('-e', `APP_KEY=${appKey}`, '-e', `DB_DIALECT=${dbDialect}`, '-e', `DB_HOST=${dbHost}`, '-e', `DB_PORT=${dbPort}`, '-e', `DB_DATABASE=${dbDatabase}`, '-e', `DB_USER=${dbUser}`, '-e', `DB_PASSWORD=${dbPassword}`, '-e', `TZ=${timeZone}`, '-v', `${storagePath}:/app/nocobase/storage`);
1739
+ pushOptionalEnvArg(args, 'DB_SCHEMA', dbSchema);
1740
+ pushOptionalEnvArg(args, 'DB_TABLE_PREFIX', dbTablePrefix);
1741
+ pushOptionalEnvArg(args, 'DB_UNDERSCORED', dbUnderscored);
1742
+ args.push(imageRef);
1627
1743
  return {
1628
1744
  source: 'docker',
1629
1745
  networkName: params.networkName,
@@ -1797,6 +1913,9 @@ export default class Install extends Command {
1797
1913
  rootResults: params.rootResults,
1798
1914
  }),
1799
1915
  };
1916
+ setOptionalEnvVar(env, 'DB_SCHEMA', optionalEnvString(params.dbResults.dbSchema));
1917
+ setOptionalEnvVar(env, 'DB_TABLE_PREFIX', optionalEnvString(params.dbResults.dbTablePrefix));
1918
+ setOptionalEnvVar(env, 'DB_UNDERSCORED', optionalEnvBoolean(params.dbResults.dbUnderscored));
1800
1919
  return env;
1801
1920
  }
1802
1921
  async startLocalApp(params) {
@@ -1938,6 +2057,10 @@ export default class Install extends Command {
1938
2057
  }
1939
2058
  const authType = String(params.envAddResults.authType ?? 'oauth').trim()
1940
2059
  || 'oauth';
2060
+ if (params.skipAuth) {
2061
+ printInfo(formatDeferredAuthMessage(params.envName, authType));
2062
+ return;
2063
+ }
1941
2064
  if (authType === 'oauth') {
1942
2065
  await this.config.runCommand('env:auth', [params.envName]);
1943
2066
  }
@@ -1982,6 +2105,9 @@ export default class Install extends Command {
1982
2105
  dbDatabase: params.dbResults.dbDatabase,
1983
2106
  dbUser: params.dbResults.dbUser,
1984
2107
  dbPassword: params.dbResults.dbPassword,
2108
+ dbSchema: params.dbResults.dbSchema,
2109
+ dbTablePrefix: params.dbResults.dbTablePrefix,
2110
+ dbUnderscored: params.dbResults.dbUnderscored,
1985
2111
  rootUsername: params.rootResults.rootUsername,
1986
2112
  rootEmail: params.rootResults.rootEmail,
1987
2113
  rootPassword: params.rootResults.rootPassword,
@@ -2041,7 +2167,7 @@ export default class Install extends Command {
2041
2167
  ...(resumePreset?.dbPreset ?? {}),
2042
2168
  ...Install.buildDbPresetValuesFromFlags(parsed),
2043
2169
  };
2044
- const dbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(envName, downloadResults, {
2170
+ const promptedDbResults = await runPromptCatalog(Install.buildDbPromptsCatalog(envName, downloadResults, {
2045
2171
  resume: parsed.resume,
2046
2172
  }), {
2047
2173
  initialValues: {
@@ -2059,6 +2185,10 @@ export default class Install extends Command {
2059
2185
  values: dbPreset,
2060
2186
  yes,
2061
2187
  });
2188
+ const dbResults = {
2189
+ ...promptedDbResults,
2190
+ ...pickPresetKeys(dbPreset, ['dbSchema', 'dbTablePrefix', 'dbUnderscored']),
2191
+ };
2062
2192
  const rootPreset = Install.buildRootPresetValuesFromFlags(parsed);
2063
2193
  const rootResults = await runPromptCatalog(Install.rootUserPrompts, {
2064
2194
  initialValues: {},
@@ -2068,19 +2198,14 @@ export default class Install extends Command {
2068
2198
  },
2069
2199
  yes,
2070
2200
  });
2071
- const envAddPromptsForInstall = {
2072
- ...EnvAdd.prompts,
2073
- apiBaseUrl: {
2074
- ...EnvAdd.prompts.apiBaseUrl,
2075
- validate: undefined,
2076
- },
2077
- };
2201
+ const envAddPromptsForInstall = this.buildEnvAddPromptsForInstall(parsed);
2078
2202
  const envAddResults = await runPromptCatalog(envAddPromptsForInstall, {
2079
2203
  initialValues: {
2080
2204
  apiBaseUrl: `http://127.0.0.1:${appResults.appPort ?? DEFAULT_INSTALL_APP_PORT}/api`,
2081
2205
  },
2082
2206
  values: {
2083
2207
  name: envName,
2208
+ ...(parsed['skip-auth'] ? { skipAuth: true } : {}),
2084
2209
  ...(resumePreset?.envAddPreset ?? {}),
2085
2210
  ...Install.buildEnvAddPresetValuesFromFlags(parsed),
2086
2211
  },
@@ -2103,6 +2228,9 @@ export default class Install extends Command {
2103
2228
  const parsed = {
2104
2229
  ...flags,
2105
2230
  };
2231
+ if (parsed['skip-auth'] && (parsed['access-token'] !== undefined || parsed.token !== undefined)) {
2232
+ this.error('--skip-auth cannot be used with --access-token or --token.');
2233
+ }
2106
2234
  setVerboseMode(Boolean(parsed.verbose));
2107
2235
  const commandStdio = this.commandStdio(parsed.verbose);
2108
2236
  if (!parsed['no-intro']) {
@@ -2235,6 +2363,7 @@ export default class Install extends Command {
2235
2363
  envName,
2236
2364
  envAddResults,
2237
2365
  appReady: Boolean(dockerAppPlan || localAppPlan),
2366
+ skipAuth: Boolean(parsed['skip-auth']),
2238
2367
  });
2239
2368
  if (!dockerAppPlan && !localAppPlan) {
2240
2369
  printInfo(`Install config for "${envName}" has been saved.`);
@@ -21,11 +21,11 @@ async function promptActivationMode() {
21
21
  return await select({
22
22
  message: 'How do you want to activate the license?',
23
23
  choices: [
24
- { value: 'key', name: 'Use an existing license key' },
25
24
  { value: 'online', name: 'Request and activate a license online' },
25
+ { value: 'key', name: 'Use an existing license key' },
26
26
  { value: 'cancel', name: 'Cancel' },
27
27
  ],
28
- default: 'key',
28
+ default: 'online',
29
29
  });
30
30
  }
31
31
  catch {
@@ -70,7 +70,7 @@ async function promptLicenseKeyInput() {
70
70
  return {};
71
71
  }
72
72
  }
73
- async function promptOnlineActivationInput(initial) {
73
+ async function promptOnlineActivationInput(initial, defaultAppName) {
74
74
  let account = String(initial.account ?? '').trim();
75
75
  if (!account) {
76
76
  try {
@@ -107,8 +107,10 @@ async function promptOnlineActivationInput(initial) {
107
107
  let appName = String(initial.appName ?? '').trim();
108
108
  if (!appName) {
109
109
  try {
110
+ const resolvedDefaultAppName = String(defaultAppName ?? '').trim();
110
111
  const answer = await input({
111
112
  message: 'Application name',
113
+ default: resolvedDefaultAppName || undefined,
112
114
  validate: (value) => String(value ?? '').trim() ? true : 'Application name is required.',
113
115
  });
114
116
  appName = String(answer ?? '').trim();
@@ -259,7 +261,7 @@ export default class LicenseActivate extends Command {
259
261
  if (!isInteractiveTerminal()) {
260
262
  this.error('Online activation requires --account, --password, and --desc when not using a TTY.');
261
263
  }
262
- const prompted = await promptOnlineActivationInput(initialOnline);
264
+ const prompted = await promptOnlineActivationInput(initialOnline, runtime.envName);
263
265
  if (!prompted) {
264
266
  return;
265
267
  }
@@ -10,6 +10,11 @@ import { Command, Flags } from '@oclif/core';
10
10
  import { buildSuggestedInitCommand, publishSourceSnapshot } from '../../lib/source-publish.js';
11
11
  import { failTask, printInfo, startTask, succeedTask } from '../../lib/ui.js';
12
12
  function formatPublishFailure(message) {
13
+ if (message.includes('The specified --cwd does not exist:')
14
+ || message.includes('The specified --cwd is not a directory:')
15
+ || message.includes('Couldn\'t find a NocoBase source project from --cwd:')) {
16
+ return message;
17
+ }
13
18
  return [
14
19
  'Couldn\'t publish a source snapshot.',
15
20
  'Check that Docker is running, the target npm registry is reachable, and the current directory is a NocoBase source repo.',
@@ -20,6 +25,8 @@ export default class SourcePublish extends Command {
20
25
  static description = 'Publish the current NocoBase source repo as a snapshot version to an npm registry for install testing.';
21
26
  static examples = [
22
27
  '<%= config.bin %> <%= command.id %> --snapshot',
28
+ '<%= config.bin %> <%= command.id %> --snapshot --no-build',
29
+ '<%= config.bin %> <%= command.id %> --snapshot --build-dts',
23
30
  '<%= config.bin %> <%= command.id %> --snapshot --cwd /path/to/nocobase/source',
24
31
  '<%= config.bin %> <%= command.id %> --snapshot --npm-registry=http://127.0.0.1:4873',
25
32
  '<%= config.bin %> <%= command.id %> --snapshot --json',
@@ -38,6 +45,14 @@ export default class SourcePublish extends Command {
38
45
  description: 'Source repository path. Defaults to the nearest detected NocoBase source root from the current working directory',
39
46
  required: false,
40
47
  }),
48
+ 'no-build': Flags.boolean({
49
+ description: 'Skip building the source repo before snapshot versioning and publish',
50
+ default: false,
51
+ }),
52
+ 'build-dts': Flags.boolean({
53
+ description: 'Generate TypeScript declaration files during the source build',
54
+ default: false,
55
+ }),
41
56
  json: Flags.boolean({
42
57
  description: 'Print the publish result as JSON',
43
58
  default: false,
@@ -59,6 +74,8 @@ export default class SourcePublish extends Command {
59
74
  const result = await publishSourceSnapshot({
60
75
  cwd: flags.cwd,
61
76
  npmRegistry: flags['npm-registry'],
77
+ build: !flags['no-build'],
78
+ buildDts: flags['build-dts'],
62
79
  verbose: flags.verbose,
63
80
  });
64
81
  if (flags.json) {