@shopify/cli-kit 4.6.0 → 4.7.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 (164) hide show
  1. package/dist/private/node/analytics/bounded-collections.js +1 -4
  2. package/dist/private/node/analytics/bounded-collections.js.map +1 -1
  3. package/dist/private/node/analytics/graphql-error-codes.d.ts +2 -2
  4. package/dist/private/node/analytics/graphql-error-codes.js +2 -2
  5. package/dist/private/node/analytics/graphql-error-codes.js.map +1 -1
  6. package/dist/private/node/analytics.js +12 -7
  7. package/dist/private/node/analytics.js.map +1 -1
  8. package/dist/private/node/api/headers.js +3 -0
  9. package/dist/private/node/api/headers.js.map +1 -1
  10. package/dist/private/node/api.js +8 -8
  11. package/dist/private/node/api.js.map +1 -1
  12. package/dist/private/node/conf-store.js +1 -1
  13. package/dist/private/node/conf-store.js.map +1 -1
  14. package/dist/private/node/content-tokens.js +27 -2
  15. package/dist/private/node/content-tokens.js.map +1 -1
  16. package/dist/private/node/otel-metrics.d.ts +1 -1
  17. package/dist/private/node/otel-metrics.js +5 -2
  18. package/dist/private/node/otel-metrics.js.map +1 -1
  19. package/dist/private/node/plugin-hints.d.ts +16 -0
  20. package/dist/private/node/plugin-hints.js +29 -0
  21. package/dist/private/node/plugin-hints.js.map +1 -0
  22. package/dist/private/node/request-ids.js +2 -3
  23. package/dist/private/node/request-ids.js.map +1 -1
  24. package/dist/private/node/session/device-authorization.js +4 -7
  25. package/dist/private/node/session/device-authorization.js.map +1 -1
  26. package/dist/private/node/session/exchange.d.ts +4 -4
  27. package/dist/private/node/session/exchange.js +21 -5
  28. package/dist/private/node/session/exchange.js.map +1 -1
  29. package/dist/private/node/testing/ui.js +18 -19
  30. package/dist/private/node/testing/ui.js.map +1 -1
  31. package/dist/private/node/ui/components/Alert.d.ts +1 -1
  32. package/dist/private/node/ui/components/Alert.js.map +1 -1
  33. package/dist/private/node/ui/components/ConcurrentOutput.test.js +2 -0
  34. package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
  35. package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +1 -1
  36. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
  37. package/dist/private/node/ui/components/List.d.ts +1 -1
  38. package/dist/private/node/ui/components/List.js.map +1 -1
  39. package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +1 -1
  40. package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -1
  41. package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -1
  42. package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
  43. package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +1 -1
  44. package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
  45. package/dist/private/node/ui/components/SingleTask.test.js +1 -0
  46. package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
  47. package/dist/private/node/ui/components/TabularData.d.ts +1 -1
  48. package/dist/private/node/ui/components/TabularData.js +2 -1
  49. package/dist/private/node/ui/components/TabularData.js.map +1 -1
  50. package/dist/private/node/ui/components/TextPrompt.d.ts +1 -1
  51. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  52. package/dist/private/node/ui/components/TokenizedText.d.ts +1 -38
  53. package/dist/private/node/ui/components/TokenizedText.js +0 -54
  54. package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
  55. package/dist/private/node/ui/components/TokenizedText.test.js +2 -1
  56. package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
  57. package/dist/private/node/ui/components/token-item.d.ts +38 -0
  58. package/dist/private/node/ui/components/token-item.js +63 -0
  59. package/dist/private/node/ui/components/token-item.js.map +1 -0
  60. package/dist/private/node/ui/hooks/use-abort-signal.js +5 -4
  61. package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
  62. package/dist/private/node/ui/hooks/use-select-state.js +2 -1
  63. package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
  64. package/dist/private/node/ui/utilities.d.ts +6 -6
  65. package/dist/private/node/ui/utilities.js +1 -1
  66. package/dist/private/node/ui/utilities.js.map +1 -1
  67. package/dist/private/node/ui.js +18 -15
  68. package/dist/private/node/ui.js.map +1 -1
  69. package/dist/public/common/string.d.ts +1 -1
  70. package/dist/public/common/string.js.map +1 -1
  71. package/dist/public/common/version.d.ts +1 -1
  72. package/dist/public/common/version.js +1 -1
  73. package/dist/public/common/version.js.map +1 -1
  74. package/dist/public/node/abort.d.ts +14 -6
  75. package/dist/public/node/abort.js +7 -6
  76. package/dist/public/node/abort.js.map +1 -1
  77. package/dist/public/node/analytics.d.ts +1 -0
  78. package/dist/public/node/analytics.js +79 -32
  79. package/dist/public/node/analytics.js.map +1 -1
  80. package/dist/public/node/api/admin.js +1 -1
  81. package/dist/public/node/api/admin.js.map +1 -1
  82. package/dist/public/node/base-command.d.ts +10 -0
  83. package/dist/public/node/base-command.js +31 -8
  84. package/dist/public/node/base-command.js.map +1 -1
  85. package/dist/public/node/cli.d.ts +13 -0
  86. package/dist/public/node/cli.js +18 -2
  87. package/dist/public/node/cli.js.map +1 -1
  88. package/dist/public/node/context/local.d.ts +3 -1
  89. package/dist/public/node/context/local.js +14 -7
  90. package/dist/public/node/context/local.js.map +1 -1
  91. package/dist/public/node/custom-oclif-loader.js +19 -16
  92. package/dist/public/node/custom-oclif-loader.js.map +1 -1
  93. package/dist/public/node/doctor/framework.js +4 -5
  94. package/dist/public/node/doctor/framework.js.map +1 -1
  95. package/dist/public/node/environment.js +8 -11
  96. package/dist/public/node/environment.js.map +1 -1
  97. package/dist/public/node/error.d.ts +1 -4
  98. package/dist/public/node/error.js +20 -7
  99. package/dist/public/node/error.js.map +1 -1
  100. package/dist/public/node/git.js +7 -5
  101. package/dist/public/node/git.js.map +1 -1
  102. package/dist/public/node/global-context.js +1 -1
  103. package/dist/public/node/global-context.js.map +1 -1
  104. package/dist/public/node/hidden-folder.js +2 -4
  105. package/dist/public/node/hidden-folder.js.map +1 -1
  106. package/dist/public/node/hooks/postrun.js +1 -1
  107. package/dist/public/node/hooks/postrun.js.map +1 -1
  108. package/dist/public/node/hooks/prerun.js +5 -1
  109. package/dist/public/node/hooks/prerun.js.map +1 -1
  110. package/dist/public/node/local-storage.js +1 -0
  111. package/dist/public/node/local-storage.js.map +1 -1
  112. package/dist/public/node/metadata.d.ts +3 -0
  113. package/dist/public/node/metadata.js.map +1 -1
  114. package/dist/public/node/mimes.js +1 -3
  115. package/dist/public/node/mimes.js.map +1 -1
  116. package/dist/public/node/node-package-manager.js +31 -73
  117. package/dist/public/node/node-package-manager.js.map +1 -1
  118. package/dist/public/node/notifications-system.js +19 -3
  119. package/dist/public/node/notifications-system.js.map +1 -1
  120. package/dist/public/node/os.js +5 -10
  121. package/dist/public/node/os.js.map +1 -1
  122. package/dist/public/node/output.js +11 -20
  123. package/dist/public/node/output.js.map +1 -1
  124. package/dist/public/node/plugins/tunnel.d.ts +1 -2
  125. package/dist/public/node/plugins/tunnel.js +2 -2
  126. package/dist/public/node/plugins/tunnel.js.map +1 -1
  127. package/dist/public/node/result.js +4 -2
  128. package/dist/public/node/result.js.map +1 -1
  129. package/dist/public/node/serial-batch-processor.js +4 -3
  130. package/dist/public/node/serial-batch-processor.js.map +1 -1
  131. package/dist/public/node/store-auth-session.js +1 -1
  132. package/dist/public/node/store-auth-session.js.map +1 -1
  133. package/dist/public/node/system.d.ts +15 -1
  134. package/dist/public/node/system.js +42 -6
  135. package/dist/public/node/system.js.map +1 -1
  136. package/dist/public/node/themes/conf.js +2 -2
  137. package/dist/public/node/themes/conf.js.map +1 -1
  138. package/dist/public/node/themes/factories.js +2 -2
  139. package/dist/public/node/themes/factories.js.map +1 -1
  140. package/dist/public/node/themes/theme-manager.js +2 -0
  141. package/dist/public/node/themes/theme-manager.js.map +1 -1
  142. package/dist/public/node/themes/urls.js +7 -7
  143. package/dist/public/node/themes/urls.js.map +1 -1
  144. package/dist/public/node/toml/toml-file.js +12 -13
  145. package/dist/public/node/toml/toml-file.js.map +1 -1
  146. package/dist/public/node/ui.d.ts +1 -1
  147. package/dist/public/node/ui.js +1 -1
  148. package/dist/public/node/ui.js.map +1 -1
  149. package/dist/public/node/vendor/dev_server/dev-server-2024.js +14 -2
  150. package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
  151. package/dist/public/node/vendor/dev_server/dev-server.js +3 -0
  152. package/dist/public/node/vendor/dev_server/dev-server.js.map +1 -1
  153. package/dist/public/node/vendor/dev_server/network/index.js +1 -1
  154. package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
  155. package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js +1 -0
  156. package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
  157. package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js +5 -2
  158. package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
  159. package/dist/public/node/vendor/otel-js/service/types.d.ts +2 -2
  160. package/dist/public/node/vendor/otel-js/service/types.js.map +1 -1
  161. package/dist/public/node/vscode.js +12 -11
  162. package/dist/public/node/vscode.js.map +1 -1
  163. package/dist/tsconfig.tsbuildinfo +1 -1
  164. package/package.json +3 -9
@@ -1 +1 @@
1
- {"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/framework.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExists, readFile} from '../fs.js'\nimport {isAbsolutePath, joinPath, relativePath} from '../path.js'\nimport {execCommand, captureCommandWithExitCode} from '../system.js'\nimport type {DoctorContext, TestResult, AssertionResult} from './types.js'\n\n/**\n * Result from running a CLI command.\n */\ninterface CommandResult {\n /** The full command that was run. */\n command: string\n /** Exit code (0 = success). */\n exitCode: number\n /** Standard output. */\n stdout: string\n /** Standard error. */\n stderr: string\n /** Combined output (stdout + stderr). */\n output: string\n /** Whether the command succeeded (exitCode === 0). */\n success: boolean\n}\n\n/**\n * A registered test with its name and function.\n */\ninterface RegisteredTest {\n /** The test name. */\n name: string\n /** The async test function. */\n fn: () => Promise<void>\n}\n\n/**\n * Base class for doctor test suites.\n *\n * Write tests using the test() method.\n *\n * ```typescript\n * export default class MyTests extends DoctorSuite {\n * static description = 'My test suite'\n *\n * tests() {\n * this.test('basic case', async () => {\n * const result = await this.run('shopify theme init')\n * this.assertSuccess(result)\n * })\n *\n * this.test('error case', async () => {\n * const result = await this.run('shopify theme init --invalid')\n * this.assertError(result, /unknown flag/)\n * })\n * }\n * }\n * ```\n */\nexport abstract class DoctorSuite<TContext extends DoctorContext = DoctorContext> {\n static description = 'Doctor test suite'\n\n protected context!: TContext\n private assertions: AssertionResult[] = []\n private registeredTests: RegisteredTest[] = []\n\n /**\n * Run the entire test suite.\n *\n * @param context - The doctor context for this suite run.\n * @returns The list of test results.\n */\n async runSuite(context: TContext): Promise<TestResult[]> {\n this.context = context\n this.registeredTests = []\n const results: TestResult[] = []\n\n // Call tests() to register tests via this.test()\n this.tests()\n\n // Run all registered tests\n for (const registeredTest of this.registeredTests) {\n this.assertions = []\n const startTime = Date.now()\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await registeredTest.fn()\n\n results.push({\n name: registeredTest.name,\n status: this.hasFailures() ? 'failed' : 'passed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n results.push({\n name: registeredTest.name,\n status: 'failed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }\n\n return results\n }\n\n /**\n * Register a test with a name and function.\n *\n * @param name - The test name.\n * @param fn - The async test function.\n */\n protected test(name: string, fn: () => Promise<void>): void {\n this.registeredTests.push({name, fn})\n }\n\n /**\n * Override this method to register tests using this.test().\n */\n protected tests(): void {\n // Subclasses override this to register tests\n }\n\n // ============================================\n // Command execution\n // ============================================\n\n /* eslint-disable tsdoc/syntax -- jsdoc/require-param expects dotted names for destructured options; tsdoc disallows dots */\n /**\n * Run a CLI command and return the result.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n * @example\n * const result = await this.run('shopify theme init my-theme')\n * const result = await this.run('shopify theme push --json')\n */\n protected async run(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n const result = await captureCommandWithExitCode(command, {cwd, env: options?.env})\n\n return {\n command,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n output: String(result.stdout) + String(result.stderr),\n success: result.exitCode === 0,\n }\n }\n\n /**\n * Run a command without capturing output (for interactive commands).\n * Returns only success/failure.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n */\n protected async runInteractive(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n let exitCode = 0\n\n try {\n await execCommand(command, {cwd, env: options?.env, stdin: 'inherit'})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n exitCode = 1\n }\n\n return {\n command,\n exitCode,\n stdout: '',\n stderr: '',\n output: '',\n success: exitCode === 0,\n }\n }\n /* eslint-enable tsdoc/syntax */\n\n // ============================================\n // Assertions\n // ============================================\n\n /**\n * Assert that a command succeeded (exit code 0).\n *\n * @param result - The command result to check.\n * @param message - Optional custom assertion message.\n */\n protected assertSuccess(result: CommandResult, message?: string): void {\n this.assertions.push({\n description: message ?? `Command succeeded: ${result.command}`,\n passed: result.success,\n expected: 'exit code 0',\n actual: `exit code ${result.exitCode}`,\n })\n }\n\n /**\n * Assert that a command failed with an error matching the pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Optional regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertError(result: CommandResult, pattern?: RegExp | string, message?: string): void {\n const failed = !result.success\n\n if (pattern) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n let actualValue: string\n if (!failed) {\n actualValue = 'command succeeded'\n } else if (matches) {\n actualValue = 'matched'\n } else {\n actualValue = `output: ${result.output.slice(0, 200)}`\n }\n this.assertions.push({\n description: message ?? `Command failed with expected error: ${pattern}`,\n passed: failed && matches,\n expected: `failure with error matching ${pattern}`,\n actual: actualValue,\n })\n } else {\n this.assertions.push({\n description: message ?? `Command failed: ${result.command}`,\n passed: failed,\n expected: 'non-zero exit code',\n actual: `exit code ${result.exitCode}`,\n })\n }\n }\n\n /**\n * Assert that a file exists and optionally matches content.\n *\n * @param path - The file path to check.\n * @param contentPattern - Optional regex or string to match file content.\n * @param message - Optional custom assertion message.\n */\n protected async assertFile(path: string, contentPattern?: RegExp | string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n\n if (!exists) {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: false,\n expected: 'file exists',\n actual: 'file not found',\n })\n return\n }\n\n if (contentPattern) {\n const content = await readFile(fullPath)\n const regex = typeof contentPattern === 'string' ? new RegExp(contentPattern) : contentPattern\n const matches = regex.test(content)\n this.assertions.push({\n description: message ?? `File ${displayPath} matches ${contentPattern}`,\n passed: matches,\n expected: `content matching ${contentPattern}`,\n actual: matches ? 'matched' : `content: ${content.slice(0, 200)}...`,\n })\n } else {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: true,\n expected: 'file exists',\n actual: 'file exists',\n })\n }\n }\n\n /**\n * Assert that a file does not exist.\n *\n * @param path - The file path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertNoFile(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `File does not exist: ${displayPath}`,\n passed: !exists,\n expected: 'file does not exist',\n actual: exists ? 'file exists' : 'file does not exist',\n })\n }\n\n /**\n * Assert that a directory exists.\n *\n * @param path - The directory path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertDirectory(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `Directory exists: ${displayPath}`,\n passed: exists,\n expected: 'directory exists',\n actual: exists ? 'directory exists' : 'directory not found',\n })\n }\n\n /**\n * Assert that output contains a pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertOutput(result: CommandResult, pattern: RegExp | string, message?: string): void {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n this.assertions.push({\n description: message ?? `Output matches ${pattern}`,\n passed: matches,\n expected: `output matching ${pattern}`,\n actual: matches ? 'matched' : `output: ${result.output.slice(0, 200)}`,\n })\n }\n\n /**\n * Assert that output contains valid JSON and optionally validate it.\n *\n * @param result - The command result to parse.\n * @param validator - Optional function to validate the parsed JSON.\n * @param message - Optional custom assertion message.\n */\n protected assertJson<T = unknown>(\n result: CommandResult,\n validator?: (json: T) => boolean,\n message?: string,\n ): T | undefined {\n try {\n const json = JSON.parse(result.stdout) as T\n if (validator) {\n const valid = validator(json)\n this.assertions.push({\n description: message ?? 'Output is valid JSON matching validator',\n passed: valid,\n expected: 'valid JSON matching validator',\n actual: valid ? 'matched' : 'validator returned false',\n })\n } else {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: true,\n expected: 'valid JSON',\n actual: 'valid JSON',\n })\n }\n return json\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: false,\n expected: 'valid JSON',\n actual: `invalid JSON: ${result.stdout.slice(0, 100)}`,\n })\n return undefined\n }\n }\n\n /**\n * Assert a boolean condition.\n *\n * @param condition - The boolean condition to assert.\n * @param message - The assertion description.\n */\n protected assert(condition: boolean, message: string): void {\n this.assertions.push({\n description: message,\n passed: condition,\n expected: 'true',\n actual: String(condition),\n })\n }\n\n /**\n * Assert two values are equal.\n *\n * @param actual - The actual value.\n * @param expected - The expected value.\n * @param message - The assertion description.\n */\n protected assertEqual<T>(actual: T, expected: T, message: string): void {\n this.assertions.push({\n description: message,\n passed: actual === expected,\n expected: String(expected),\n actual: String(actual),\n })\n }\n\n private hasFailures(): boolean {\n return this.assertions.some((assertion) => !assertion.passed)\n }\n}\n"]}
1
+ {"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../../src/public/node/doctor/framework.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExists, readFile} from '../fs.js'\nimport {isAbsolutePath, joinPath, relativePath} from '../path.js'\nimport {execCommand, captureCommandWithExitCode} from '../system.js'\nimport type {DoctorContext, TestResult, AssertionResult} from './types.js'\n\n/**\n * Result from running a CLI command.\n */\ninterface CommandResult {\n /** The full command that was run. */\n command: string\n /** Exit code (0 = success). */\n exitCode: number\n /** Standard output. */\n stdout: string\n /** Standard error. */\n stderr: string\n /** Combined output (stdout + stderr). */\n output: string\n /** Whether the command succeeded (exitCode === 0). */\n success: boolean\n}\n\n/**\n * A registered test with its name and function.\n */\ninterface RegisteredTest {\n /** The test name. */\n name: string\n /** The async test function. */\n fn: () => Promise<void>\n}\n\n/**\n * Base class for doctor test suites.\n *\n * Write tests using the test() method.\n *\n * ```typescript\n * export default class MyTests extends DoctorSuite {\n * static description = 'My test suite'\n *\n * tests() {\n * this.test('basic case', async () => {\n * const result = await this.run('shopify theme init')\n * this.assertSuccess(result)\n * })\n *\n * this.test('error case', async () => {\n * const result = await this.run('shopify theme init --invalid')\n * this.assertError(result, /unknown flag/)\n * })\n * }\n * }\n * ```\n */\nexport abstract class DoctorSuite<TContext extends DoctorContext = DoctorContext> {\n static description = 'Doctor test suite'\n\n protected context!: TContext\n private assertions: AssertionResult[] = []\n private registeredTests: RegisteredTest[] = []\n\n /**\n * Run the entire test suite.\n *\n * @param context - The doctor context for this suite run.\n * @returns The list of test results.\n */\n async runSuite(context: TContext): Promise<TestResult[]> {\n this.context = context\n this.registeredTests = []\n const results: TestResult[] = []\n\n // Call tests() to register tests via this.test()\n this.tests()\n\n // Run all registered tests\n for (const registeredTest of this.registeredTests) {\n this.assertions = []\n const startTime = Date.now()\n\n try {\n // eslint-disable-next-line no-await-in-loop\n await registeredTest.fn()\n\n results.push({\n name: registeredTest.name,\n status: this.hasFailures() ? 'failed' : 'passed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n results.push({\n name: registeredTest.name,\n status: 'failed',\n duration: Date.now() - startTime,\n assertions: [...this.assertions],\n error: error instanceof Error ? error : new Error(String(error)),\n })\n }\n }\n\n return results\n }\n\n /**\n * Register a test with a name and function.\n *\n * @param name - The test name.\n * @param fn - The async test function.\n */\n protected test(name: string, fn: () => Promise<void>): void {\n this.registeredTests.push({name, fn})\n }\n\n /**\n * Override this method to register tests using this.test().\n */\n protected tests(): void {\n // Subclasses override this to register tests\n }\n\n // ============================================\n // Command execution\n // ============================================\n\n /* eslint-disable tsdoc/syntax -- jsdoc/require-param expects dotted names for destructured options; tsdoc disallows dots */\n /**\n * Run a CLI command and return the result.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n * @example\n * const result = await this.run('shopify theme init my-theme')\n * const result = await this.run('shopify theme push --json')\n */\n protected async run(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n const result = await captureCommandWithExitCode(command, {cwd, env: options?.env})\n\n return {\n command,\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n output: String(result.stdout) + String(result.stderr),\n success: result.exitCode === 0,\n }\n }\n\n /**\n * Run a command without capturing output (for interactive commands).\n * Returns only success/failure.\n *\n * @param command - The CLI command to run.\n * @param options - Optional overrides.\n * @param options.cwd - Working directory for the command.\n * @param options.env - Environment variables for the command.\n */\n protected async runInteractive(\n command: string,\n options?: {cwd?: string; env?: {[key: string]: string}},\n ): Promise<CommandResult> {\n const cwd = options?.cwd ?? this.context.workingDirectory\n let exitCode = 0\n\n try {\n await execCommand(command, {cwd, env: options?.env, stdin: 'inherit'})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n exitCode = 1\n }\n\n return {\n command,\n exitCode,\n stdout: '',\n stderr: '',\n output: '',\n success: exitCode === 0,\n }\n }\n /* eslint-enable tsdoc/syntax */\n\n // ============================================\n // Assertions\n // ============================================\n\n /**\n * Assert that a command succeeded (exit code 0).\n *\n * @param result - The command result to check.\n * @param message - Optional custom assertion message.\n */\n protected assertSuccess(result: CommandResult, message?: string): void {\n this.assertions.push({\n description: message ?? `Command succeeded: ${result.command}`,\n passed: result.success,\n expected: 'exit code 0',\n actual: `exit code ${result.exitCode}`,\n })\n }\n\n /**\n * Assert that a command failed with an error matching the pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Optional regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertError(result: CommandResult, pattern?: RegExp | string, message?: string): void {\n const failed = !result.success\n\n if (pattern) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n let actualValue: string\n if (!failed) {\n actualValue = 'command succeeded'\n } else if (matches) {\n actualValue = 'matched'\n } else {\n actualValue = `output: ${result.output.slice(0, 200)}`\n }\n this.assertions.push({\n description: message ?? `Command failed with expected error: ${pattern}`,\n passed: failed && matches,\n expected: `failure with error matching ${pattern}`,\n actual: actualValue,\n })\n } else {\n this.assertions.push({\n description: message ?? `Command failed: ${result.command}`,\n passed: failed,\n expected: 'non-zero exit code',\n actual: `exit code ${result.exitCode}`,\n })\n }\n }\n\n /**\n * Assert that a file exists and optionally matches content.\n *\n * @param path - The file path to check.\n * @param contentPattern - Optional regex or string to match file content.\n * @param message - Optional custom assertion message.\n */\n protected async assertFile(path: string, contentPattern?: RegExp | string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n\n if (!exists) {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: false,\n expected: 'file exists',\n actual: 'file not found',\n })\n return\n }\n\n if (contentPattern) {\n const content = await readFile(fullPath)\n const regex = typeof contentPattern === 'string' ? new RegExp(contentPattern) : contentPattern\n const matches = regex.test(content)\n this.assertions.push({\n description: message ?? `File ${displayPath} matches ${contentPattern}`,\n passed: matches,\n expected: `content matching ${contentPattern}`,\n actual: matches ? 'matched' : `content: ${content.slice(0, 200)}...`,\n })\n } else {\n this.assertions.push({\n description: message ?? `File exists: ${displayPath}`,\n passed: true,\n expected: 'file exists',\n actual: 'file exists',\n })\n }\n }\n\n /**\n * Assert that a file does not exist.\n *\n * @param path - The file path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertNoFile(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `File does not exist: ${displayPath}`,\n passed: !exists,\n expected: 'file does not exist',\n actual: exists ? 'file exists' : 'file does not exist',\n })\n }\n\n /**\n * Assert that a directory exists.\n *\n * @param path - The directory path to check.\n * @param message - Optional custom assertion message.\n */\n protected async assertDirectory(path: string, message?: string): Promise<void> {\n const fullPath = isAbsolutePath(path) ? path : joinPath(this.context.workingDirectory, path)\n const displayPath = relativePath(this.context.workingDirectory, fullPath)\n const exists = await fileExists(fullPath)\n this.assertions.push({\n description: message ?? `Directory exists: ${displayPath}`,\n passed: exists,\n expected: 'directory exists',\n actual: exists ? 'directory exists' : 'directory not found',\n })\n }\n\n /**\n * Assert that output contains a pattern.\n *\n * @param result - The command result to check.\n * @param pattern - Regex or string pattern to match against output.\n * @param message - Optional custom assertion message.\n */\n protected assertOutput(result: CommandResult, pattern: RegExp | string, message?: string): void {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern\n const matches = regex.test(result.output)\n this.assertions.push({\n description: message ?? `Output matches ${pattern}`,\n passed: matches,\n expected: `output matching ${pattern}`,\n actual: matches ? 'matched' : `output: ${result.output.slice(0, 200)}`,\n })\n }\n\n /**\n * Assert that output contains valid JSON and optionally validate it.\n *\n * @param result - The command result to parse.\n * @param validator - Optional function to validate the parsed JSON.\n * @param message - Optional custom assertion message.\n */\n protected assertJson<T = unknown>(\n result: CommandResult,\n validator?: (json: T) => boolean,\n message?: string,\n ): T | undefined {\n try {\n const json = JSON.parse(result.stdout) as T\n if (validator) {\n const valid = validator(json)\n this.assertions.push({\n description: message ?? 'Output is valid JSON matching validator',\n passed: valid,\n expected: 'valid JSON matching validator',\n actual: valid ? 'matched' : 'validator returned false',\n })\n } else {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: true,\n expected: 'valid JSON',\n actual: 'valid JSON',\n })\n }\n return json\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n this.assertions.push({\n description: message ?? 'Output is valid JSON',\n passed: false,\n expected: 'valid JSON',\n actual: `invalid JSON: ${result.stdout.slice(0, 100)}`,\n })\n return undefined\n }\n }\n\n /**\n * Assert a boolean condition.\n *\n * @param condition - The boolean condition to assert.\n * @param message - The assertion description.\n */\n protected assert(condition: boolean, message: string): void {\n this.assertions.push({\n description: message,\n passed: condition,\n expected: 'true',\n actual: String(condition),\n })\n }\n\n /**\n * Assert two values are equal.\n *\n * @param actual - The actual value.\n * @param expected - The expected value.\n * @param message - The assertion description.\n */\n protected assertEqual<T>(actual: T, expected: T, message: string): void {\n this.assertions.push({\n description: message,\n passed: actual === expected,\n expected: String(expected),\n actual: String(actual),\n })\n }\n\n private hasFailures(): boolean {\n return this.assertions.some((assertion) => !assertion.passed)\n }\n}\n"]}
@@ -33,17 +33,19 @@ export function getAppAutomationToken() {
33
33
  export function getOrganization() {
34
34
  return getEnvironmentVariables()[environmentVariables.organization];
35
35
  }
36
+ function parseEnvNumber(value) {
37
+ if (value && !isNaN(Number(value))) {
38
+ return Number(value);
39
+ }
40
+ return undefined;
41
+ }
36
42
  /**
37
43
  * Return the backend port value.
38
44
  *
39
45
  * @returns The port as a number. Undefined otherwise.
40
46
  */
41
47
  export function getBackendPort() {
42
- const backendPort = getEnvironmentVariables()[systemEnvironmentVariables.backendPort];
43
- if (backendPort && !isNaN(Number(backendPort))) {
44
- return Number(backendPort);
45
- }
46
- return undefined;
48
+ return parseEnvNumber(getEnvironmentVariables()[systemEnvironmentVariables.backendPort]);
47
49
  }
48
50
  /**
49
51
  * Returns the information of the identity & refresh tokens, provided by environment variables.
@@ -92,11 +94,6 @@ export function skipNetworkLevelRetry(environment = getEnvironmentVariables()) {
92
94
  * @returns The maximum request time in milliseconds.
93
95
  */
94
96
  export function maxRequestTimeForNetworkCallsMs(environment = getEnvironmentVariables()) {
95
- const maxRequestTime = environment[environmentVariables.maxRequestTimeForNetworkCalls];
96
- if (maxRequestTime && !isNaN(Number(maxRequestTime))) {
97
- return Number(maxRequestTime);
98
- }
99
- // 30 seconds is the default
100
- return 30 * 1000;
97
+ return parseEnvNumber(environment[environmentVariables.maxRequestTimeForNetworkCalls]) ?? 30 * 1000;
101
98
  }
102
99
  //# sourceMappingURL=environment.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/public/node/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,oBAAoB,EAAE,0BAA0B,EAAC,MAAM,iCAAiC,CAAA;AAEhG;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,OAAO,CAAC,GAAG,CAAA;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,GAAG,GAAG,uBAAuB,EAAE,CAAA;IACrC,OAAO,GAAG,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;AAChG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,WAAW,GAAG,uBAAuB,EAAE,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAA;IACrF,IAAI,WAAW,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC,WAAW,CAAC,CAAA;IAC5B,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,MAAM,aAAa,GAAG,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;IACnF,MAAM,YAAY,GAAG,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;IACjF,IAAI,CAAC,aAAa,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAA;IACrD,OAAO;QACL,WAAW,EAAE,aAAa;QAC1B,YAAY;QACZ,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC;KACrC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAW,GAAG,uBAAuB,EAAE;IACvE,OAAO,YAAY,EAAE,IAAI,QAAQ,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAW,GAAG,uBAAuB,EAAE;IAC3E,OAAO,QAAQ,CAAC,WAAW,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,CAAC,CAAA;AAC1E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,+BAA+B,CAAC,WAAW,GAAG,uBAAuB,EAAE;IACrF,MAAM,cAAc,GAAG,WAAW,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,CAAA;IACtF,IAAI,cAAc,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;QACrD,OAAO,MAAM,CAAC,cAAc,CAAC,CAAA;IAC/B,CAAC;IACD,4BAA4B;IAC5B,OAAO,EAAE,GAAG,IAAI,CAAA;AAClB,CAAC","sourcesContent":["import {nonRandomUUID} from './crypto.js'\nimport {isTruthy} from './context/utilities.js'\nimport {sniffForJson} from './path.js'\nimport {environmentVariables, systemEnvironmentVariables} from '../../private/node/constants.js'\n\n/**\n * It returns the environment variables of the environment\n * where the Node process is running.\n *\n * This function exists to prevent the access of the process\n * global variable which is discouraged via the no-process-env\n * ESLint rule.\n *\n * @returns Current process environment variables.\n */\nexport function getEnvironmentVariables(): NodeJS.ProcessEnv {\n return process.env\n}\n\n/**\n * Returns the value of the SHOPIFY_APP_AUTOMATION_TOKEN environment variable,\n * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN.\n *\n * @returns The app automation token value, or undefined if neither env var is set.\n */\nexport function getAppAutomationToken(): string | undefined {\n const env = getEnvironmentVariables()\n return env[environmentVariables.appAutomationToken] ?? env[environmentVariables.partnersToken]\n}\n\n/**\n * Returns the value of the organization id from the environment variables.\n *\n * @returns True if the current proccess is running using the partners token.\n */\nexport function getOrganization(): string | undefined {\n return getEnvironmentVariables()[environmentVariables.organization]\n}\n\n/**\n * Return the backend port value.\n *\n * @returns The port as a number. Undefined otherwise.\n */\nexport function getBackendPort(): number | undefined {\n const backendPort = getEnvironmentVariables()[systemEnvironmentVariables.backendPort]\n if (backendPort && !isNaN(Number(backendPort))) {\n return Number(backendPort)\n }\n return undefined\n}\n\n/**\n * Returns the information of the identity & refresh tokens, provided by environment variables.\n *\n * @returns The identity token information in case it exists.\n */\nexport function getIdentityTokenInformation(): {accessToken: string; refreshToken: string; userId: string} | undefined {\n const identityToken = getEnvironmentVariables()[environmentVariables.identityToken]\n const refreshToken = getEnvironmentVariables()[environmentVariables.refreshToken]\n if (!identityToken || !refreshToken) return undefined\n return {\n accessToken: identityToken,\n refreshToken,\n userId: nonRandomUUID(identityToken),\n }\n}\n\n/**\n * Checks if the JSON output is enabled via flag (--json or -j) or environment variable (SHOPIFY_FLAG_JSON).\n *\n * @param environment - Process environment variables.\n * @returns True if the JSON output is enabled, false otherwise.\n */\nexport function jsonOutputEnabled(environment = getEnvironmentVariables()): boolean {\n return sniffForJson() || isTruthy(environment[environmentVariables.json])\n}\n\n/**\n * If true, the CLI should not use the network level retry.\n *\n * If there is an error when calling a network API that looks like a DNS or connectivity issue, the CLI will by default\n * automatically retry the request.\n *\n * @param environment - Process environment variables.\n * @returns True if the SHOPIFY_CLI_SKIP_NETWORK_LEVEL_RETRY environment variable is set.\n */\nexport function skipNetworkLevelRetry(environment = getEnvironmentVariables()): boolean {\n return isTruthy(environment[environmentVariables.skipNetworkLevelRetry])\n}\n\n/**\n * Returns the default maximum request time for network calls in milliseconds.\n *\n * After this long, API requests may be cancelled by an AbortSignal. The limit can be overridden by setting the\n * SHOPIFY_CLI_MAX_REQUEST_TIME_FOR_NETWORK_CALLS environment variable.\n *\n * @param environment - Process environment variables.\n * @returns The maximum request time in milliseconds.\n */\nexport function maxRequestTimeForNetworkCallsMs(environment = getEnvironmentVariables()): number {\n const maxRequestTime = environment[environmentVariables.maxRequestTimeForNetworkCalls]\n if (maxRequestTime && !isNaN(Number(maxRequestTime))) {\n return Number(maxRequestTime)\n }\n // 30 seconds is the default\n return 30 * 1000\n}\n"]}
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/public/node/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,oBAAoB,EAAE,0BAA0B,EAAC,MAAM,iCAAiC,CAAA;AAEhG;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,OAAO,CAAC,GAAG,CAAA;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,GAAG,GAAG,uBAAuB,EAAE,CAAA;IACrC,OAAO,GAAG,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;AAChG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;AACrE,CAAC;AAED,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,cAAc,CAAC,uBAAuB,EAAE,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,CAAA;AAC1F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,MAAM,aAAa,GAAG,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;IACnF,MAAM,YAAY,GAAG,uBAAuB,EAAE,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;IACjF,IAAI,CAAC,aAAa,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAA;IACrD,OAAO;QACL,WAAW,EAAE,aAAa;QAC1B,YAAY;QACZ,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC;KACrC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAW,GAAG,uBAAuB,EAAE;IACvE,OAAO,YAAY,EAAE,IAAI,QAAQ,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAW,GAAG,uBAAuB,EAAE;IAC3E,OAAO,QAAQ,CAAC,WAAW,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,CAAC,CAAA;AAC1E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,+BAA+B,CAAC,WAAW,GAAG,uBAAuB,EAAE;IACrF,OAAO,cAAc,CAAC,WAAW,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAA;AACrG,CAAC","sourcesContent":["import {nonRandomUUID} from './crypto.js'\nimport {isTruthy} from './context/utilities.js'\nimport {sniffForJson} from './path.js'\nimport {environmentVariables, systemEnvironmentVariables} from '../../private/node/constants.js'\n\n/**\n * It returns the environment variables of the environment\n * where the Node process is running.\n *\n * This function exists to prevent the access of the process\n * global variable which is discouraged via the no-process-env\n * ESLint rule.\n *\n * @returns Current process environment variables.\n */\nexport function getEnvironmentVariables(): NodeJS.ProcessEnv {\n return process.env\n}\n\n/**\n * Returns the value of the SHOPIFY_APP_AUTOMATION_TOKEN environment variable,\n * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN.\n *\n * @returns The app automation token value, or undefined if neither env var is set.\n */\nexport function getAppAutomationToken(): string | undefined {\n const env = getEnvironmentVariables()\n return env[environmentVariables.appAutomationToken] ?? env[environmentVariables.partnersToken]\n}\n\n/**\n * Returns the value of the organization id from the environment variables.\n *\n * @returns True if the current proccess is running using the partners token.\n */\nexport function getOrganization(): string | undefined {\n return getEnvironmentVariables()[environmentVariables.organization]\n}\n\nfunction parseEnvNumber(value: string | undefined): number | undefined {\n if (value && !isNaN(Number(value))) {\n return Number(value)\n }\n return undefined\n}\n\n/**\n * Return the backend port value.\n *\n * @returns The port as a number. Undefined otherwise.\n */\nexport function getBackendPort(): number | undefined {\n return parseEnvNumber(getEnvironmentVariables()[systemEnvironmentVariables.backendPort])\n}\n\n/**\n * Returns the information of the identity & refresh tokens, provided by environment variables.\n *\n * @returns The identity token information in case it exists.\n */\nexport function getIdentityTokenInformation(): {accessToken: string; refreshToken: string; userId: string} | undefined {\n const identityToken = getEnvironmentVariables()[environmentVariables.identityToken]\n const refreshToken = getEnvironmentVariables()[environmentVariables.refreshToken]\n if (!identityToken || !refreshToken) return undefined\n return {\n accessToken: identityToken,\n refreshToken,\n userId: nonRandomUUID(identityToken),\n }\n}\n\n/**\n * Checks if the JSON output is enabled via flag (--json or -j) or environment variable (SHOPIFY_FLAG_JSON).\n *\n * @param environment - Process environment variables.\n * @returns True if the JSON output is enabled, false otherwise.\n */\nexport function jsonOutputEnabled(environment = getEnvironmentVariables()): boolean {\n return sniffForJson() || isTruthy(environment[environmentVariables.json])\n}\n\n/**\n * If true, the CLI should not use the network level retry.\n *\n * If there is an error when calling a network API that looks like a DNS or connectivity issue, the CLI will by default\n * automatically retry the request.\n *\n * @param environment - Process environment variables.\n * @returns True if the SHOPIFY_CLI_SKIP_NETWORK_LEVEL_RETRY environment variable is set.\n */\nexport function skipNetworkLevelRetry(environment = getEnvironmentVariables()): boolean {\n return isTruthy(environment[environmentVariables.skipNetworkLevelRetry])\n}\n\n/**\n * Returns the default maximum request time for network calls in milliseconds.\n *\n * After this long, API requests may be cancelled by an AbortSignal. The limit can be overridden by setting the\n * SHOPIFY_CLI_MAX_REQUEST_TIME_FOR_NETWORK_CALLS environment variable.\n *\n * @param environment - Process environment variables.\n * @returns The maximum request time in milliseconds.\n */\nexport function maxRequestTimeForNetworkCallsMs(environment = getEnvironmentVariables()): number {\n return parseEnvNumber(environment[environmentVariables.maxRequestTimeForNetworkCalls]) ?? 30 * 1000\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  import { OutputMessage } from './output.js';
2
- import { InlineToken, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
2
+ import { type InlineToken, type TokenItem } from '../../private/node/ui/components/token-item.js';
3
3
  import type { AlertCustomSection } from './ui.js';
4
- export { ExtendableError } from 'ts-error';
5
4
  export declare enum FatalErrorType {
6
5
  Abort = 0,
7
6
  AbortSilent = 1,
@@ -38,8 +37,6 @@ export declare abstract class FatalError extends Error {
38
37
  * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.
39
38
  */
40
39
  export declare class AbortError extends FatalError {
41
- nextSteps?: TokenItem<InlineToken>[];
42
- customSections?: AlertCustomSection[];
43
40
  constructor(message: TokenItem | OutputMessage, tryMessage?: TokenItem | OutputMessage | null, nextSteps?: TokenItem<InlineToken>[], customSections?: AlertCustomSection[]);
44
41
  }
45
42
  /**
@@ -1,10 +1,8 @@
1
1
  import { normalizePath } from './path.js';
2
2
  import { stringifyMessage, TokenizedString } from './output.js';
3
- import { tokenItemToString } from '../../private/node/ui/components/TokenizedText.js';
3
+ import { tokenItemToString } from '../../private/node/ui/components/token-item.js';
4
4
  import { hasRateLimitCode } from '../../private/node/analytics/graphql-error-codes.js';
5
5
  import { Errors } from '@oclif/core';
6
- import { ClientError } from 'graphql-request';
7
- export { ExtendableError } from 'ts-error';
8
6
  export var FatalErrorType;
9
7
  (function (FatalErrorType) {
10
8
  FatalErrorType[FatalErrorType["Abort"] = 0] = "Abort";
@@ -18,6 +16,12 @@ export class CancelExecution extends Error {
18
16
  * There shouldn't be code that catches fatal errors.
19
17
  */
20
18
  export class FatalError extends Error {
19
+ tryMessage;
20
+ type;
21
+ nextSteps;
22
+ formattedMessage;
23
+ customSections;
24
+ skipOclifErrorHandling;
21
25
  /**
22
26
  * Creates a new FatalError error.
23
27
  *
@@ -66,6 +70,8 @@ export class AbortError extends FatalError {
66
70
  * This is useful to represent errors coming from external commands, usually executed by execa.
67
71
  */
68
72
  export class ExternalError extends FatalError {
73
+ command;
74
+ args;
69
75
  constructor(message, command, args, tryMessage = null) {
70
76
  super(message, FatalErrorType.Abort, tryMessage);
71
77
  this.command = command;
@@ -183,21 +189,28 @@ export function shouldReportErrorAsUnexpected(error) {
183
189
  * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape
184
190
  * detected by `errorsIncludeStatus429` in `private/node/api.ts`.
185
191
  *
186
- * Scoped to the external `ClientError` type only — importing the cli-kit `GraphQLClientError`
192
+ * Scoped to the external `ClientError` shape only — importing the cli-kit `GraphQLClientError`
187
193
  * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle.
188
194
  *
195
+ * Matched structurally rather than with `instanceof ClientError`, because importing the class
196
+ * pulls `graphql-request` — and through it `graphql`, `tr46` and `whatwg-url` — into the module
197
+ * graph of every command, for one type check on an error path. `ClientError` is the only error
198
+ * reaching here that carries both `response` and `request`; the cli-kit wrapper carries
199
+ * `statusCode` instead (see `private/node/api/headers.ts`).
200
+ *
189
201
  * @param error - Error to be checked.
190
202
  * @returns A boolean indicating if the error is a known expected API error.
191
203
  */
192
204
  function isExpectedApiError(error) {
193
- if (!(error instanceof ClientError)) {
205
+ const candidate = error;
206
+ if (typeof candidate.response !== 'object' || candidate.response === null || candidate.request === undefined) {
194
207
  return false;
195
208
  }
196
- const status = error.response?.status;
209
+ const status = candidate.response.status;
197
210
  if (status === 401 || status === 429) {
198
211
  return true;
199
212
  }
200
- return hasRateLimitCode(error.response?.errors);
213
+ return hasRateLimitCode(candidate.response.errors);
201
214
  }
202
215
  /**
203
216
  * Stack traces usually have file:// - we strip that and also remove the Windows drive designation.
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/public/node/error.ts"],"names":[],"mappings":"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","sourcesContent":["import {normalizePath} from './path.js'\nimport {OutputMessage, stringifyMessage, TokenizedString} from './output.js'\nimport {InlineToken, TokenItem, tokenItemToString} from '../../private/node/ui/components/TokenizedText.js'\nimport {hasRateLimitCode} from '../../private/node/analytics/graphql-error-codes.js'\n\nimport {Errors} from '@oclif/core'\nimport {ClientError} from 'graphql-request'\n\nimport type {AlertCustomSection} from './ui.js'\n\nexport {ExtendableError} from 'ts-error'\n\nexport enum FatalErrorType {\n Abort,\n AbortSilent,\n Bug,\n}\n\nexport class CancelExecution extends Error {}\n\n/**\n * A fatal error represents an error shouldn't be rescued and that causes the execution to terminate.\n * There shouldn't be code that catches fatal errors.\n */\nexport abstract class FatalError extends Error {\n tryMessage: TokenItem | null\n type: FatalErrorType\n nextSteps?: TokenItem<InlineToken>[]\n formattedMessage?: TokenItem\n customSections?: AlertCustomSection[]\n skipOclifErrorHandling: boolean\n /**\n * Creates a new FatalError error.\n *\n * @param message - The error message.\n * @param type - The type of fatal error.\n * @param tryMessage - The message that recommends next steps to the user.\n * You can pass a string a {@link TokenizedString} or a {@link TokenItem}\n * if you need to style the message inside the error Banner component.\n * @param nextSteps - Message to show as \"next steps\" with suggestions to solve the issue.\n * @param customSections - Custom sections to show in the error banner. To be used if nextSteps is not enough.\n */\n constructor(\n message: TokenItem | OutputMessage,\n type: FatalErrorType,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n const messageIsOutputMessage = typeof message === 'string' || 'value' in message\n super(messageIsOutputMessage ? stringifyMessage(message) : tokenItemToString(message))\n\n if (tryMessage) {\n if (tryMessage instanceof TokenizedString) {\n this.tryMessage = stringifyMessage(tryMessage)\n } else {\n this.tryMessage = tryMessage\n }\n } else {\n this.tryMessage = null\n }\n\n this.type = type\n this.nextSteps = nextSteps\n this.customSections = customSections\n this.skipOclifErrorHandling = true\n\n if (!messageIsOutputMessage) {\n this.formattedMessage = message\n }\n }\n}\n\n/**\n * An abort error is a fatal error that shouldn't be reported as a bug.\n * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.\n */\nexport class AbortError extends FatalError {\n nextSteps?: TokenItem<InlineToken>[]\n customSections?: AlertCustomSection[]\n\n constructor(\n message: TokenItem | OutputMessage,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n super(message, FatalErrorType.Abort, tryMessage, nextSteps, customSections)\n }\n}\n\n/**\n * An external error is similar to Abort but has extra command and args attributes.\n * This is useful to represent errors coming from external commands, usually executed by execa.\n */\nexport class ExternalError extends FatalError {\n command: string\n args: string[]\n\n constructor(\n message: OutputMessage,\n command: string,\n args: string[],\n tryMessage: TokenItem | OutputMessage | null = null,\n ) {\n super(message, FatalErrorType.Abort, tryMessage)\n this.command = command\n this.args = args\n }\n}\n\nexport class AbortSilentError extends FatalError {\n constructor() {\n super('', FatalErrorType.AbortSilent)\n }\n}\n\n/**\n * A bug error is an error that represents a bug and therefore should be reported.\n */\nexport class BugError extends FatalError {\n constructor(message: TokenItem | OutputMessage, tryMessage: TokenItem | OutputMessage | null = null) {\n super(message, FatalErrorType.Bug, tryMessage)\n }\n}\n\n/**\n * A function that handles errors that blow up in the CLI.\n *\n * @param error - Error to be handled.\n * @returns A promise that resolves with the error passed.\n */\nexport async function handler(error: unknown): Promise<unknown> {\n let fatal: FatalError\n if (isFatal(error)) {\n fatal = error\n } else if (typeof error === 'string') {\n fatal = new BugError(error)\n } else if (error instanceof Error) {\n fatal = new BugError(error.message)\n fatal.stack = error.stack\n } else {\n // errors can come in all shapes and sizes...\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const maybeError = error as any\n fatal = new BugError(maybeError?.message ?? 'Unknown error')\n if (maybeError?.stack) {\n fatal.stack = maybeError?.stack\n }\n }\n\n const {renderFatalError} = await import('./ui.js')\n renderFatalError(fatal)\n return Promise.resolve(error)\n}\n\n/**\n * A function that maps an error to an Abort with the stack trace when coming from the CLI.\n *\n * @param error - Error to be mapped.\n * @returns A promise that resolves with the new error object.\n */\nexport function errorMapper(error: unknown): Promise<unknown> {\n if (error instanceof Errors.CLIError) {\n const mappedError = new AbortError(error.message)\n mappedError.stack = error.stack\n return Promise.resolve(mappedError)\n } else {\n return Promise.resolve(error)\n }\n}\n\n/**\n * A function that checks if an error is a fatal one.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a fatal one.\n */\nfunction isFatal(error: unknown): error is FatalError {\n try {\n return Object.prototype.hasOwnProperty.call(error, 'type')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * A function that checks if an error should be reported as unexpected.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error should be reported as unexpected.\n */\nexport function shouldReportErrorAsUnexpected(error: unknown): boolean {\n if (!isFatal(error)) {\n // this means its not one of the CLI wrapped errors\n if (error instanceof Error) {\n // Raw API errors that slip through unwrapped (e.g. the handleErrors:false path) are expected\n // environmental conditions, not CLI bugs. Treat them as expected so they don't pollute crash\n // reporting.\n if (isExpectedApiError(error)) {\n return false\n }\n const message = error.message\n return !errorMessageImpliesEnvironmentIssue(message)\n }\n return true\n }\n if (error.type === FatalErrorType.Bug) {\n return true\n }\n return false\n}\n\n/**\n * Detects raw graphql-request `ClientError`s that are expected environmental conditions rather than\n * CLI bugs. These reach the reporter as plain `Error`s (not `FatalError`s) and would otherwise be\n * reported as unexpected. Two distinct cases, both kept out of crash reporting:\n *\n * HTTP 401 (unauthenticated) is not \"transient\" in the retry sense — it means the user's session\n * token is expired or invalid, a credential/environment condition (see issue #7891). Rate limiting\n * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape\n * detected by `errorsIncludeStatus429` in `private/node/api.ts`.\n *\n * Scoped to the external `ClientError` type only — importing the cli-kit `GraphQLClientError`\n * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a known expected API error.\n */\nfunction isExpectedApiError(error: Error): boolean {\n if (!(error instanceof ClientError)) {\n return false\n }\n const status = error.response?.status\n if (status === 401 || status === 429) {\n return true\n }\n return hasRateLimitCode(error.response?.errors)\n}\n\n/**\n * Stack traces usually have file:// - we strip that and also remove the Windows drive designation.\n *\n * @param filePath - Path to be cleaned.\n * @returns The cleaned path.\n */\nexport function cleanSingleStackTracePath(filePath: string): string {\n return normalizePath(filePath)\n .replace('file:/', '/')\n .replace(/^\\/?[A-Z]:/, '')\n}\n\n/**\n * There are certain errors that we know are not due to a CLI bug, but are environmental/user error.\n *\n * @param message - The error message to check.\n * @returns A boolean indicating if the error message implies an environment issue.\n */\nfunction errorMessageImpliesEnvironmentIssue(message: string): boolean {\n const environmentIssueMessages = [\n 'EPERM: operation not permitted, scandir',\n 'EPERM: operation not permitted, rename',\n 'EACCES: permission denied',\n 'EPERM: operation not permitted, symlink',\n 'This version of npm supports the following node versions',\n 'EBUSY: resource busy or locked',\n 'ENOTEMPTY: directory not empty',\n 'getaddrinfo ENOTFOUND',\n 'Client network socket disconnected before secure TLS connection was established',\n 'spawn EPERM',\n 'socket hang up',\n 'The user aborted a request.',\n 'write EPIPE',\n 'Unsupported platform',\n ]\n const anyMatches = environmentIssueMessages.some((issueMessage) => message.includes(issueMessage))\n return anyMatches\n}\n"]}
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/public/node/error.ts"],"names":[],"mappings":"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","sourcesContent":["import {normalizePath} from './path.js'\nimport {OutputMessage, stringifyMessage, TokenizedString} from './output.js'\nimport {tokenItemToString, type InlineToken, type TokenItem} from '../../private/node/ui/components/token-item.js'\nimport {hasRateLimitCode} from '../../private/node/analytics/graphql-error-codes.js'\n\nimport {Errors} from '@oclif/core'\n\nimport type {AlertCustomSection} from './ui.js'\n\nexport enum FatalErrorType {\n Abort,\n AbortSilent,\n Bug,\n}\n\nexport class CancelExecution extends Error {}\n\n/**\n * A fatal error represents an error shouldn't be rescued and that causes the execution to terminate.\n * There shouldn't be code that catches fatal errors.\n */\nexport abstract class FatalError extends Error {\n tryMessage: TokenItem | null\n type: FatalErrorType\n nextSteps?: TokenItem<InlineToken>[]\n formattedMessage?: TokenItem\n customSections?: AlertCustomSection[]\n skipOclifErrorHandling: boolean\n /**\n * Creates a new FatalError error.\n *\n * @param message - The error message.\n * @param type - The type of fatal error.\n * @param tryMessage - The message that recommends next steps to the user.\n * You can pass a string a {@link TokenizedString} or a {@link TokenItem}\n * if you need to style the message inside the error Banner component.\n * @param nextSteps - Message to show as \"next steps\" with suggestions to solve the issue.\n * @param customSections - Custom sections to show in the error banner. To be used if nextSteps is not enough.\n */\n constructor(\n message: TokenItem | OutputMessage,\n type: FatalErrorType,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n const messageIsOutputMessage = typeof message === 'string' || 'value' in message\n super(messageIsOutputMessage ? stringifyMessage(message) : tokenItemToString(message))\n\n if (tryMessage) {\n if (tryMessage instanceof TokenizedString) {\n this.tryMessage = stringifyMessage(tryMessage)\n } else {\n this.tryMessage = tryMessage\n }\n } else {\n this.tryMessage = null\n }\n\n this.type = type\n this.nextSteps = nextSteps\n this.customSections = customSections\n this.skipOclifErrorHandling = true\n\n if (!messageIsOutputMessage) {\n this.formattedMessage = message\n }\n }\n}\n\n/**\n * An abort error is a fatal error that shouldn't be reported as a bug.\n * Those usually represent unexpected scenarios that we can't handle and that usually require some action from the developer.\n */\nexport class AbortError extends FatalError {\n constructor(\n message: TokenItem | OutputMessage,\n tryMessage: TokenItem | OutputMessage | null = null,\n nextSteps?: TokenItem<InlineToken>[],\n customSections?: AlertCustomSection[],\n ) {\n super(message, FatalErrorType.Abort, tryMessage, nextSteps, customSections)\n }\n}\n\n/**\n * An external error is similar to Abort but has extra command and args attributes.\n * This is useful to represent errors coming from external commands, usually executed by execa.\n */\nexport class ExternalError extends FatalError {\n command: string\n args: string[]\n\n constructor(\n message: OutputMessage,\n command: string,\n args: string[],\n tryMessage: TokenItem | OutputMessage | null = null,\n ) {\n super(message, FatalErrorType.Abort, tryMessage)\n this.command = command\n this.args = args\n }\n}\n\nexport class AbortSilentError extends FatalError {\n constructor() {\n super('', FatalErrorType.AbortSilent)\n }\n}\n\n/**\n * A bug error is an error that represents a bug and therefore should be reported.\n */\nexport class BugError extends FatalError {\n constructor(message: TokenItem | OutputMessage, tryMessage: TokenItem | OutputMessage | null = null) {\n super(message, FatalErrorType.Bug, tryMessage)\n }\n}\n\n/**\n * A function that handles errors that blow up in the CLI.\n *\n * @param error - Error to be handled.\n * @returns A promise that resolves with the error passed.\n */\nexport async function handler(error: unknown): Promise<unknown> {\n let fatal: FatalError\n if (isFatal(error)) {\n fatal = error\n } else if (typeof error === 'string') {\n fatal = new BugError(error)\n } else if (error instanceof Error) {\n fatal = new BugError(error.message)\n fatal.stack = error.stack\n } else {\n // errors can come in all shapes and sizes...\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const maybeError = error as any\n fatal = new BugError(maybeError?.message ?? 'Unknown error')\n if (maybeError?.stack) {\n fatal.stack = maybeError?.stack\n }\n }\n\n const {renderFatalError} = await import('./ui.js')\n renderFatalError(fatal)\n return Promise.resolve(error)\n}\n\n/**\n * A function that maps an error to an Abort with the stack trace when coming from the CLI.\n *\n * @param error - Error to be mapped.\n * @returns A promise that resolves with the new error object.\n */\nexport function errorMapper(error: unknown): Promise<unknown> {\n if (error instanceof Errors.CLIError) {\n const mappedError = new AbortError(error.message)\n mappedError.stack = error.stack\n return Promise.resolve(mappedError)\n } else {\n return Promise.resolve(error)\n }\n}\n\n/**\n * A function that checks if an error is a fatal one.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a fatal one.\n */\nfunction isFatal(error: unknown): error is FatalError {\n try {\n return Object.prototype.hasOwnProperty.call(error, 'type')\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n return false\n }\n}\n\n/**\n * A function that checks if an error should be reported as unexpected.\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error should be reported as unexpected.\n */\nexport function shouldReportErrorAsUnexpected(error: unknown): boolean {\n if (!isFatal(error)) {\n // this means its not one of the CLI wrapped errors\n if (error instanceof Error) {\n // Raw API errors that slip through unwrapped (e.g. the handleErrors:false path) are expected\n // environmental conditions, not CLI bugs. Treat them as expected so they don't pollute crash\n // reporting.\n if (isExpectedApiError(error)) {\n return false\n }\n const message = error.message\n return !errorMessageImpliesEnvironmentIssue(message)\n }\n return true\n }\n if (error.type === FatalErrorType.Bug) {\n return true\n }\n return false\n}\n\n/**\n * Detects raw graphql-request `ClientError`s that are expected environmental conditions rather than\n * CLI bugs. These reach the reporter as plain `Error`s (not `FatalError`s) and would otherwise be\n * reported as unexpected. Two distinct cases, both kept out of crash reporting:\n *\n * HTTP 401 (unauthenticated) is not \"transient\" in the retry sense — it means the user's session\n * token is expired or invalid, a credential/environment condition (see issue #7891). Rate limiting\n * (HTTP 429, or a `THROTTLED`/`429` GraphQL code on any error in the response) matches the shape\n * detected by `errorsIncludeStatus429` in `private/node/api.ts`.\n *\n * Scoped to the external `ClientError` shape only — importing the cli-kit `GraphQLClientError`\n * wrapper here would create an `error.ts → headers.ts → error.ts` import cycle.\n *\n * Matched structurally rather than with `instanceof ClientError`, because importing the class\n * pulls `graphql-request` — and through it `graphql`, `tr46` and `whatwg-url` — into the module\n * graph of every command, for one type check on an error path. `ClientError` is the only error\n * reaching here that carries both `response` and `request`; the cli-kit wrapper carries\n * `statusCode` instead (see `private/node/api/headers.ts`).\n *\n * @param error - Error to be checked.\n * @returns A boolean indicating if the error is a known expected API error.\n */\nfunction isExpectedApiError(error: Error): boolean {\n const candidate = error as Error & {\n response?: {status?: number; errors?: unknown}\n request?: unknown\n }\n if (typeof candidate.response !== 'object' || candidate.response === null || candidate.request === undefined) {\n return false\n }\n const status = candidate.response.status\n if (status === 401 || status === 429) {\n return true\n }\n return hasRateLimitCode(candidate.response.errors)\n}\n\n/**\n * Stack traces usually have file:// - we strip that and also remove the Windows drive designation.\n *\n * @param filePath - Path to be cleaned.\n * @returns The cleaned path.\n */\nexport function cleanSingleStackTracePath(filePath: string): string {\n return normalizePath(filePath)\n .replace('file:/', '/')\n .replace(/^\\/?[A-Z]:/, '')\n}\n\n/**\n * There are certain errors that we know are not due to a CLI bug, but are environmental/user error.\n *\n * @param message - The error message to check.\n * @returns A boolean indicating if the error message implies an environment issue.\n */\nfunction errorMessageImpliesEnvironmentIssue(message: string): boolean {\n const environmentIssueMessages = [\n 'EPERM: operation not permitted, scandir',\n 'EPERM: operation not permitted, rename',\n 'EACCES: permission denied',\n 'EPERM: operation not permitted, symlink',\n 'This version of npm supports the following node versions',\n 'EBUSY: resource busy or locked',\n 'ENOTEMPTY: directory not empty',\n 'getaddrinfo ENOTFOUND',\n 'Client network socket disconnected before secure TLS connection was established',\n 'spawn EPERM',\n 'socket hang up',\n 'The user aborted a request.',\n 'write EPIPE',\n 'Unsupported platform',\n ]\n const anyMatches = environmentIssueMessages.some((issueMessage) => message.includes(issueMessage))\n return anyMatches\n}\n"]}
@@ -30,6 +30,10 @@ async function gitCommand(args, directory) {
30
30
  * @param initialBranch - The name of the initial branch.
31
31
  */
32
32
  export async function initializeGitRepository(directory, initialBranch = 'main') {
33
+ // Guard against command/argument injection attacks if initialBranch starts with '-'
34
+ if (initialBranch.startsWith('-')) {
35
+ throw new AbortError(`Invalid initial branch name: ${initialBranch}. Branch names can't start with a hyphen.`);
36
+ }
33
37
  outputDebug(outputContent `Initializing git repository at ${outputToken.path(directory)}...`);
34
38
  await ensureGitIsPresentOrAbort();
35
39
  // We use init and checkout instead of `init --initial-branch` because the latter is only supported in git 2.28+
@@ -66,11 +70,9 @@ export async function checkIfIgnoredInGitRepository(directory, files) {
66
70
  export function createGitIgnore(directory, template) {
67
71
  outputDebug(outputContent `Creating .gitignore at ${outputToken.path(directory)}...`);
68
72
  const filePath = `${directory}/.gitignore`;
69
- let fileContent = '';
70
- for (const [section, lines] of Object.entries(template)) {
71
- fileContent += `# ${section}\n`;
72
- fileContent += `${lines.join('\n')}\n\n`;
73
- }
73
+ const fileContent = Object.entries(template)
74
+ .map(([section, lines]) => `# ${section}\n${lines.join('\n')}\n\n`)
75
+ .join('');
74
76
  appendFileSync(filePath, fileContent);
75
77
  }
76
78
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/public/node/git.ts"],"names":[],"mappings":"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","sourcesContent":["import {outputContent, outputToken, outputDebug} from './output.js'\nimport {hasGit, isTerminalInteractive} from './context/local.js'\nimport {\n appendFileSync,\n detectEOL,\n fileExists,\n fileExistsSync,\n glob,\n isDirectory,\n readFileSync,\n writeFileSync,\n} from './fs.js'\nimport {AbortError} from './error.js'\nimport {cwd, joinPath} from './path.js'\nimport {runWithTimer} from './metadata.js'\nimport {execa} from 'execa'\n\nimport ignore from 'ignore'\n\nexport interface GitLogEntry {\n hash: string\n date: string\n message: string\n refs: string\n body: string\n author_name: string\n author_email: string\n}\n\nasync function gitCommand(args: string[], directory?: string): Promise<string> {\n try {\n const result = await execa('git', args, {cwd: directory})\n return result.stdout\n } catch (err) {\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n if ('exitCode' in err) {\n Object.assign(abortError, {exitCode: err.exitCode})\n }\n throw abortError\n }\n throw err\n }\n}\n\n/**\n * Initialize a git repository at the given directory.\n *\n * @param directory - The directory where the git repository will be initialized.\n * @param initialBranch - The name of the initial branch.\n */\nexport async function initializeGitRepository(directory: string, initialBranch = 'main'): Promise<void> {\n outputDebug(outputContent`Initializing git repository at ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n // We use init and checkout instead of `init --initial-branch` because the latter is only supported in git 2.28+\n await gitCommand(['init'], directory)\n await gitCommand(['checkout', '-b', initialBranch], directory)\n}\n\n/**\n * Given a Git repository and a list of absolute paths to files contained\n * in the repository, it filters and returns the files that are ignored\n * by the .gitignore.\n *\n * @param directory - The absolute path to the directory containing the files.\n * @param files - The list of files to check against.\n * @returns Files ignored by the lockfile.\n */\nexport async function checkIfIgnoredInGitRepository(directory: string, files: string[]): Promise<string[]> {\n try {\n const stdout = await gitCommand(['check-ignore', ...files], directory)\n return stdout.split('\\n').filter(Boolean)\n } catch (error) {\n // git check-ignore exits with code 1 when no files are ignored\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 1) return []\n throw error\n }\n}\n\nexport type GitIgnoreTemplate = Record<string, string[]>\n/**\n * Create a .gitignore file in the given directory.\n *\n * @param directory - The directory where the .gitignore file will be created.\n * @param template - The template to use to create the .gitignore file.\n */\nexport function createGitIgnore(directory: string, template: GitIgnoreTemplate): void {\n outputDebug(outputContent`Creating .gitignore at ${outputToken.path(directory)}...`)\n const filePath = `${directory}/.gitignore`\n\n let fileContent = ''\n for (const [section, lines] of Object.entries(template)) {\n fileContent += `# ${section}\\n`\n fileContent += `${lines.join('\\n')}\\n\\n`\n }\n\n appendFileSync(filePath, fileContent)\n}\n\n/**\n * Add an entry to an existing .gitignore file.\n *\n * If the .gitignore file doesn't exist, or if the entry is already present,\n * no changes will be made.\n *\n * @param root - The directory containing the .gitignore file.\n * @param entry - The entry to add to the .gitignore file.\n */\nexport function addToGitIgnore(root: string, entry: string): void {\n const gitIgnorePath = joinPath(root, '.gitignore')\n\n if (!fileExistsSync(gitIgnorePath)) {\n // When the .gitignore file does not exist, the CLI should not be opinionated about creating it\n return\n }\n\n const gitIgnoreContent = readFileSync(gitIgnorePath).toString()\n const eol = detectEOL(gitIgnoreContent)\n\n const lines = gitIgnoreContent.split(eol).map((line) => line.trim())\n const ignoreManager = ignore.default({allowRelativePaths: true}).add(lines)\n\n const isIgnoredEntry = ignoreManager.ignores(joinPath(entry))\n const isIgnoredEntryAsDir = ignoreManager.ignores(joinPath(entry, 'ignored.txt'))\n const isAlreadyIgnored = isIgnoredEntry || isIgnoredEntryAsDir\n if (isAlreadyIgnored) {\n // The file is already ignored by an existing pattern\n return\n }\n\n if (gitIgnoreContent.endsWith(eol)) {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${entry}${eol}`)\n } else {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${eol}${entry}${eol}`)\n }\n}\n\n/**\n * Options to use when cloning a git repository.\n *\n * @param repoUrl - The URL of the repository to clone.\n * @param destination - The directory where the repository will be cloned.\n * @param shallow - Whether to clone the repository shallowly.\n * @param latestTag - Whether to clone the latest tag instead of the default branch.\n */\nexport interface GitCloneOptions {\n repoUrl: string\n destination: string\n shallow?: boolean\n latestTag?: boolean\n}\n/**\n * Clone a git repository.\n *\n * @param cloneOptions - The options to use to clone the repository.\n * @returns A promise that resolves when the clone is complete.\n */\nexport async function downloadGitRepository(cloneOptions: GitCloneOptions): Promise<void> {\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n const {repoUrl, destination, shallow, latestTag} = cloneOptions\n outputDebug(outputContent`Git-cloning repository ${repoUrl} into ${outputToken.path(destination)}...`)\n await ensureGitIsPresentOrAbort()\n\n // Validate destination directory before attempting to clone\n if (await fileExists(destination)) {\n // Check if it's a directory\n if (!(await isDirectory(destination))) {\n throw new AbortError(\n outputContent`Can't clone to ${outputToken.path(destination)}`,\n \"The path exists but isn't a directory.\",\n )\n }\n\n // Check if directory is empty\n const entries = await glob(['*', '.*'], {\n cwd: destination,\n deep: 1,\n onlyFiles: false,\n })\n\n if (entries.length > 0) {\n throw new AbortError(\n outputContent`Directory ${outputToken.path(destination)} already exists and is not empty`,\n outputContent`Choose a different name or remove the existing directory first.`,\n )\n }\n }\n\n const [repository, branch] = repoUrl.split('#')\n\n if (branch && latestTag) {\n throw new AbortError(\"Error cloning the repository. Git can't clone the latest release with a 'branch'.\")\n }\n\n if (shallow && latestTag) {\n throw new AbortError(\n \"Error cloning the repository. Git can't clone the latest release with the 'shallow' property.\",\n )\n }\n\n const args = ['clone', '--recurse-submodules']\n if (branch) {\n args.push('--branch', branch)\n }\n if (shallow) {\n args.push('--depth', '1')\n }\n if (!isTerminalInteractive()) {\n args.push('-c', 'core.askpass=true')\n }\n args.push(repository!, destination)\n\n try {\n await execa('git', args)\n\n if (latestTag) {\n const tag = await getLatestTagFromDirectory(destination, repoUrl)\n await gitCommand(['checkout', tag], destination)\n }\n } catch (err) {\n if (err instanceof AbortError) {\n throw err\n }\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n throw abortError\n }\n throw err\n }\n })\n}\n\nasync function getLatestTagFromDirectory(directory: string, repoUrl: string): Promise<string> {\n const tag = await getLatestTag(directory)\n\n if (!tag) {\n throw new AbortError(`Couldn't obtain the most recent tag of the repository ${repoUrl}`)\n }\n\n return tag\n}\n\n/**\n * Get the latest commit of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The latest commit of the repository.\n */\nexport async function getLatestGitCommit(directory?: string): Promise<GitLogEntry> {\n const format = '%H%x00%ai%x00%s%x00%D%x00%b%x00%an%x00%ae'\n const stdout = await gitCommand(['log', '-1', `--format=${format}`], directory)\n if (!stdout.trim()) {\n throw new AbortError(\n 'Must have at least one commit to run command',\n outputContent`Run ${outputToken.genericShellCommand(\n \"git commit -m 'Initial commit'\",\n )} to create your first commit.`,\n )\n }\n const parts = stdout.split('\\x00')\n return {\n hash: parts[0]!,\n date: parts[1]!,\n message: parts[2]!,\n refs: parts[3]!,\n body: parts[4]!,\n author_name: parts[5]!,\n author_email: parts[6]!,\n }\n}\n\n/**\n * Add all files to the git index from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @returns A promise that resolves when the files are added to the index.\n */\nexport async function addAllToGitFromDirectory(directory?: string): Promise<void> {\n await gitCommand(['add', '--all'], directory)\n}\n\nexport interface CreateGitCommitOptions {\n directory?: string\n author?: string\n}\n\n/**\n * Create a git commit.\n *\n * @param message - The message of the commit.\n * @param options - The options to use to create the commit.\n * @returns The hash of the created commit.\n */\nexport async function createGitCommit(message: string, options?: CreateGitCommitOptions): Promise<string> {\n const args = ['commit', '-m', message]\n if (options?.author) {\n args.push('--author', options.author)\n }\n await gitCommand(args, options?.directory)\n const stdout = await gitCommand(['rev-parse', 'HEAD'], options?.directory)\n return stdout.trim()\n}\n\n/**\n * Get the HEAD symbolic reference of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The HEAD symbolic reference of the repository.\n */\nexport async function getHeadSymbolicRef(directory?: string): Promise<string> {\n const ref = await gitCommand(['symbolic-ref', '-q', 'HEAD'], directory)\n if (!ref) {\n throw new AbortError(\n \"Git HEAD can't be detached to run command\",\n outputContent`Run ${outputToken.genericShellCommand(\n 'git checkout [branchName]',\n )} to reattach HEAD or see git ${outputToken.link(\n 'documentation',\n 'https://git-scm.com/book/en/v2/Git-Internals-Git-References',\n )} for more details`,\n )\n }\n return ref.trim()\n}\n\n/**\n * If \"git\" is not present in the environment it throws\n * an abort error.\n */\nexport async function ensureGitIsPresentOrAbort(): Promise<void> {\n if (!(await hasGit())) {\n throw new AbortError(\n `Git is necessary in the environment to continue`,\n outputContent`Install ${outputToken.link(\n 'git',\n 'https://git-scm.com/book/en/v2/Getting-Started-Installing-Git',\n )}`,\n )\n }\n}\n\nexport class OutsideGitDirectoryError extends AbortError {}\n/**\n * If command run from outside a .git directory tree\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureInsideGitDirectory(directory?: string): Promise<void> {\n await ensureGitIsPresentOrAbort()\n\n if (!(await checkIfInsideGitDirectory(directory))) {\n throw new OutsideGitDirectoryError(`${outputToken.path(directory ?? cwd())} is not a Git directory`)\n }\n}\n\n/**\n * Returns true if the given directory is inside a .git directory tree.\n *\n * @param directory - The directory to check.\n * @returns True if the directory is inside a .git directory tree.\n */\nexport async function insideGitDirectory(directory?: string): Promise<boolean> {\n if (!(await hasGit())) {\n return false\n }\n\n return checkIfInsideGitDirectory(directory)\n}\n\nasync function checkIfInsideGitDirectory(directory?: string): Promise<boolean> {\n try {\n await execa('git', ['rev-parse', '--git-dir'], {cwd: directory})\n return true\n } catch (error) {\n if (error instanceof Error && 'exitCode' in error && error.exitCode === 128) return false\n throw error\n }\n}\n\nexport class GitDirectoryNotCleanError extends AbortError {}\n/**\n * If the .git directory tree is not clean (has uncommitted changes)\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureIsClean(directory?: string): Promise<void> {\n if (!(await isClean(directory))) {\n throw new GitDirectoryNotCleanError(`${outputToken.path(directory ?? cwd())} is not a clean Git directory`)\n }\n}\n\n/**\n * Returns true if the .git directory tree is clean (no uncommitted changes).\n *\n * @param directory - The directory to check.\n * @returns True is the .git directory is clean.\n */\nexport async function isClean(directory?: string): Promise<boolean> {\n const stdout = await gitCommand(['status', '--porcelain'], directory)\n return stdout.trim() === ''\n}\n\n/**\n * Returns the latest tag of a git repository.\n *\n * @param directory - The directory to check.\n * @returns String with the latest tag or undefined if no tags are found.\n */\nexport async function getLatestTag(directory?: string): Promise<string | undefined> {\n try {\n const stdout = await gitCommand(['describe', '--tags', '--abbrev=0'], directory)\n return stdout.trim() || undefined\n } catch (error) {\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 128) return undefined\n throw error\n }\n}\n\n/**\n * Remove a git remote from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @param remoteName - The name of the remote to remove (defaults to 'origin').\n * @returns A promise that resolves when the remote is removed.\n */\nexport async function removeGitRemote(directory: string, remoteName = 'origin'): Promise<void> {\n outputDebug(outputContent`Removing git remote ${remoteName} from ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n\n const stdout = await gitCommand(['remote'], directory)\n const remotes = stdout.split('\\n').filter(Boolean)\n\n if (!remotes.includes(remoteName)) {\n outputDebug(outputContent`Remote ${remoteName} does not exist, no action needed`)\n return\n }\n\n await gitCommand(['remote', 'remove', remoteName], directory)\n}\n"]}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/public/node/git.ts"],"names":[],"mappings":"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","sourcesContent":["import {outputContent, outputToken, outputDebug} from './output.js'\nimport {hasGit, isTerminalInteractive} from './context/local.js'\nimport {\n appendFileSync,\n detectEOL,\n fileExists,\n fileExistsSync,\n glob,\n isDirectory,\n readFileSync,\n writeFileSync,\n} from './fs.js'\nimport {AbortError} from './error.js'\nimport {cwd, joinPath} from './path.js'\nimport {runWithTimer} from './metadata.js'\nimport {execa} from 'execa'\n\nimport ignore from 'ignore'\n\nexport interface GitLogEntry {\n hash: string\n date: string\n message: string\n refs: string\n body: string\n author_name: string\n author_email: string\n}\n\nasync function gitCommand(args: string[], directory?: string): Promise<string> {\n try {\n const result = await execa('git', args, {cwd: directory})\n return result.stdout\n } catch (err) {\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n if ('exitCode' in err) {\n Object.assign(abortError, {exitCode: err.exitCode})\n }\n throw abortError\n }\n throw err\n }\n}\n\n/**\n * Initialize a git repository at the given directory.\n *\n * @param directory - The directory where the git repository will be initialized.\n * @param initialBranch - The name of the initial branch.\n */\nexport async function initializeGitRepository(directory: string, initialBranch = 'main'): Promise<void> {\n // Guard against command/argument injection attacks if initialBranch starts with '-'\n if (initialBranch.startsWith('-')) {\n throw new AbortError(`Invalid initial branch name: ${initialBranch}. Branch names can't start with a hyphen.`)\n }\n\n outputDebug(outputContent`Initializing git repository at ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n // We use init and checkout instead of `init --initial-branch` because the latter is only supported in git 2.28+\n await gitCommand(['init'], directory)\n await gitCommand(['checkout', '-b', initialBranch], directory)\n}\n\n/**\n * Given a Git repository and a list of absolute paths to files contained\n * in the repository, it filters and returns the files that are ignored\n * by the .gitignore.\n *\n * @param directory - The absolute path to the directory containing the files.\n * @param files - The list of files to check against.\n * @returns Files ignored by the lockfile.\n */\nexport async function checkIfIgnoredInGitRepository(directory: string, files: string[]): Promise<string[]> {\n try {\n const stdout = await gitCommand(['check-ignore', ...files], directory)\n return stdout.split('\\n').filter(Boolean)\n } catch (error) {\n // git check-ignore exits with code 1 when no files are ignored\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 1) return []\n throw error\n }\n}\n\nexport type GitIgnoreTemplate = Record<string, string[]>\n/**\n * Create a .gitignore file in the given directory.\n *\n * @param directory - The directory where the .gitignore file will be created.\n * @param template - The template to use to create the .gitignore file.\n */\nexport function createGitIgnore(directory: string, template: GitIgnoreTemplate): void {\n outputDebug(outputContent`Creating .gitignore at ${outputToken.path(directory)}...`)\n const filePath = `${directory}/.gitignore`\n\n const fileContent = Object.entries(template)\n .map(([section, lines]) => `# ${section}\\n${lines.join('\\n')}\\n\\n`)\n .join('')\n\n appendFileSync(filePath, fileContent)\n}\n\n/**\n * Add an entry to an existing .gitignore file.\n *\n * If the .gitignore file doesn't exist, or if the entry is already present,\n * no changes will be made.\n *\n * @param root - The directory containing the .gitignore file.\n * @param entry - The entry to add to the .gitignore file.\n */\nexport function addToGitIgnore(root: string, entry: string): void {\n const gitIgnorePath = joinPath(root, '.gitignore')\n\n if (!fileExistsSync(gitIgnorePath)) {\n // When the .gitignore file does not exist, the CLI should not be opinionated about creating it\n return\n }\n\n const gitIgnoreContent = readFileSync(gitIgnorePath).toString()\n const eol = detectEOL(gitIgnoreContent)\n\n const lines = gitIgnoreContent.split(eol).map((line) => line.trim())\n const ignoreManager = ignore.default({allowRelativePaths: true}).add(lines)\n\n const isIgnoredEntry = ignoreManager.ignores(joinPath(entry))\n const isIgnoredEntryAsDir = ignoreManager.ignores(joinPath(entry, 'ignored.txt'))\n const isAlreadyIgnored = isIgnoredEntry || isIgnoredEntryAsDir\n if (isAlreadyIgnored) {\n // The file is already ignored by an existing pattern\n return\n }\n\n if (gitIgnoreContent.endsWith(eol)) {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${entry}${eol}`)\n } else {\n writeFileSync(gitIgnorePath, `${gitIgnoreContent}${eol}${entry}${eol}`)\n }\n}\n\n/**\n * Options to use when cloning a git repository.\n *\n * @param repoUrl - The URL of the repository to clone.\n * @param destination - The directory where the repository will be cloned.\n * @param shallow - Whether to clone the repository shallowly.\n * @param latestTag - Whether to clone the latest tag instead of the default branch.\n */\nexport interface GitCloneOptions {\n repoUrl: string\n destination: string\n shallow?: boolean\n latestTag?: boolean\n}\n/**\n * Clone a git repository.\n *\n * @param cloneOptions - The options to use to clone the repository.\n * @returns A promise that resolves when the clone is complete.\n */\nexport async function downloadGitRepository(cloneOptions: GitCloneOptions): Promise<void> {\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n const {repoUrl, destination, shallow, latestTag} = cloneOptions\n outputDebug(outputContent`Git-cloning repository ${repoUrl} into ${outputToken.path(destination)}...`)\n await ensureGitIsPresentOrAbort()\n\n // Validate destination directory before attempting to clone\n if (await fileExists(destination)) {\n // Check if it's a directory\n if (!(await isDirectory(destination))) {\n throw new AbortError(\n outputContent`Can't clone to ${outputToken.path(destination)}`,\n \"The path exists but isn't a directory.\",\n )\n }\n\n // Check if directory is empty\n const entries = await glob(['*', '.*'], {\n cwd: destination,\n deep: 1,\n onlyFiles: false,\n })\n\n if (entries.length > 0) {\n throw new AbortError(\n outputContent`Directory ${outputToken.path(destination)} already exists and is not empty`,\n outputContent`Choose a different name or remove the existing directory first.`,\n )\n }\n }\n\n const [repository, branch] = repoUrl.split('#')\n\n if (branch && latestTag) {\n throw new AbortError(\"Error cloning the repository. Git can't clone the latest release with a 'branch'.\")\n }\n\n if (shallow && latestTag) {\n throw new AbortError(\n \"Error cloning the repository. Git can't clone the latest release with the 'shallow' property.\",\n )\n }\n\n const args = ['clone', '--recurse-submodules']\n if (branch) {\n args.push('--branch', branch)\n }\n if (shallow) {\n args.push('--depth', '1')\n }\n if (!isTerminalInteractive()) {\n args.push('-c', 'core.askpass=true')\n }\n args.push(repository!, destination)\n\n try {\n await execa('git', args)\n\n if (latestTag) {\n const tag = await getLatestTagFromDirectory(destination, repoUrl)\n await gitCommand(['checkout', tag], destination)\n }\n } catch (err) {\n if (err instanceof AbortError) {\n throw err\n }\n if (err instanceof Error) {\n const abortError = new AbortError(err.message)\n abortError.stack = err.stack\n throw abortError\n }\n throw err\n }\n })\n}\n\nasync function getLatestTagFromDirectory(directory: string, repoUrl: string): Promise<string> {\n const tag = await getLatestTag(directory)\n\n if (!tag) {\n throw new AbortError(`Couldn't obtain the most recent tag of the repository ${repoUrl}`)\n }\n\n return tag\n}\n\n/**\n * Get the latest commit of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The latest commit of the repository.\n */\nexport async function getLatestGitCommit(directory?: string): Promise<GitLogEntry> {\n const format = '%H%x00%ai%x00%s%x00%D%x00%b%x00%an%x00%ae'\n const stdout = await gitCommand(['log', '-1', `--format=${format}`], directory)\n if (!stdout.trim()) {\n throw new AbortError(\n 'Must have at least one commit to run command',\n outputContent`Run ${outputToken.genericShellCommand(\n \"git commit -m 'Initial commit'\",\n )} to create your first commit.`,\n )\n }\n const parts = stdout.split('\\x00')\n return {\n hash: parts[0]!,\n date: parts[1]!,\n message: parts[2]!,\n refs: parts[3]!,\n body: parts[4]!,\n author_name: parts[5]!,\n author_email: parts[6]!,\n }\n}\n\n/**\n * Add all files to the git index from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @returns A promise that resolves when the files are added to the index.\n */\nexport async function addAllToGitFromDirectory(directory?: string): Promise<void> {\n await gitCommand(['add', '--all'], directory)\n}\n\nexport interface CreateGitCommitOptions {\n directory?: string\n author?: string\n}\n\n/**\n * Create a git commit.\n *\n * @param message - The message of the commit.\n * @param options - The options to use to create the commit.\n * @returns The hash of the created commit.\n */\nexport async function createGitCommit(message: string, options?: CreateGitCommitOptions): Promise<string> {\n const args = ['commit', '-m', message]\n if (options?.author) {\n args.push('--author', options.author)\n }\n await gitCommand(args, options?.directory)\n const stdout = await gitCommand(['rev-parse', 'HEAD'], options?.directory)\n return stdout.trim()\n}\n\n/**\n * Get the HEAD symbolic reference of a git repository.\n *\n * @param directory - The directory of the git repository.\n * @returns The HEAD symbolic reference of the repository.\n */\nexport async function getHeadSymbolicRef(directory?: string): Promise<string> {\n const ref = await gitCommand(['symbolic-ref', '-q', 'HEAD'], directory)\n if (!ref) {\n throw new AbortError(\n \"Git HEAD can't be detached to run command\",\n outputContent`Run ${outputToken.genericShellCommand(\n 'git checkout [branchName]',\n )} to reattach HEAD or see git ${outputToken.link(\n 'documentation',\n 'https://git-scm.com/book/en/v2/Git-Internals-Git-References',\n )} for more details`,\n )\n }\n return ref.trim()\n}\n\n/**\n * If \"git\" is not present in the environment it throws\n * an abort error.\n */\nexport async function ensureGitIsPresentOrAbort(): Promise<void> {\n if (!(await hasGit())) {\n throw new AbortError(\n `Git is necessary in the environment to continue`,\n outputContent`Install ${outputToken.link(\n 'git',\n 'https://git-scm.com/book/en/v2/Getting-Started-Installing-Git',\n )}`,\n )\n }\n}\n\nexport class OutsideGitDirectoryError extends AbortError {}\n/**\n * If command run from outside a .git directory tree\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureInsideGitDirectory(directory?: string): Promise<void> {\n await ensureGitIsPresentOrAbort()\n\n if (!(await checkIfInsideGitDirectory(directory))) {\n throw new OutsideGitDirectoryError(`${outputToken.path(directory ?? cwd())} is not a Git directory`)\n }\n}\n\n/**\n * Returns true if the given directory is inside a .git directory tree.\n *\n * @param directory - The directory to check.\n * @returns True if the directory is inside a .git directory tree.\n */\nexport async function insideGitDirectory(directory?: string): Promise<boolean> {\n if (!(await hasGit())) {\n return false\n }\n\n return checkIfInsideGitDirectory(directory)\n}\n\nasync function checkIfInsideGitDirectory(directory?: string): Promise<boolean> {\n try {\n await execa('git', ['rev-parse', '--git-dir'], {cwd: directory})\n return true\n } catch (error) {\n if (error instanceof Error && 'exitCode' in error && error.exitCode === 128) return false\n throw error\n }\n}\n\nexport class GitDirectoryNotCleanError extends AbortError {}\n/**\n * If the .git directory tree is not clean (has uncommitted changes)\n * it throws an abort error.\n *\n * @param directory - The directory to check.\n */\nexport async function ensureIsClean(directory?: string): Promise<void> {\n if (!(await isClean(directory))) {\n throw new GitDirectoryNotCleanError(`${outputToken.path(directory ?? cwd())} is not a clean Git directory`)\n }\n}\n\n/**\n * Returns true if the .git directory tree is clean (no uncommitted changes).\n *\n * @param directory - The directory to check.\n * @returns True is the .git directory is clean.\n */\nexport async function isClean(directory?: string): Promise<boolean> {\n const stdout = await gitCommand(['status', '--porcelain'], directory)\n return stdout.trim() === ''\n}\n\n/**\n * Returns the latest tag of a git repository.\n *\n * @param directory - The directory to check.\n * @returns String with the latest tag or undefined if no tags are found.\n */\nexport async function getLatestTag(directory?: string): Promise<string | undefined> {\n try {\n const stdout = await gitCommand(['describe', '--tags', '--abbrev=0'], directory)\n return stdout.trim() || undefined\n } catch (error) {\n if (error instanceof AbortError && 'exitCode' in error && error.exitCode === 128) return undefined\n throw error\n }\n}\n\n/**\n * Remove a git remote from the given directory.\n *\n * @param directory - The directory where the git repository is located.\n * @param remoteName - The name of the remote to remove (defaults to 'origin').\n * @returns A promise that resolves when the remote is removed.\n */\nexport async function removeGitRemote(directory: string, remoteName = 'origin'): Promise<void> {\n outputDebug(outputContent`Removing git remote ${remoteName} from ${outputToken.path(directory)}...`)\n await ensureGitIsPresentOrAbort()\n\n const stdout = await gitCommand(['remote'], directory)\n const remotes = stdout.split('\\n').filter(Boolean)\n\n if (!remotes.includes(remoteName)) {\n outputDebug(outputContent`Remote ${remoteName} does not exist, no action needed`)\n return\n }\n\n await gitCommand(['remote', 'remove', remoteName], directory)\n}\n"]}
@@ -5,7 +5,7 @@ let _globalContext;
5
5
  * @returns Global context.
6
6
  */
7
7
  function getGlobalContext() {
8
- _globalContext ?? (_globalContext = { currentCommandId: '' });
8
+ _globalContext ??= { currentCommandId: '' };
9
9
  return _globalContext;
10
10
  }
11
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"global-context.js","sourceRoot":"","sources":["../../../src/public/node/global-context.ts"],"names":[],"mappings":"AAIA,IAAI,cAAyC,CAAA;AAE7C;;;;GAIG;AACH,SAAS,gBAAgB;IACvB,cAAc,KAAd,cAAc,GAAK,EAAC,gBAAgB,EAAE,EAAE,EAAC,EAAA;IACzC,OAAO,cAAc,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,gBAAgB,EAAE,CAAC,gBAAgB,CAAA;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,gBAAgB,EAAE,CAAC,gBAAgB,GAAG,SAAS,CAAA;AACjD,CAAC","sourcesContent":["export interface GlobalContext {\n currentCommandId: string\n}\n\nlet _globalContext: GlobalContext | undefined\n\n/**\n * Get the global context.\n *\n * @returns Global context.\n */\nfunction getGlobalContext(): GlobalContext {\n _globalContext ??= {currentCommandId: ''}\n return _globalContext\n}\n\n/**\n * Get the current command ID.\n *\n * @returns Current command ID.\n */\nexport function getCurrentCommandId(): string {\n return getGlobalContext().currentCommandId\n}\n\n/**\n * Set the current command ID.\n *\n * @param commandId - Command ID.\n */\nexport function setCurrentCommandId(commandId: string): void {\n getGlobalContext().currentCommandId = commandId\n}\n"]}
1
+ {"version":3,"file":"global-context.js","sourceRoot":"","sources":["../../../src/public/node/global-context.ts"],"names":[],"mappings":"AAIA,IAAI,cAAyC,CAAA;AAE7C;;;;GAIG;AACH,SAAS,gBAAgB;IACvB,cAAc,KAAK,EAAC,gBAAgB,EAAE,EAAE,EAAC,CAAA;IACzC,OAAO,cAAc,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,gBAAgB,EAAE,CAAC,gBAAgB,CAAA;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,gBAAgB,EAAE,CAAC,gBAAgB,GAAG,SAAS,CAAA;AACjD,CAAC","sourcesContent":["export interface GlobalContext {\n currentCommandId: string\n}\n\nlet _globalContext: GlobalContext | undefined\n\n/**\n * Get the global context.\n *\n * @returns Global context.\n */\nfunction getGlobalContext(): GlobalContext {\n _globalContext ??= {currentCommandId: ''}\n return _globalContext\n}\n\n/**\n * Get the current command ID.\n *\n * @returns Current command ID.\n */\nexport function getCurrentCommandId(): string {\n return getGlobalContext().currentCommandId\n}\n\n/**\n * Set the current command ID.\n *\n * @param commandId - Command ID.\n */\nexport function setCurrentCommandId(commandId: string): void {\n getGlobalContext().currentCommandId = commandId\n}\n"]}
@@ -12,13 +12,11 @@ const HIDDEN_FOLDER_NAME = '.shopify';
12
12
  export async function getOrCreateHiddenShopifyFolder(directory) {
13
13
  const hiddenFolder = joinPath(directory, HIDDEN_FOLDER_NAME);
14
14
  const gitignorePath = joinPath(hiddenFolder, '.gitignore');
15
- // Check if both the folder and .gitignore exist
16
- const [folderExists, gitignoreExists] = await Promise.all([fileExists(hiddenFolder), fileExists(gitignorePath)]);
17
- if (!folderExists) {
15
+ if (!(await fileExists(hiddenFolder))) {
18
16
  outputDebug(outputContent `Creating hidden .shopify folder at ${outputToken.path(hiddenFolder)}...`);
19
17
  await mkdir(hiddenFolder);
20
18
  }
21
- if (!gitignoreExists) {
19
+ if (!(await fileExists(gitignorePath))) {
22
20
  outputDebug(outputContent `Creating .gitignore in ${outputToken.path(hiddenFolder)}...`);
23
21
  await writeFile(gitignorePath, `# Ignore the entire ${HIDDEN_FOLDER_NAME} directory\n*`);
24
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hidden-folder.js","sourceRoot":"","sources":["../../../src/public/node/hidden-folder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAClC,OAAO,EAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAC,MAAM,SAAS,CAAA;AACpD,OAAO,EAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAEnE,MAAM,kBAAkB,GAAG,UAAU,CAAA;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,SAAiB;IACpE,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAA;IAC5D,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAC1D,gDAAgD;IAChD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAA;IAChH,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,WAAW,CAAC,aAAa,CAAA,sCAAsC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACnG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;IAC3B,CAAC;IACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,WAAW,CAAC,aAAa,CAAA,0BAA0B,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACvF,MAAM,SAAS,CAAC,aAAa,EAAE,uBAAuB,kBAAkB,eAAe,CAAC,CAAA;IAC1F,CAAC;IACD,OAAO,YAAY,CAAA;AACrB,CAAC","sourcesContent":["import {joinPath} from './path.js'\nimport {mkdir, writeFile, fileExists} from './fs.js'\nimport {outputDebug, outputContent, outputToken} from './output.js'\n\nconst HIDDEN_FOLDER_NAME = '.shopify'\n\n/**\n * Gets the path to the hidden .shopify folder for a given project directory.\n * Creates the folder if it doesn't exist.\n *\n * @param directory - The directory of the project.\n * @returns The path to the created hidden folder.\n */\nexport async function getOrCreateHiddenShopifyFolder(directory: string): Promise<string> {\n const hiddenFolder = joinPath(directory, HIDDEN_FOLDER_NAME)\n const gitignorePath = joinPath(hiddenFolder, '.gitignore')\n // Check if both the folder and .gitignore exist\n const [folderExists, gitignoreExists] = await Promise.all([fileExists(hiddenFolder), fileExists(gitignorePath)])\n if (!folderExists) {\n outputDebug(outputContent`Creating hidden .shopify folder at ${outputToken.path(hiddenFolder)}...`)\n await mkdir(hiddenFolder)\n }\n if (!gitignoreExists) {\n outputDebug(outputContent`Creating .gitignore in ${outputToken.path(hiddenFolder)}...`)\n await writeFile(gitignorePath, `# Ignore the entire ${HIDDEN_FOLDER_NAME} directory\\n*`)\n }\n return hiddenFolder\n}\n"]}
1
+ {"version":3,"file":"hidden-folder.js","sourceRoot":"","sources":["../../../src/public/node/hidden-folder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAClC,OAAO,EAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAC,MAAM,SAAS,CAAA;AACpD,OAAO,EAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAEnE,MAAM,kBAAkB,GAAG,UAAU,CAAA;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,SAAiB;IACpE,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAA;IAC5D,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAE1D,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtC,WAAW,CAAC,aAAa,CAAA,sCAAsC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACnG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;IAC3B,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QACvC,WAAW,CAAC,aAAa,CAAA,0BAA0B,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACvF,MAAM,SAAS,CAAC,aAAa,EAAE,uBAAuB,kBAAkB,eAAe,CAAC,CAAA;IAC1F,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC","sourcesContent":["import {joinPath} from './path.js'\nimport {mkdir, writeFile, fileExists} from './fs.js'\nimport {outputDebug, outputContent, outputToken} from './output.js'\n\nconst HIDDEN_FOLDER_NAME = '.shopify'\n\n/**\n * Gets the path to the hidden .shopify folder for a given project directory.\n * Creates the folder if it doesn't exist.\n *\n * @param directory - The directory of the project.\n * @returns The path to the created hidden folder.\n */\nexport async function getOrCreateHiddenShopifyFolder(directory: string): Promise<string> {\n const hiddenFolder = joinPath(directory, HIDDEN_FOLDER_NAME)\n const gitignorePath = joinPath(hiddenFolder, '.gitignore')\n\n if (!(await fileExists(hiddenFolder))) {\n outputDebug(outputContent`Creating hidden .shopify folder at ${outputToken.path(hiddenFolder)}...`)\n await mkdir(hiddenFolder)\n }\n\n if (!(await fileExists(gitignorePath))) {\n outputDebug(outputContent`Creating .gitignore in ${outputToken.path(hiddenFolder)}...`)\n await writeFile(gitignorePath, `# Ignore the entire ${HIDDEN_FOLDER_NAME} directory\\n*`)\n }\n\n return hiddenFolder\n}\n"]}
@@ -65,7 +65,7 @@ export const hook = async ({ config, Command }) => {
65
65
  const { outputDebug } = await import('../output.js');
66
66
  const command = Command.id.replace(/:/g, ' ');
67
67
  outputDebug(`Completed command ${command}`);
68
- if (!command.includes('notifications') && !command.includes('upgrade'))
68
+ if (!command.includes('notifications') && !command.includes('upgrade') && !command.includes('send-analytics'))
69
69
  await autoUpgradeIfNeeded();
70
70
  const { reportAnalyticsEvent } = await import('../analytics.js');
71
71
  await reportAnalyticsEvent({ config, exitMode: 'ok' });