gt 2.21.5 → 2.22.0

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 (114) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/api/collectUserEditDiffs.js +1 -1
  3. package/dist/auth/callbackPage.d.ts +1 -0
  4. package/dist/auth/callbackPage.js +77 -0
  5. package/dist/auth/callbackPage.js.map +1 -0
  6. package/dist/auth/credentialStore.d.ts +15 -0
  7. package/dist/auth/credentialStore.js +107 -0
  8. package/dist/auth/credentialStore.js.map +1 -0
  9. package/dist/auth/errors.d.ts +7 -0
  10. package/dist/auth/errors.js +23 -0
  11. package/dist/auth/errors.js.map +1 -0
  12. package/dist/auth/loopback.d.ts +9 -0
  13. package/dist/auth/loopback.js +73 -0
  14. package/dist/auth/loopback.js.map +1 -0
  15. package/dist/auth/loopback.test.d.ts +1 -0
  16. package/dist/auth/oauth.d.ts +39 -0
  17. package/dist/auth/oauth.js +260 -0
  18. package/dist/auth/oauth.js.map +1 -0
  19. package/dist/bin/bin-entry.js +2 -10
  20. package/dist/bin/bin-entry.js.map +1 -1
  21. package/dist/cli/base.d.ts +4 -8
  22. package/dist/cli/base.js +119 -60
  23. package/dist/cli/base.js.map +1 -1
  24. package/dist/cli/commands/api.js +6 -2
  25. package/dist/cli/commands/api.js.map +1 -1
  26. package/dist/cli/commands/upload.js +2 -2
  27. package/dist/cli/commands/upload.js.map +1 -1
  28. package/dist/cli/commands/utils/validation.d.ts +7 -7
  29. package/dist/cli/commands/utils/validation.js +7 -20
  30. package/dist/cli/commands/utils/validation.js.map +1 -1
  31. package/dist/config/generateSettings.js +4 -9
  32. package/dist/config/generateSettings.js.map +1 -1
  33. package/dist/config/optionPresets.js +16 -6
  34. package/dist/config/optionPresets.js.map +1 -1
  35. package/dist/config/validateSettings.d.ts +4 -2
  36. package/dist/config/validateSettings.js +9 -0
  37. package/dist/config/validateSettings.js.map +1 -1
  38. package/dist/console/index.d.ts +0 -2
  39. package/dist/console/index.js +2 -4
  40. package/dist/console/index.js.map +1 -1
  41. package/dist/console/inkPrompts.js +8 -6
  42. package/dist/console/inkPrompts.js.map +1 -1
  43. package/dist/console/inkTypes.d.ts +3 -0
  44. package/dist/console/logger.d.ts +13 -0
  45. package/dist/console/logger.js +60 -20
  46. package/dist/console/logger.js.map +1 -1
  47. package/dist/console/logging.d.ts +5 -3
  48. package/dist/console/logging.js +8 -6
  49. package/dist/console/logging.js.map +1 -1
  50. package/dist/console/promptParsing.d.ts +4 -3
  51. package/dist/console/promptParsing.js +7 -7
  52. package/dist/console/promptParsing.js.map +1 -1
  53. package/dist/formats/files/aggregateFiles.js +4 -4
  54. package/dist/formats/files/aggregateFiles.js.map +1 -1
  55. package/dist/formats/files/localeContent.js +2 -2
  56. package/dist/formats/files/localeContent.js.map +1 -1
  57. package/dist/formats/files/transformFormat.d.ts +2 -0
  58. package/dist/formats/files/transformFormat.js +8 -2
  59. package/dist/formats/files/transformFormat.js.map +1 -1
  60. package/dist/formats/json/extractJson.js +3 -3
  61. package/dist/formats/json/extractJson.js.map +1 -1
  62. package/dist/formats/json/mergeJson.js +6 -6
  63. package/dist/formats/json/mergeJson.js.map +1 -1
  64. package/dist/formats/xcstrings/mergeXcstrings.js +2 -2
  65. package/dist/formats/xcstrings/mergeXcstrings.js.map +1 -1
  66. package/dist/generated/version.d.ts +1 -1
  67. package/dist/generated/version.js +1 -1
  68. package/dist/generated/version.js.map +1 -1
  69. package/dist/git/setupMergeDrivers.js +1 -1
  70. package/dist/git/setupMergeDrivers.js.map +1 -1
  71. package/dist/index.js +2 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/main.js +2 -10
  74. package/dist/main.js.map +1 -1
  75. package/dist/react/jsx/utils/jsxParsing/addGTIdentifierToSyntaxTree.js +1 -1
  76. package/dist/react/jsx/utils/jsxParsing/parseJsx.js +1 -1
  77. package/dist/react/jsx/utils/parseString.js +1 -1
  78. package/dist/react/jsx/utils/stringParsing/derivation/index.js +1 -1
  79. package/dist/setup/developmentCredentials.d.ts +8 -0
  80. package/dist/setup/developmentCredentials.js +82 -0
  81. package/dist/setup/developmentCredentials.js.map +1 -0
  82. package/dist/setup/setupViteSPA.js +1 -1
  83. package/dist/setup/setupViteSPA.js.map +1 -1
  84. package/dist/setup/userInput.d.ts +1 -0
  85. package/dist/setup/userInput.js +7 -2
  86. package/dist/setup/userInput.js.map +1 -1
  87. package/dist/translation/extractInline.js +1 -1
  88. package/dist/translation/extractInline.js.map +1 -1
  89. package/dist/types/index.d.ts +4 -1
  90. package/dist/utils/api.d.ts +146 -67
  91. package/dist/utils/api.js +5 -94
  92. package/dist/utils/api.js.map +1 -1
  93. package/dist/utils/credentials.d.ts +37 -10
  94. package/dist/utils/credentials.js +267 -58
  95. package/dist/utils/credentials.js.map +1 -1
  96. package/dist/utils/loadEnv.d.ts +2 -0
  97. package/dist/utils/loadEnv.js +24 -0
  98. package/dist/utils/loadEnv.js.map +1 -0
  99. package/dist/utils/reactPackageCompatibility.js +1 -1
  100. package/dist/utils/reactPackageCompatibility.js.map +1 -1
  101. package/dist/workflows/steps/PollJobsStep.js +40 -53
  102. package/dist/workflows/steps/PollJobsStep.js.map +1 -1
  103. package/dist/workflows/utils/syncFonts.js +2 -2
  104. package/dist/workflows/utils/syncFonts.js.map +1 -1
  105. package/package.json +8 -7
  106. package/dist/next/config/parseNextConfig.d.ts +0 -10
  107. package/dist/next/config/parseNextConfig.js +0 -34
  108. package/dist/next/config/parseNextConfig.js.map +0 -1
  109. package/dist/utils/fetch.d.ts +0 -11
  110. package/dist/utils/fetch.js +0 -24
  111. package/dist/utils/fetch.js.map +0 -1
  112. package/dist/utils/gt.d.ts +0 -2
  113. package/dist/utils/gt.js +0 -7
  114. package/dist/utils/gt.js.map +0 -1
package/dist/cli/base.js CHANGED
@@ -8,6 +8,9 @@ import findFilepath from "../fs/findFilepath.js";
8
8
  import { lottieTranslateError } from "../console/index.js";
9
9
  import { loadConfig } from "../fs/config/loadConfig.js";
10
10
  import { FILE_EXT_TO_EXT_LABEL } from "../formats/files/supportedFiles.js";
11
+ import { UserAuthError } from "../auth/errors.js";
12
+ import { hasLogin, login, logout, whoAmI } from "../auth/oauth.js";
13
+ import { resolveConfig } from "../config/resolveConfig.js";
11
14
  import { api } from "../utils/api.js";
12
15
  import { generateSettings } from "../config/generateSettings.js";
13
16
  import { createOrUpdateConfig } from "../fs/config/setupConfig.js";
@@ -16,9 +19,10 @@ import { installPackage } from "../utils/installPackage.js";
16
19
  import { getFrameworkDisplayName, getReactFrameworkLibrary } from "../setup/frameworkUtils.js";
17
20
  import { handleSetupReactCommand } from "../setup/wizard.js";
18
21
  import { getDesiredLocales } from "../setup/userInput.js";
19
- import { areCredentialsSet, retrieveCredentials, setCredentials } from "../utils/credentials.js";
22
+ import { areCredentialsSet } from "../utils/credentials.js";
23
+ import { provisionDevelopmentCredentials } from "../setup/developmentCredentials.js";
20
24
  import { clearWarnings } from "../state/translateWarnings.js";
21
- import { hasValidApiKey, hasValidCredentials, hasValidServiceLocales } from "./commands/utils/validation.js";
25
+ import { hasValidCredentials, hasValidServiceLocales } from "./commands/utils/validation.js";
22
26
  import { upload } from "./commands/upload.js";
23
27
  import { attachSharedFlags, attachTranslateFlags } from "./flags.js";
24
28
  import updateConfig from "../fs/config/updateConfig.js";
@@ -43,8 +47,10 @@ import { handleApiCommand } from "./commands/api.js";
43
47
  import chalk from "chalk";
44
48
  import path from "node:path";
45
49
  import fs from "node:fs";
46
- import { createDiagnosticMessage, formatDiagnosticErrorDetails } from "generaltranslation/internal";
50
+ import { createDiagnosticMessage, formatDiagnosticErrorDetails } from "generaltranslation/diagnostics";
51
+ import { ProjectApiKeyPermission } from "generaltranslation/api";
47
52
  import { manifestDirectlyDeclaresGTVue } from "@generaltranslation/vue-extractor/integration";
53
+ import { InvalidArgumentError, Option } from "commander";
48
54
  //#region src/cli/base.ts
49
55
  const ID_COMPATIBILITY_WARNING_COMMANDS = new Set([
50
56
  "download",
@@ -70,12 +76,47 @@ function createProjectCommandError(whatHappened, error) {
70
76
  details: formatDiagnosticErrorDetails(error)
71
77
  });
72
78
  }
79
+ const emptyApiKeyNameError = createDiagnosticMessage({
80
+ whatHappened: "The key name cannot be empty",
81
+ fix: "Pass a non-empty value with --name"
82
+ });
83
+ function parseApiKeyName(value) {
84
+ const name = value.trim();
85
+ if (!name) throw new InvalidArgumentError(emptyApiKeyNameError);
86
+ return name;
87
+ }
73
88
  const electronSetupError = createDiagnosticMessage({
74
89
  source: "gt",
75
90
  severity: "Error",
76
91
  whatHappened: "The automatic setup wizard is not ready for Electron applications",
77
92
  docsUrl: "https://generaltranslation.com/docs/react"
78
93
  });
94
+ /** .env.local never reaches production; the runtime key there is set on the host. */
95
+ function productionRuntimeKeyGuidance(dashboardUrl) {
96
+ return `${chalk.dim("For runtime translation in production, create an API key in the dashboard")} ${chalk.cyan(dashboardUrl)} ${chalk.dim("and set GT_API_KEY and GT_PROJECT_ID in your hosting environment.")}`;
97
+ }
98
+ async function loginInteractively(baseUrl, useBrowser = true) {
99
+ await login({
100
+ baseUrl,
101
+ noBrowser: !useBrowser,
102
+ onDeviceCode: ({ userCode, verificationUri, verificationUriComplete }) => {
103
+ logger.message(`${useBrowser ? "Opening your browser. If it does not open, on any device visit" : "On any device, visit"} ${chalk.cyan(verificationUriComplete ?? verificationUri)} and ${verificationUriComplete ? "confirm" : "enter"} the code ${chalk.bold(userCode)}\nWaiting for approval...`);
104
+ },
105
+ onAuthorizationUrl: (url) => {
106
+ logger.message(`Opening your browser to sign in. If it does not open, visit:\n${chalk.cyan(url)}`);
107
+ }
108
+ });
109
+ }
110
+ function createUserAuthError(whatHappened, error) {
111
+ if (error instanceof UserAuthError) return error.message;
112
+ return createDiagnosticMessage({
113
+ source: "gt",
114
+ severity: "Error",
115
+ whatHappened,
116
+ details: formatDiagnosticErrorDetails(error),
117
+ fix: "Run `gt login` and try again"
118
+ });
119
+ }
79
120
  async function exitIfUnsupportedSetupTarget() {
80
121
  const packageJson = await searchForPackageJson();
81
122
  if (packageJson && isPackageInstalled("electron", packageJson, false, true)) logErrorAndExit(electronSetupError);
@@ -92,6 +133,9 @@ var BaseCLI = class {
92
133
  this.program.option("--skip-version-check", "Skip the monorepo GT package version consistency check");
93
134
  this.program.option("--suppress-id-compatibility-warning", "Suppress the React package ID compatibility warning");
94
135
  this.program.option("-q, --quiet", "Suppress informational output; only warnings and errors are shown");
136
+ this.program.hook("preAction", (_thisCommand, actionCommand) => {
137
+ logger.setConsoleOutput(actionCommand.parent?.name() === "api-key" ? "stderr" : "stdout");
138
+ });
95
139
  this.program.hook("preAction", () => {
96
140
  logger.setQuiet(Boolean(this.program.opts().quiet));
97
141
  });
@@ -103,10 +147,11 @@ var BaseCLI = class {
103
147
  this.setupInitCommand();
104
148
  this.setupConfigureCommand();
105
149
  this.setupUploadCommand();
106
- this.setupLoginCommand();
150
+ this.setupUserAuthCommands();
107
151
  this.setupSendDiffsCommand();
108
152
  this.setupApiCommand();
109
153
  this.setupProjectCommands();
154
+ this.setupApiKeyCommands();
110
155
  this.setupGitCommand();
111
156
  }
112
157
  init() {
@@ -180,8 +225,7 @@ var BaseCLI = class {
180
225
  const projectCommand = this.program.command("project").description("Manage General Translation projects");
181
226
  attachSharedFlags(projectCommand.command("create").description("Create a General Translation project using an organization API key").requiredOption("--org-id <orgId>", "Organization ID").requiredOption("--name <name>", "Project name").requiredOption("--default-locale <locale>", "Project default locale").option("--cdn-enabled", "Enable CDN delivery", false)).action(async (options) => {
182
227
  try {
183
- const settings = await generateSettings(options);
184
- if (!hasValidApiKey(settings) || !hasValidServiceLocales(settings)) return exitSync(1);
228
+ if (!hasValidServiceLocales(await generateSettings(options))) return exitSync(1);
185
229
  const { project } = await api.createProject(options.orgId, {
186
230
  name: options.name,
187
231
  defaultLocale: options.defaultLocale,
@@ -202,6 +246,21 @@ var BaseCLI = class {
202
246
  }
203
247
  });
204
248
  }
249
+ setupApiKeyCommands() {
250
+ attachSharedFlags(this.program.command("api-key").description("Manage API keys for the configured project").command("create").description("Create a project API key with the requested permissions and print it once").requiredOption("--name <name>", "Key name", parseApiKeyName).addOption(new Option("--permission <permissions...>", "Permissions to grant").choices(Object.values(ProjectApiKeyPermission)).makeOptionMandatory())).action(async (options) => {
251
+ try {
252
+ const settings = await generateSettings(options);
253
+ if (!hasValidCredentials(settings)) return exitSync(1);
254
+ const { apiKey } = await api.createProjectApiKey(settings.projectId, {
255
+ name: options.name,
256
+ permissions: options.permission
257
+ });
258
+ process.stdout.write(`${apiKey.key}\n`);
259
+ } catch (error) {
260
+ return logErrorAndExit(error instanceof UserAuthError ? error.message : createProjectCommandError("Failed to create the API key", error));
261
+ }
262
+ });
263
+ }
205
264
  setupGitCommand() {
206
265
  const gitCommand = this.program.command("git").description("Configure Git integrations for General Translation");
207
266
  gitCommand.command("setup").description("Set up GT merge drivers for generated translation files").option("-c, --config <path>", "Filepath to config file, by default gt.config.json", findFilepath(["gt.config.json"])).option("--dry-run", "Print changes without writing files", false).option("--omit-config-ids", "Persist omitConfigIds and remove generated config IDs").option("--driver-command <command>", "Command Git should use to invoke gt, e.g. \"pnpm exec gt\"").action(async (options) => {
@@ -300,30 +359,32 @@ var BaseCLI = class {
300
359
  logger.endCommand("Done!");
301
360
  });
302
361
  }
303
- setupLoginCommand() {
304
- this.program.command("auth").description("Generate General Translation API keys and project ID").option("-c, --config <path>", "Filepath to config file, by default gt.config.json", findFilepath(["gt.config.json"])).option("-t, --key-type <type>", "Type of key to generate, production | development | all").action(async (options) => {
305
- displayHeader("Authenticating with General Translation...");
306
- if (!options.keyType) options.keyType = await promptSelect({
307
- message: "What type of API key would you like to generate?",
308
- options: [
309
- {
310
- value: "development",
311
- label: "Development"
312
- },
313
- {
314
- value: "production",
315
- label: "Production"
316
- },
317
- {
318
- value: "all",
319
- label: "Both"
320
- }
321
- ],
322
- defaultValue: "all"
323
- });
324
- else if (options.keyType !== "development" && options.keyType !== "production" && options.keyType !== "all") logErrorAndExit("Invalid key type, must be development, production, or all");
325
- await this.handleLoginCommand(options);
326
- logger.endCommand(`Done! ${options.keyType} keys have been generated and saved to your .env.local file.`);
362
+ setupUserAuthCommands() {
363
+ this.program.command("login").description("Sign in to your General Translation account").option("--no-browser", "Do not open a browser; show a sign-in URL to use on any device instead").action(async (options) => {
364
+ displayHeader("Signing in to General Translation...");
365
+ try {
366
+ const baseUrl = resolveConfig(process.cwd())?.config.baseUrl;
367
+ await loginInteractively(typeof baseUrl === "string" ? baseUrl : void 0, options.browser);
368
+ logger.endCommand("Signed in successfully.");
369
+ } catch (error) {
370
+ logErrorAndExit(createUserAuthError("Sign in failed", error));
371
+ }
372
+ });
373
+ this.program.command("logout").description("Sign out of your General Translation account").action(async () => {
374
+ try {
375
+ await logout();
376
+ logger.endCommand("Signed out successfully.");
377
+ } catch (error) {
378
+ logErrorAndExit(createUserAuthError("Sign out failed", error));
379
+ }
380
+ });
381
+ this.program.command("whoami").description("Show the signed-in General Translation account").action(async () => {
382
+ try {
383
+ const user = await whoAmI();
384
+ logger.message(user.email ?? user.name ?? user.sub);
385
+ } catch (error) {
386
+ logErrorAndExit(createUserAuthError("Could not load your account", error));
387
+ }
327
388
  });
328
389
  }
329
390
  setupInitCommand() {
@@ -367,7 +428,7 @@ var BaseCLI = class {
367
428
  }
368
429
  }
369
430
  if (ranReactSetup) logger.startCommand("Setting up project config...");
370
- await this.handleInitCommand(ranReactSetup, useDefaults, framework.name === "vite");
431
+ await this.handleInitCommand(ranReactSetup, useDefaults, framework.name === "vite", options, framework.name);
371
432
  logger.endCommand("Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs");
372
433
  }
373
434
  });
@@ -421,7 +482,7 @@ Configure createGT({ loadTranslations }) to load files from that directory.
421
482
  See https://www.npmjs.com/package/gt-vue`);
422
483
  return guidance.length > 0 ? guidance.join("\n") : void 0;
423
484
  }
424
- async handleInitCommand(ranReactSetup, useDefaults = false, isVite = false, options) {
485
+ async handleInitCommand(ranReactSetup, useDefaults = false, isVite = false, options, framework) {
425
486
  const configFilepath = options?.config || (!isVite && fs.existsSync("src/gt.config.json") ? "src/gt.config.json" : "gt.config.json");
426
487
  const { defaultLocale, locales } = await getDesiredLocales(loadConfig(configFilepath));
427
488
  const packageJson = await searchForPackageJson();
@@ -527,37 +588,35 @@ See https://www.npmjs.com/package/gt-vue`);
527
588
  await installPackage("gt", packageManager, true);
528
589
  spinner.stop(chalk.green("Installed gt."));
529
590
  }
530
- if ((!isVite || !isUsingGT || usingCDN) && !areCredentialsSet()) {
531
- if (useDefaults ? true : await promptConfirm({
532
- message: "Would you like the wizard to automatically generate API keys and a project ID for you?",
533
- defaultValue: true
534
- })) {
535
- const settings = await generateSettings({});
536
- await setCredentials(await retrieveCredentials(settings, useDefaults ? "all" : await promptSelect({
537
- message: "What type of API key would you like to generate?",
538
- options: [
539
- {
540
- value: "development",
541
- label: "Development"
542
- },
543
- {
544
- value: "production",
545
- label: "Production"
546
- },
547
- {
548
- value: "all",
549
- label: "Both"
550
- }
551
- ],
552
- defaultValue: "all"
553
- })), isVite ? "vite" : settings.framework);
591
+ const localVite = isVite && isUsingGT && !usingCDN;
592
+ const enableLiveTranslations = localVite && await promptConfirm({
593
+ message: "Would you like to set up live development translations? This requires signing in or an API key.",
594
+ defaultValue: false
595
+ });
596
+ if (!localVite || enableLiveTranslations) {
597
+ const settings = await generateSettings({ config: configFilepath });
598
+ const envFramework = framework ?? (isVite ? "vite" : settings.framework);
599
+ if (!settings.apiKey && !await hasLogin({ baseUrl: settings.baseUrl })) try {
600
+ await loginInteractively(settings.baseUrl);
601
+ logger.message("Signed in successfully.");
602
+ } catch (error) {
603
+ logErrorAndExit(createUserAuthError("Sign in failed", error));
604
+ }
605
+ if (!areCredentialsSet(settings, envFramework)) {
606
+ if (useDefaults || enableLiveTranslations ? true : await promptConfirm({
607
+ message: "Would you like to set up a project ID and hot-reload key in .env.local?",
608
+ defaultValue: true
609
+ })) {
610
+ try {
611
+ await provisionDevelopmentCredentials(settings, envFramework);
612
+ } catch (error) {
613
+ logErrorAndExit(error instanceof UserAuthError ? error.message : createProjectCommandError("Failed to set up the development credentials", error));
614
+ }
615
+ logger.message(productionRuntimeKeyGuidance(settings.dashboardUrl));
616
+ }
554
617
  }
555
618
  }
556
619
  }
557
- async handleLoginCommand(options) {
558
- const settings = await generateSettings({ config: options.config });
559
- await setCredentials(await retrieveCredentials(settings, options.keyType || "all"), settings.framework);
560
- }
561
620
  };
562
621
  //#endregion
563
622
  export { BaseCLI };
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command } from 'commander';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { lottieTranslateError } from '../console/index.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { retrieveCredentials, setCredentials } from '../utils/credentials.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport {\n hasValidApiKey,\n hasValidCredentials,\n hasValidServiceLocales,\n} from './commands/utils/validation.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES, Libraries } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\nimport {\n createDiagnosticMessage,\n formatDiagnosticErrorDetails,\n} from 'generaltranslation/internal';\nimport { setupViteSPA } from '../setup/setupViteSPA.js';\nimport { manifestDirectlyDeclaresGTVue } from '@generaltranslation/vue-extractor/integration';\nimport { api } from '../utils/api.js';\nimport { handleApiCommand, type ApiCommandOptions } from './commands/api.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\nconst workspaceRootSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The setup wizard cannot run from a monorepo workspace root',\n why: 'GT must be configured in the specific app you want to localize',\n fix: \"Change to that app's directory and rerun `npx gt@latest`\",\n});\nfunction createProjectCommandError(\n whatHappened: string,\n error: unknown\n): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened,\n details: formatDiagnosticErrorDetails(error),\n });\n}\n\nconst electronSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened:\n 'The automatic setup wizard is not ready for Electron applications',\n docsUrl: 'https://generaltranslation.com/docs/react',\n});\n\nasync function exitIfUnsupportedSetupTarget(): Promise<void> {\n const packageJson = await searchForPackageJson();\n if (packageJson && isPackageInstalled('electron', packageJson, false, true)) {\n logErrorAndExit(electronSetupError);\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'pnpm-workspace.yaml')) ||\n packageJson?.workspaces\n ) {\n logErrorAndExit(workspaceRootSetupError);\n }\n}\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type LoginOptions = {\n config?: string;\n keyType?: 'development' | 'production' | 'all';\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\ntype LocalTranslationGuidanceOptions = {\n generatedLoader: boolean;\n runtimeSetup: InlineRuntimeSetup;\n translationsDir: string;\n};\n\ntype InlineRuntimeSetup = {\n hasOtherInlineRuntime: boolean;\n hasVueRuntime: boolean;\n ranReactSetup: boolean;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.option(\n '-q, --quiet',\n 'Suppress informational output; only warnings and errors are shown'\n );\n // Apply --quiet before any other hook or command action runs so the\n // singleton logger is muted for the rest of the invocation. The flag is a\n // global root option, so commander resolves it in any position and for\n // nested commands (e.g. `gt git setup --quiet`).\n this.program.hook('preAction', () => {\n logger.setQuiet(Boolean(this.program.opts().quiet));\n });\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupLoginCommand();\n this.setupSendDiffsCommand();\n this.setupApiCommand();\n this.setupProjectCommands();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n if (!hasValidCredentials(settings) || !hasValidServiceLocales(settings))\n return exitSync(1);\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupApiCommand(): void {\n attachSharedFlags(\n this.program\n .command('api [endpoint]')\n .description('Make an authenticated request to the GT API')\n .option('-X, --method <method>', 'HTTP method', 'GET')\n .option('--input <file>', 'Request body file, or - for standard input')\n .option(\n '-H, --header <header>',\n 'Request header in \"Key: Value\" format',\n (header, headers: string[] | undefined) => [\n ...(headers ?? []),\n header,\n ]\n )\n .option('-i, --include', 'Include response status and headers')\n .option('--spec', 'Print the bundled OpenAPI specification')\n ).action((endpoint, options: ApiCommandOptions) =>\n handleApiCommand(endpoint, options)\n );\n }\n\n protected setupProjectCommands(): void {\n const projectCommand = this.program\n .command('project')\n .description('Manage General Translation projects');\n\n attachSharedFlags(\n projectCommand\n .command('create')\n .description(\n 'Create a General Translation project using an organization API key'\n )\n .requiredOption('--org-id <orgId>', 'Organization ID')\n .requiredOption('--name <name>', 'Project name')\n .requiredOption('--default-locale <locale>', 'Project default locale')\n .option('--cdn-enabled', 'Enable CDN delivery', false)\n ).action(async (options) => {\n try {\n const settings = await generateSettings(options);\n // Project creation uses an organization key before a project ID exists.\n if (!hasValidApiKey(settings) || !hasValidServiceLocales(settings))\n return exitSync(1);\n const { project } = await api.createProject(options.orgId, {\n name: options.name,\n defaultLocale: options.defaultLocale,\n cdnEnabled: options.cdnEnabled,\n });\n logger.info(`Created ${project.name} (${project.id})`);\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError('Failed to create the project', error)\n );\n }\n });\n\n attachSharedFlags(\n projectCommand\n .command('status')\n .description('Check the status of a project setup job')\n .argument('<job-id>', 'Setup job ID')\n ).action(async (jobId, options) => {\n try {\n const settings = await generateSettings(options);\n if (!hasValidCredentials(settings)) return exitSync(1);\n const [status] = await api.checkJobStatus([jobId]);\n logger.info(status?.status ?? 'unknown');\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError(\n 'Failed to check the project setup status',\n error\n )\n );\n }\n });\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(driver, base, ours, theirs);\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Lottie translations finish asynchronously server-side (layout\n // refinement runs after the translation job completes), so the immediate\n // translate flow would try to download them before they're ready. Only\n // the stage + download flow supports them.\n if (settings.files?.resolvedPaths.lottie?.length) {\n return logErrorAndExit(lottieTranslateError);\n }\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap,\n results.inlineLibrary\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupLoginCommand(): void {\n this.program\n .command('auth')\n .description('Generate General Translation API keys and project ID')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option(\n '-t, --key-type <type>',\n 'Type of key to generate, production | development | all'\n )\n .action(async (options: LoginOptions) => {\n displayHeader('Authenticating with General Translation...');\n if (!options.keyType) {\n options.keyType = await promptSelect<\n 'development' | 'production' | 'all'\n >({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n } else {\n if (\n options.keyType !== 'development' &&\n options.keyType !== 'production' &&\n options.keyType !== 'all'\n ) {\n logErrorAndExit(\n 'Invalid key type, must be development, production, or all'\n );\n }\n }\n await this.handleLoginCommand(options);\n logger.endCommand(\n `Done! ${options.keyType} keys have been generated and saved to your .env.local file.`\n );\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n await exitIfUnsupportedSetupTarget();\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.name === 'vite'\n ? `${library} & initializeGTSPA, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message:\n framework.name === 'vite'\n ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite'\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(() => this.handleConfigureCommand());\n }\n\n protected async handleConfigureCommand(\n options?: SetupOptions\n ): Promise<void> {\n await exitIfUnsupportedSetupTarget();\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(\n false,\n false,\n framework.name === 'vite',\n options\n );\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n /** Describes installed runtimes without changing historical package lookup. */\n protected getInlineRuntimeSetup(\n packageJson: Record<string, unknown>,\n ranReactSetup: boolean = false\n ): InlineRuntimeSetup {\n return {\n hasOtherInlineRuntime: INLINE_LIBRARIES.some(\n (lib) =>\n lib !== Libraries.GT_VUE && isPackageInstalled(lib, packageJson)\n ),\n hasVueRuntime: manifestDirectlyDeclaresGTVue(packageJson),\n ranReactSetup,\n };\n }\n\n /** Returns whether any inline runtime is installed for setup. */\n protected isInlineRuntimeInstalled(\n packageJson: Record<string, unknown>\n ): boolean {\n const { hasOtherInlineRuntime, hasVueRuntime } =\n this.getInlineRuntimeSetup(packageJson);\n return hasOtherInlineRuntime || hasVueRuntime;\n }\n\n /** Returns whether every installed runtime can consume CDN translations. */\n protected supportsCDNStorage(runtimeSetup: InlineRuntimeSetup): boolean {\n return !runtimeSetup.hasVueRuntime;\n }\n\n /** Returns whether setup should generate a local runtime loader. */\n protected shouldGenerateLocalTranslationLoader(\n isVite: boolean,\n runtimeSetup: InlineRuntimeSetup\n ): boolean {\n if (isVite) return false;\n if (!runtimeSetup.hasVueRuntime) return true;\n return runtimeSetup.hasOtherInlineRuntime || runtimeSetup.ranReactSetup;\n }\n\n /** Returns framework guidance after selecting local translation storage. */\n protected getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir,\n }: LocalTranslationGuidanceOptions): string | undefined {\n const guidance: string[] = [];\n if (generatedLoader) {\n guidance.push(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`);\n }\n if (runtimeSetup.hasVueRuntime) {\n guidance.push(`GT will write local translation files to ${translationsDir}.\nConfigure createGT({ loadTranslations }) to load files from that directory.\nSee https://www.npmjs.com/package/gt-vue`);\n }\n return guidance.length > 0 ? guidance.join('\\n') : undefined;\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false,\n options?: SetupOptions\n ): Promise<void> {\n const configFilepath =\n options?.config ||\n (!isVite && fs.existsSync('src/gt.config.json')\n ? 'src/gt.config.json'\n : 'gt.config.json');\n const existingConfig = loadConfig(configFilepath);\n const { defaultLocale, locales } = await getDesiredLocales(existingConfig);\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const runtimeSetup: InlineRuntimeSetup = packageJson\n ? this.getInlineRuntimeSetup(packageJson, ranReactSetup)\n : {\n hasOtherInlineRuntime: false,\n hasVueRuntime: false,\n ranReactSetup,\n };\n const isUsingGT =\n runtimeSetup.ranReactSetup ||\n runtimeSetup.hasOtherInlineRuntime ||\n runtimeSetup.hasVueRuntime;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n if (!this.supportsCDNStorage(runtimeSetup)) return false;\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n const generatedLoader = this.shouldGenerateLocalTranslationLoader(\n isVite,\n runtimeSetup\n );\n if (generatedLoader) {\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n }\n const guidance = this.getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir: finalTranslationsDir,\n });\n if (guidance) logger.message(guidance);\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n src: options?.src,\n files: Object.keys(files).length > 0 ? files : undefined,\n framework: isVite ? 'vite' : undefined,\n publish: isUsingGT && usingCDN,\n clearPublish: runtimeSetup.hasVueRuntime && !usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n if (ranReactSetup && isVite) {\n await setupViteSPA({\n appDirectory: process.cwd(),\n configFilepath,\n defaultLocale,\n locales,\n translationsDir: usingCDN ? undefined : finalTranslationsDir,\n });\n }\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled && !(isUsingGT && isVite)) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n // Set credentials\n if ((!isVite || !isUsingGT || usingCDN) && !areCredentialsSet()) {\n const loginQuestion = useDefaults\n ? true\n : await promptConfirm({\n message:\n 'Would you like the wizard to automatically generate API keys and a project ID for you?',\n defaultValue: true,\n });\n if (loginQuestion) {\n const settings = await generateSettings({});\n const keyType = useDefaults\n ? 'all'\n : await promptSelect<'development' | 'production' | 'all'>({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, isVite ? 'vite' : settings.framework);\n }\n }\n }\n protected async handleLoginCommand(options: LoginOptions): Promise<void> {\n const settings = await generateSettings({ config: options.config });\n const keyType = options.keyType || 'all';\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command, InvalidArgumentError, Option } from 'commander';\nimport { ProjectApiKeyPermission } from 'generaltranslation/api';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { lottieTranslateError } from '../console/index.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedFrameworks,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { provisionDevelopmentCredentials } from '../setup/developmentCredentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { loadConfig } from '../fs/config/loadConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport {\n hasValidCredentials,\n hasValidServiceLocales,\n} from './commands/utils/validation.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES, Libraries } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\nimport {\n createDiagnosticMessage,\n formatDiagnosticErrorDetails,\n} from 'generaltranslation/diagnostics';\nimport { hasLogin, login, logout, whoAmI } from '../auth/oauth.js';\nimport { UserAuthError } from '../auth/errors.js';\nimport { resolveConfig } from '../config/resolveConfig.js';\nimport { setupViteSPA } from '../setup/setupViteSPA.js';\nimport { manifestDirectlyDeclaresGTVue } from '@generaltranslation/vue-extractor/integration';\nimport { api } from '../utils/api.js';\nimport { handleApiCommand, type ApiCommandOptions } from './commands/api.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\nconst workspaceRootSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened: 'The setup wizard cannot run from a monorepo workspace root',\n why: 'GT must be configured in the specific app you want to localize',\n fix: \"Change to that app's directory and rerun `npx gt@latest`\",\n});\nfunction createProjectCommandError(\n whatHappened: string,\n error: unknown\n): string {\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened,\n details: formatDiagnosticErrorDetails(error),\n });\n}\n\nconst emptyApiKeyNameError = createDiagnosticMessage({\n whatHappened: 'The key name cannot be empty',\n fix: 'Pass a non-empty value with --name',\n});\n\nfunction parseApiKeyName(value: string): string {\n const name = value.trim();\n if (!name) throw new InvalidArgumentError(emptyApiKeyNameError);\n return name;\n}\n\nconst electronSetupError = createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened:\n 'The automatic setup wizard is not ready for Electron applications',\n docsUrl: 'https://generaltranslation.com/docs/react',\n});\n\n/** .env.local never reaches production; the runtime key there is set on the host. */\nfunction productionRuntimeKeyGuidance(dashboardUrl: string): string {\n return `${chalk.dim('For runtime translation in production, create an API key in the dashboard')} ${chalk.cyan(dashboardUrl)} ${chalk.dim('and set GT_API_KEY and GT_PROJECT_ID in your hosting environment.')}`;\n}\n\nasync function loginInteractively(\n baseUrl: string | undefined,\n useBrowser = true\n): Promise<void> {\n await login({\n baseUrl,\n noBrowser: !useBrowser,\n onDeviceCode: ({ userCode, verificationUri, verificationUriComplete }) => {\n logger.message(\n `${useBrowser ? 'Opening your browser. If it does not open, on any device visit' : 'On any device, visit'} ${chalk.cyan(verificationUriComplete ?? verificationUri)} and ${verificationUriComplete ? 'confirm' : 'enter'} the code ${chalk.bold(userCode)}\\nWaiting for approval...`\n );\n },\n onAuthorizationUrl: (url) => {\n logger.message(\n `Opening your browser to sign in. If it does not open, visit:\\n${chalk.cyan(url)}`\n );\n },\n });\n}\n\nfunction createUserAuthError(whatHappened: string, error: unknown): string {\n if (error instanceof UserAuthError) return error.message;\n return createDiagnosticMessage({\n source: 'gt',\n severity: 'Error',\n whatHappened,\n details: formatDiagnosticErrorDetails(error),\n fix: 'Run `gt login` and try again',\n });\n}\n\nasync function exitIfUnsupportedSetupTarget(): Promise<void> {\n const packageJson = await searchForPackageJson();\n if (packageJson && isPackageInstalled('electron', packageJson, false, true)) {\n logErrorAndExit(electronSetupError);\n }\n if (\n fs.existsSync(path.join(process.cwd(), 'pnpm-workspace.yaml')) ||\n packageJson?.workspaces\n ) {\n logErrorAndExit(workspaceRootSetupError);\n }\n}\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\ntype LocalTranslationGuidanceOptions = {\n generatedLoader: boolean;\n runtimeSetup: InlineRuntimeSetup;\n translationsDir: string;\n};\n\ntype InlineRuntimeSetup = {\n hasOtherInlineRuntime: boolean;\n hasVueRuntime: boolean;\n ranReactSetup: boolean;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.option(\n '-q, --quiet',\n 'Suppress informational output; only warnings and errors are shown'\n );\n // Select console routing for this command before anything else logs:\n // root hooks run before subclass hooks (version checks) and the action's\n // settings resolution. `gt api-key create` prints the new secret on\n // stdout, so its diagnostics go to stderr; every other command gets the\n // historical default back (main() routes startup output to stderr).\n this.program.hook('preAction', (_thisCommand, actionCommand) => {\n logger.setConsoleOutput(\n actionCommand.parent?.name() === 'api-key' ? 'stderr' : 'stdout'\n );\n });\n // Apply --quiet before any other hook or command action runs so the\n // singleton logger is muted for the rest of the invocation. The flag is a\n // global root option, so commander resolves it in any position and for\n // nested commands (e.g. `gt git setup --quiet`).\n this.program.hook('preAction', () => {\n logger.setQuiet(Boolean(this.program.opts().quiet));\n });\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupUserAuthCommands();\n this.setupSendDiffsCommand();\n this.setupApiCommand();\n this.setupProjectCommands();\n this.setupApiKeyCommands();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n if (!hasValidCredentials(settings) || !hasValidServiceLocales(settings))\n return exitSync(1);\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupApiCommand(): void {\n attachSharedFlags(\n this.program\n .command('api [endpoint]')\n .description('Make an authenticated request to the GT API')\n .option('-X, --method <method>', 'HTTP method', 'GET')\n .option('--input <file>', 'Request body file, or - for standard input')\n .option(\n '-H, --header <header>',\n 'Request header in \"Key: Value\" format',\n (header, headers: string[] | undefined) => [\n ...(headers ?? []),\n header,\n ]\n )\n .option('-i, --include', 'Include response status and headers')\n .option('--spec', 'Print the bundled OpenAPI specification')\n ).action((endpoint, options: ApiCommandOptions) =>\n handleApiCommand(endpoint, options)\n );\n }\n\n protected setupProjectCommands(): void {\n const projectCommand = this.program\n .command('project')\n .description('Manage General Translation projects');\n\n attachSharedFlags(\n projectCommand\n .command('create')\n .description(\n 'Create a General Translation project using an organization API key'\n )\n .requiredOption('--org-id <orgId>', 'Organization ID')\n .requiredOption('--name <name>', 'Project name')\n .requiredOption('--default-locale <locale>', 'Project default locale')\n .option('--cdn-enabled', 'Enable CDN delivery', false)\n ).action(async (options) => {\n try {\n const settings = await generateSettings(options);\n // Project creation happens before a project ID exists.\n if (!hasValidServiceLocales(settings)) return exitSync(1);\n const { project } = await api.createProject(options.orgId, {\n name: options.name,\n defaultLocale: options.defaultLocale,\n cdnEnabled: options.cdnEnabled,\n });\n logger.info(`Created ${project.name} (${project.id})`);\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError('Failed to create the project', error)\n );\n }\n });\n\n attachSharedFlags(\n projectCommand\n .command('status')\n .description('Check the status of a project setup job')\n .argument('<job-id>', 'Setup job ID')\n ).action(async (jobId, options) => {\n try {\n const settings = await generateSettings(options);\n if (!hasValidCredentials(settings)) return exitSync(1);\n const [status] = await api.checkJobStatus([jobId]);\n logger.info(status?.status ?? 'unknown');\n } catch (error) {\n return logErrorAndExit(\n createProjectCommandError(\n 'Failed to check the project setup status',\n error\n )\n );\n }\n });\n }\n\n protected setupApiKeyCommands(): void {\n const apiKeyCommand = this.program\n .command('api-key')\n .description('Manage API keys for the configured project');\n\n attachSharedFlags(\n apiKeyCommand\n .command('create')\n .description(\n 'Create a project API key with the requested permissions and print it once'\n )\n .requiredOption('--name <name>', 'Key name', parseApiKeyName)\n // Validated before any request; the server grants the requested set\n // all-or-nothing, so omitting permissions would delegate everything.\n .addOption(\n new Option('--permission <permissions...>', 'Permissions to grant')\n .choices(Object.values(ProjectApiKeyPermission))\n .makeOptionMandatory()\n )\n ).action(\n async (\n options: SharedFlags & {\n name: string;\n permission: ProjectApiKeyPermission[];\n }\n ) => {\n try {\n const settings = await generateSettings(options);\n if (!hasValidCredentials(settings)) return exitSync(1);\n const { apiKey } = await api.createProjectApiKey(settings.projectId, {\n name: options.name,\n permissions: options.permission,\n });\n // Raw stdout: the secret is shown once and never reaches the log file.\n process.stdout.write(`${apiKey.key}\\n`);\n } catch (error) {\n return logErrorAndExit(\n error instanceof UserAuthError\n ? error.message\n : createProjectCommandError('Failed to create the API key', error)\n );\n }\n }\n );\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(driver, base, ours, theirs);\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Lottie translations finish asynchronously server-side (layout\n // refinement runs after the translation job completes), so the immediate\n // translate flow would try to download them before they're ready. Only\n // the stage + download flow supports them.\n if (settings.files?.resolvedPaths.lottie?.length) {\n return logErrorAndExit(lottieTranslateError);\n }\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap,\n results.inlineLibrary\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupUserAuthCommands(): void {\n this.program\n .command('login')\n .description('Sign in to your General Translation account')\n .option(\n '--no-browser',\n 'Do not open a browser; show a sign-in URL to use on any device instead'\n )\n .action(async (options: { browser: boolean }) => {\n displayHeader('Signing in to General Translation...');\n try {\n // Tokens are bound to one API resource, so log in to the configured one.\n const baseUrl = resolveConfig(process.cwd())?.config.baseUrl;\n await loginInteractively(\n typeof baseUrl === 'string' ? baseUrl : undefined,\n options.browser\n );\n logger.endCommand('Signed in successfully.');\n } catch (error) {\n logErrorAndExit(createUserAuthError('Sign in failed', error));\n }\n });\n\n this.program\n .command('logout')\n .description('Sign out of your General Translation account')\n .action(async () => {\n try {\n await logout();\n logger.endCommand('Signed out successfully.');\n } catch (error) {\n logErrorAndExit(createUserAuthError('Sign out failed', error));\n }\n });\n\n this.program\n .command('whoami')\n .description('Show the signed-in General Translation account')\n .action(async () => {\n try {\n const user = await whoAmI();\n logger.message(user.email ?? user.name ?? user.sub);\n } catch (error) {\n logErrorAndExit(\n createUserAuthError('Could not load your account', error)\n );\n }\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n await exitIfUnsupportedSetupTarget();\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.name === 'vite'\n ? `${library} & initializeGTSPA, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message:\n framework.name === 'vite'\n ? `Would you like to install ${library} and configure initializeGTSPA? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n : `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite',\n options,\n framework.name\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(() => this.handleConfigureCommand());\n }\n\n protected async handleConfigureCommand(\n options?: SetupOptions\n ): Promise<void> {\n await exitIfUnsupportedSetupTarget();\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(\n false,\n false,\n framework.name === 'vite',\n options\n );\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n /** Describes installed runtimes without changing historical package lookup. */\n protected getInlineRuntimeSetup(\n packageJson: Record<string, unknown>,\n ranReactSetup: boolean = false\n ): InlineRuntimeSetup {\n return {\n hasOtherInlineRuntime: INLINE_LIBRARIES.some(\n (lib) =>\n lib !== Libraries.GT_VUE && isPackageInstalled(lib, packageJson)\n ),\n hasVueRuntime: manifestDirectlyDeclaresGTVue(packageJson),\n ranReactSetup,\n };\n }\n\n /** Returns whether any inline runtime is installed for setup. */\n protected isInlineRuntimeInstalled(\n packageJson: Record<string, unknown>\n ): boolean {\n const { hasOtherInlineRuntime, hasVueRuntime } =\n this.getInlineRuntimeSetup(packageJson);\n return hasOtherInlineRuntime || hasVueRuntime;\n }\n\n /** Returns whether every installed runtime can consume CDN translations. */\n protected supportsCDNStorage(runtimeSetup: InlineRuntimeSetup): boolean {\n return !runtimeSetup.hasVueRuntime;\n }\n\n /** Returns whether setup should generate a local runtime loader. */\n protected shouldGenerateLocalTranslationLoader(\n isVite: boolean,\n runtimeSetup: InlineRuntimeSetup\n ): boolean {\n if (isVite) return false;\n if (!runtimeSetup.hasVueRuntime) return true;\n return runtimeSetup.hasOtherInlineRuntime || runtimeSetup.ranReactSetup;\n }\n\n /** Returns framework guidance after selecting local translation storage. */\n protected getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir,\n }: LocalTranslationGuidanceOptions): string | undefined {\n const guidance: string[] = [];\n if (generatedLoader) {\n guidance.push(`Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`);\n }\n if (runtimeSetup.hasVueRuntime) {\n guidance.push(`GT will write local translation files to ${translationsDir}.\nConfigure createGT({ loadTranslations }) to load files from that directory.\nSee https://www.npmjs.com/package/gt-vue`);\n }\n return guidance.length > 0 ? guidance.join('\\n') : undefined;\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false,\n options?: SetupOptions,\n framework?: SupportedFrameworks\n ): Promise<void> {\n const configFilepath =\n options?.config ||\n (!isVite && fs.existsSync('src/gt.config.json')\n ? 'src/gt.config.json'\n : 'gt.config.json');\n const existingConfig = loadConfig(configFilepath);\n const { defaultLocale, locales } = await getDesiredLocales(existingConfig);\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const runtimeSetup: InlineRuntimeSetup = packageJson\n ? this.getInlineRuntimeSetup(packageJson, ranReactSetup)\n : {\n hasOtherInlineRuntime: false,\n hasVueRuntime: false,\n ranReactSetup,\n };\n const isUsingGT =\n runtimeSetup.ranReactSetup ||\n runtimeSetup.hasOtherInlineRuntime ||\n runtimeSetup.hasVueRuntime;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n if (!this.supportsCDNStorage(runtimeSetup)) return false;\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n const generatedLoader = this.shouldGenerateLocalTranslationLoader(\n isVite,\n runtimeSetup\n );\n if (generatedLoader) {\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n }\n const guidance = this.getLocalTranslationGuidance({\n generatedLoader,\n runtimeSetup,\n translationsDir: finalTranslationsDir,\n });\n if (guidance) logger.message(guidance);\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n src: options?.src,\n files: Object.keys(files).length > 0 ? files : undefined,\n framework: isVite ? 'vite' : undefined,\n publish: isUsingGT && usingCDN,\n clearPublish: runtimeSetup.hasVueRuntime && !usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n if (ranReactSetup && isVite) {\n await setupViteSPA({\n appDirectory: process.cwd(),\n configFilepath,\n defaultLocale,\n locales,\n translationsDir: usingCDN ? undefined : finalTranslationsDir,\n });\n }\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled && !(isUsingGT && isVite)) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n const localVite = isVite && isUsingGT && !usingCDN;\n const enableLiveTranslations =\n localVite &&\n (await promptConfirm({\n message:\n 'Would you like to set up live development translations? This requires signing in or an API key.',\n defaultValue: false,\n }));\n if (!localVite || enableLiveTranslations) {\n const settings = await generateSettings({ config: configFilepath });\n const envFramework = framework ?? (isVite ? 'vite' : settings.framework);\n // The CLI translates as the signed-in user; an API key in the\n // environment takes precedence and needs no login. A development key in\n // .env.local is runtime-only and never stands in for either.\n if (\n !settings.apiKey &&\n !(await hasLogin({ baseUrl: settings.baseUrl }))\n ) {\n try {\n await loginInteractively(settings.baseUrl);\n logger.message('Signed in successfully.');\n } catch (error) {\n logErrorAndExit(createUserAuthError('Sign in failed', error));\n }\n }\n if (!areCredentialsSet(settings, envFramework)) {\n const provision =\n useDefaults || enableLiveTranslations\n ? true\n : await promptConfirm({\n message:\n 'Would you like to set up a project ID and hot-reload key in .env.local?',\n defaultValue: true,\n });\n if (provision) {\n try {\n await provisionDevelopmentCredentials(settings, envFramework);\n } catch (error) {\n logErrorAndExit(\n error instanceof UserAuthError\n ? error.message\n : createProjectCommandError(\n 'Failed to set up the development credentials',\n error\n )\n );\n }\n logger.message(productionRuntimeKeyGuidance(settings.dashboardUrl));\n }\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  import { exitSync } from "../../console/logging.js";
2
2
  import { loadConfig } from "../../fs/config/loadConfig.js";
3
3
  import { resolveProjectId } from "../../fs/utils.js";
4
+ import { createUserTokenProvider } from "../../auth/oauth.js";
4
5
  import { resolveConfig } from "../../config/resolveConfig.js";
5
6
  import fs from "node:fs";
6
- import { createDiagnosticMessage, defaultBaseUrl, formatDiagnosticErrorDetails } from "generaltranslation/internal";
7
+ import { createDiagnosticMessage, formatDiagnosticErrorDetails } from "generaltranslation/diagnostics";
8
+ import { defaultBaseUrl } from "generaltranslation/internal";
7
9
  import { createApiClient } from "generaltranslation/api";
8
10
  import openApiSpec from "generaltranslation/api/openapi.json" with { type: "json" };
9
11
  //#region src/cli/commands/api.ts
@@ -105,9 +107,11 @@ async function handleApiCommand(endpoint, options, dependencies = {}) {
105
107
  const method = parseMethod(options.method, dependencies);
106
108
  const configPath = options.config?.endsWith(".json") ? options.config : options.config ? `${options.config}.json` : void 0;
107
109
  const config = configPath ? loadConfig(configPath) : resolveConfig(process.cwd())?.config ?? {};
110
+ const baseUrl = typeof config.baseUrl === "string" ? config.baseUrl : defaultBaseUrl;
108
111
  const client = createApiClient({
109
112
  apiKey: options.apiKey ?? process.env.GT_API_KEY,
110
- baseUrl: typeof config.baseUrl === "string" ? config.baseUrl : defaultBaseUrl,
113
+ userTokenProvider: createUserTokenProvider({ baseUrl }),
114
+ baseUrl,
111
115
  fetch: dependencies.fetch,
112
116
  projectId: resolveApiProjectId(config, options.projectId, dependencies),
113
117
  retryPolicy: "none"