@shopify/cli-kit 4.0.0 → 4.2.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 (76) hide show
  1. package/README.md +2 -2
  2. package/assets/graphiql/favicon.ico +0 -0
  3. package/assets/graphiql/style.css +58 -0
  4. package/dist/private/common/array.js +2 -1
  5. package/dist/private/common/array.js.map +1 -1
  6. package/dist/private/node/api/headers.js +6 -3
  7. package/dist/private/node/api/headers.js.map +1 -1
  8. package/dist/private/node/constants.d.ts +0 -1
  9. package/dist/private/node/constants.js +0 -1
  10. package/dist/private/node/constants.js.map +1 -1
  11. package/dist/private/node/session/device-authorization.js +4 -16
  12. package/dist/private/node/session/device-authorization.js.map +1 -1
  13. package/dist/private/node/ui.js +4 -1
  14. package/dist/private/node/ui.js.map +1 -1
  15. package/dist/public/common/gid.d.ts +24 -0
  16. package/dist/public/common/gid.js +32 -0
  17. package/dist/public/common/gid.js.map +1 -0
  18. package/dist/public/common/string.js +7 -6
  19. package/dist/public/common/string.js.map +1 -1
  20. package/dist/public/common/url.d.ts +16 -0
  21. package/dist/public/common/url.js +30 -0
  22. package/dist/public/common/url.js.map +1 -1
  23. package/dist/public/common/version.d.ts +1 -1
  24. package/dist/public/common/version.js +1 -1
  25. package/dist/public/common/version.js.map +1 -1
  26. package/dist/public/node/analytics.js +3 -5
  27. package/dist/public/node/analytics.js.map +1 -1
  28. package/dist/public/node/cli.d.ts +13 -0
  29. package/dist/public/node/cli.js +12 -0
  30. package/dist/public/node/cli.js.map +1 -1
  31. package/dist/public/node/context/local.d.ts +0 -7
  32. package/dist/public/node/context/local.js +18 -9
  33. package/dist/public/node/context/local.js.map +1 -1
  34. package/dist/public/node/error-handler.js +1 -1
  35. package/dist/public/node/error-handler.js.map +1 -1
  36. package/dist/public/node/git.js +8 -1
  37. package/dist/public/node/git.js.map +1 -1
  38. package/dist/public/node/graphiql/server.d.ts +80 -0
  39. package/dist/public/node/graphiql/server.js +234 -0
  40. package/dist/public/node/graphiql/server.js.map +1 -0
  41. package/dist/public/node/graphiql/templates/graphiql.d.ts +12 -0
  42. package/dist/public/node/graphiql/templates/graphiql.js +314 -0
  43. package/dist/public/node/graphiql/templates/graphiql.js.map +1 -0
  44. package/dist/public/node/graphiql/templates/unauthorized.d.ts +5 -0
  45. package/dist/public/node/graphiql/templates/unauthorized.js +111 -0
  46. package/dist/public/node/graphiql/templates/unauthorized.js.map +1 -0
  47. package/dist/public/node/graphiql/utilities.d.ts +12 -0
  48. package/dist/public/node/graphiql/utilities.js +44 -0
  49. package/dist/public/node/graphiql/utilities.js.map +1 -0
  50. package/dist/public/node/graphql.d.ts +19 -0
  51. package/dist/public/node/graphql.js +41 -0
  52. package/dist/public/node/graphql.js.map +1 -0
  53. package/dist/public/node/hooks/postrun.js +12 -2
  54. package/dist/public/node/hooks/postrun.js.map +1 -1
  55. package/dist/public/node/http.js +27 -31
  56. package/dist/public/node/http.js.map +1 -1
  57. package/dist/public/node/import-extractor.js +4 -3
  58. package/dist/public/node/import-extractor.js.map +1 -1
  59. package/dist/public/node/metadata.d.ts +3 -0
  60. package/dist/public/node/metadata.js.map +1 -1
  61. package/dist/public/node/monorail.d.ts +2 -1
  62. package/dist/public/node/monorail.js +1 -1
  63. package/dist/public/node/monorail.js.map +1 -1
  64. package/dist/public/node/output.js +22 -11
  65. package/dist/public/node/output.js.map +1 -1
  66. package/dist/public/node/system.js +5 -42
  67. package/dist/public/node/system.js.map +1 -1
  68. package/dist/public/node/tcp.js +11 -3
  69. package/dist/public/node/tcp.js.map +1 -1
  70. package/dist/public/node/themes/api.js +76 -4
  71. package/dist/public/node/themes/api.js.map +1 -1
  72. package/dist/public/node/toml/toml-file.d.ts +3 -2
  73. package/dist/public/node/toml/toml-file.js +3 -2
  74. package/dist/public/node/toml/toml-file.js.map +1 -1
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +34 -29
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../src/public/node/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,EAAC,MAAM,SAAS,CAAA;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,aAAsB;IACpE,IAAI,QAAQ,CAAA;IACZ,IAAI,CAAC;QACH,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QACvB,sGAAsG;IACxG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAC5C,CAAC,UAAU,EAAyC,EAAE,CAAC,UAAU,CAAC,IAAI,KAAK,qBAAqB,CACjG,CAAA;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEzC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,KAAK,aAAa,CAAC,CAAA;QACtF,OAAO,MAAM,EAAE,SAAS,KAAK,UAAU,CAAA;IACzC,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,UAAU,CAAC,CAAC,CAAE,CAAC,SAAS,KAAK,UAAU,CAAA;IAChD,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,SAAS,KAAK,UAAU,CAAC,CAAA;AAC3E,CAAC","sourcesContent":["import {OperationDefinitionNode, parse} from 'graphql'\n\n/**\n * Returns true if the GraphQL document contains a mutation operation that\n * would actually be executed for the given (optional) operation name.\n *\n * - When `operationName` is provided, only the matching operation is checked.\n * - When `operationName` is omitted and the document has a single operation,\n * that operation is checked.\n * - When the document has multiple operations and no operation name is given,\n * any mutation in the document is treated as a mutation request (the GraphQL\n * server would reject the ambiguous request anyway).\n *\n * Returns false for queries, subscriptions, fragment-only documents, and any\n * input that fails to parse as GraphQL.\n *\n * @param query - The GraphQL document to inspect.\n * @param operationName - Optional name of the operation to check; when set, only that operation is considered.\n * @returns True if the relevant operation is a mutation; false otherwise.\n */\nexport function containsMutation(query: string, operationName?: string): boolean {\n let document\n try {\n document = parse(query)\n // eslint-disable-next-line no-catch-all/no-catch-all -- swallowing parse errors is the entire purpose\n } catch {\n return false\n }\n\n const operations = document.definitions.filter(\n (definition): definition is OperationDefinitionNode => definition.kind === 'OperationDefinition',\n )\n\n if (operations.length === 0) return false\n\n if (operationName) {\n const target = operations.find((operation) => operation.name?.value === operationName)\n return target?.operation === 'mutation'\n }\n\n if (operations.length === 1) {\n return operations[0]!.operation === 'mutation'\n }\n\n return operations.some((operation) => operation.operation === 'mutation')\n}\n"]}
@@ -50,8 +50,16 @@ export function waitForPostRunHookAndExit() {
50
50
  // This hook is called after each successful command run. More info: https://oclif.io/docs/hooks
51
51
  export const hook = async ({ config, Command }) => {
52
52
  await detectStopCommand(Command);
53
- const { reportAnalyticsEvent } = await import('../analytics.js');
54
- await reportAnalyticsEvent({ config, exitMode: 'ok' });
53
+ const metadata = await import('../metadata.js');
54
+ const { commandStartOptions } = metadata.getAllSensitiveMetadata();
55
+ if (commandStartOptions) {
56
+ await metadata.addSensitiveMetadata(() => ({
57
+ commandStartOptions: {
58
+ ...commandStartOptions,
59
+ endTime: new Date().getTime(),
60
+ },
61
+ }));
62
+ }
55
63
  const { postrun: deprecationsHook } = await import('./deprecations.js');
56
64
  deprecationsHook(Command);
57
65
  const { outputDebug } = await import('../output.js');
@@ -59,6 +67,8 @@ export const hook = async ({ config, Command }) => {
59
67
  outputDebug(`Completed command ${command}`);
60
68
  if (!command.includes('notifications') && !command.includes('upgrade'))
61
69
  await autoUpgradeIfNeeded();
70
+ const { reportAnalyticsEvent } = await import('../analytics.js');
71
+ await reportAnalyticsEvent({ config, exitMode: 'ok' });
62
72
  postRunHookCompleted = true;
63
73
  };
64
74
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"postrun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/postrun.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Postrun hook — uses dynamic imports to avoid loading heavy modules (base-command, analytics)\n * at module evaluation time. These are only needed after the command has already finished.\n */\nimport {treeKill} from '../tree-kill.js'\nimport {Command, Hook} from '@oclif/core'\n\nlet postRunHookCompleted = false\n\n/**\n * Check if post run hook has completed.\n *\n * @returns Whether post run hook has completed.\n */\nexport function postRunHookHasCompleted(): boolean {\n return postRunHookCompleted\n}\n\n/**\n * Wait for the postrun hook to finish (so auto-upgrade has a chance to run) and then\n * tree-kill the current process tree before exiting.\n *\n * Long-running interactive commands like `app dev` need this when the user terminates\n * the command via `q` or Ctrl+C. The dev sub-processes such as servers and watchers keep\n * the event loop alive, so even after oclif's postrun hook completes the node process\n * won't exit on its own and we have to `treeKill` the process tree. We must not do that\n * before the postrun hook has actually finished running auto-upgrade, otherwise we would\n * kill the upgrade mid-way while `npm install` is still running.\n *\n * The flag `postRunHookCompleted` is flipped at the very end of the hook after\n * `autoUpgradeIfNeeded` resolves, so polling it here is safe.\n */\nexport function waitForPostRunHookAndExit(): void {\n const pollIntervalMs = 100\n // Auto-upgrade can take a while (npm/pnpm/yarn install). Cap the wait generously so\n // a stuck upgrade still terminates the process eventually.\n const maxWaitMs = 120000\n\n let elapsed = 0\n let terminating = false\n const handle = setInterval(() => {\n if (terminating) return\n if (postRunHookHasCompleted() || elapsed >= maxWaitMs) {\n terminating = true\n clearInterval(handle)\n treeKill(process.pid, 'SIGINT', false, () => {\n process.exit(0)\n })\n return\n }\n elapsed += pollIntervalMs\n }, pollIntervalMs)\n}\n\n// This hook is called after each successful command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Postrun = async ({config, Command}) => {\n await detectStopCommand(Command as unknown as typeof Command)\n\n const {reportAnalyticsEvent} = await import('../analytics.js')\n await reportAnalyticsEvent({config, exitMode: 'ok'})\n\n const {postrun: deprecationsHook} = await import('./deprecations.js')\n deprecationsHook(Command)\n\n const {outputDebug} = await import('../output.js')\n const command = Command.id.replace(/:/g, ' ')\n outputDebug(`Completed command ${command}`)\n\n if (!command.includes('notifications') && !command.includes('upgrade')) await autoUpgradeIfNeeded()\n postRunHookCompleted = true\n}\n\n/**\n * Auto-upgrades the CLI after a command completes, if a newer version is available.\n * The entire flow is rate-limited to once per day unless forced via SHOPIFY_CLI_FORCE_AUTO_UPGRADE.\n *\n * @returns Resolves when the upgrade attempt (or fallback warning) is complete.\n */\nexport async function autoUpgradeIfNeeded(): Promise<void> {\n const {versionToAutoUpgrade, warnIfUpgradeAvailable} = await import('../upgrade.js')\n const newerVersion = versionToAutoUpgrade()\n if (!newerVersion) {\n await warnIfUpgradeAvailable()\n return\n }\n\n const forced = process.env.SHOPIFY_CLI_FORCE_AUTO_UPGRADE === '1'\n\n // SHOPIFY_CLI_FORCE_AUTO_UPGRADE bypasses the daily rate limit so tests and intentional upgrades always run.\n if (forced) {\n await performAutoUpgrade(newerVersion)\n } else {\n const {runAtMinimumInterval} = await import('../../../private/node/conf-store.js')\n // Rate-limit the entire upgrade flow to once per day to avoid repeated attempts and major-version warnings.\n await runAtMinimumInterval('auto-upgrade', {days: 1}, async () => {\n await performAutoUpgrade(newerVersion)\n })\n }\n}\n\nasync function performAutoUpgrade(newerVersion: string): Promise<void> {\n const [\n {CLI_KIT_VERSION},\n {isMajorVersionChange},\n {outputWarn, outputDebug},\n {getOutputUpdateCLIReminder, runCLIUpgrade, hasBlockingAutoUpgradeNotification},\n metadata,\n ] = await Promise.all([\n import('../../common/version.js'),\n import('../version.js'),\n import('../output.js'),\n import('../upgrade.js'),\n import('../metadata.js'),\n ])\n\n if (isMajorVersionChange(CLI_KIT_VERSION, newerVersion)) {\n outputWarn(getOutputUpdateCLIReminder(newerVersion, true))\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'major_version',\n }))\n return\n }\n\n // Notification kill switch: an `error`-type notification on the `autoupgrade` surface\n // silently disables auto-upgrade. Checked last — after every other gate, including the\n // daily rate limit and the major-version check — so the network fetch only happens when\n // we're about to actually run the upgrade.\n if (await hasBlockingAutoUpgradeNotification()) {\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'blocked_by_notification',\n }))\n return\n }\n\n try {\n await runCLIUpgrade({autoupgrade: true})\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: true}))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n const errorMessage = `Auto-upgrade failed: ${error}`\n outputDebug(errorMessage)\n outputWarn(getOutputUpdateCLIReminder(newerVersion))\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: false}))\n // Report to Observe as a handled error without showing anything extra to the user\n const [{sendErrorToBugsnag}, {inferPackageManagerForGlobalCLI}] = await Promise.all([\n import('../error-handler.js'),\n import('../is-global.js'),\n ])\n const enrichedError = Object.assign(new Error(errorMessage), {\n packageManager: inferPackageManagerForGlobalCLI(),\n platform: process.platform,\n cliVersion: CLI_KIT_VERSION,\n })\n await sendErrorToBugsnag(enrichedError, 'expected_error')\n }\n}\n\n/**\n * Override the command name with the stop one for analytics purposes.\n *\n * @param commandClass - Command.Class.\n */\nasync function detectStopCommand(commandClass: Command.Class): Promise<void> {\n const currentTime = new Date().getTime()\n // Check for analyticsStopCommand without importing BaseCommand\n if (\n commandClass &&\n 'analyticsStopCommand' in commandClass &&\n typeof commandClass.analyticsStopCommand === 'function'\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stopCommand = (commandClass as any).analyticsStopCommand()\n if (stopCommand) {\n const metadata = await import('../metadata.js')\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n if (!commandStartOptions) return\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n ...commandStartOptions,\n startTime: currentTime,\n startCommand: stopCommand,\n },\n }))\n }\n }\n}\n"]}
1
+ {"version":3,"file":"postrun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/postrun.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Postrun hook — uses dynamic imports to avoid loading heavy modules (base-command, analytics)\n * at module evaluation time. These are only needed after the command has already finished.\n */\nimport {treeKill} from '../tree-kill.js'\nimport {Command, Hook} from '@oclif/core'\n\nlet postRunHookCompleted = false\n\n/**\n * Check if post run hook has completed.\n *\n * @returns Whether post run hook has completed.\n */\nexport function postRunHookHasCompleted(): boolean {\n return postRunHookCompleted\n}\n\n/**\n * Wait for the postrun hook to finish (so auto-upgrade has a chance to run) and then\n * tree-kill the current process tree before exiting.\n *\n * Long-running interactive commands like `app dev` need this when the user terminates\n * the command via `q` or Ctrl+C. The dev sub-processes such as servers and watchers keep\n * the event loop alive, so even after oclif's postrun hook completes the node process\n * won't exit on its own and we have to `treeKill` the process tree. We must not do that\n * before the postrun hook has actually finished running auto-upgrade, otherwise we would\n * kill the upgrade mid-way while `npm install` is still running.\n *\n * The flag `postRunHookCompleted` is flipped at the very end of the hook after\n * `autoUpgradeIfNeeded` resolves, so polling it here is safe.\n */\nexport function waitForPostRunHookAndExit(): void {\n const pollIntervalMs = 100\n // Auto-upgrade can take a while (npm/pnpm/yarn install). Cap the wait generously so\n // a stuck upgrade still terminates the process eventually.\n const maxWaitMs = 120000\n\n let elapsed = 0\n let terminating = false\n const handle = setInterval(() => {\n if (terminating) return\n if (postRunHookHasCompleted() || elapsed >= maxWaitMs) {\n terminating = true\n clearInterval(handle)\n treeKill(process.pid, 'SIGINT', false, () => {\n process.exit(0)\n })\n return\n }\n elapsed += pollIntervalMs\n }, pollIntervalMs)\n}\n\n// This hook is called after each successful command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Postrun = async ({config, Command}) => {\n await detectStopCommand(Command as unknown as typeof Command)\n\n const metadata = await import('../metadata.js')\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n if (commandStartOptions) {\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n ...commandStartOptions,\n endTime: new Date().getTime(),\n },\n }))\n }\n\n const {postrun: deprecationsHook} = await import('./deprecations.js')\n deprecationsHook(Command)\n\n const {outputDebug} = await import('../output.js')\n const command = Command.id.replace(/:/g, ' ')\n outputDebug(`Completed command ${command}`)\n\n if (!command.includes('notifications') && !command.includes('upgrade')) await autoUpgradeIfNeeded()\n\n const {reportAnalyticsEvent} = await import('../analytics.js')\n await reportAnalyticsEvent({config, exitMode: 'ok'})\n\n postRunHookCompleted = true\n}\n\n/**\n * Auto-upgrades the CLI after a command completes, if a newer version is available.\n * The entire flow is rate-limited to once per day unless forced via SHOPIFY_CLI_FORCE_AUTO_UPGRADE.\n *\n * @returns Resolves when the upgrade attempt (or fallback warning) is complete.\n */\nexport async function autoUpgradeIfNeeded(): Promise<void> {\n const {versionToAutoUpgrade, warnIfUpgradeAvailable} = await import('../upgrade.js')\n const newerVersion = versionToAutoUpgrade()\n if (!newerVersion) {\n await warnIfUpgradeAvailable()\n return\n }\n\n const forced = process.env.SHOPIFY_CLI_FORCE_AUTO_UPGRADE === '1'\n\n // SHOPIFY_CLI_FORCE_AUTO_UPGRADE bypasses the daily rate limit so tests and intentional upgrades always run.\n if (forced) {\n await performAutoUpgrade(newerVersion)\n } else {\n const {runAtMinimumInterval} = await import('../../../private/node/conf-store.js')\n // Rate-limit the entire upgrade flow to once per day to avoid repeated attempts and major-version warnings.\n await runAtMinimumInterval('auto-upgrade', {days: 1}, async () => {\n await performAutoUpgrade(newerVersion)\n })\n }\n}\n\nasync function performAutoUpgrade(newerVersion: string): Promise<void> {\n const [\n {CLI_KIT_VERSION},\n {isMajorVersionChange},\n {outputWarn, outputDebug},\n {getOutputUpdateCLIReminder, runCLIUpgrade, hasBlockingAutoUpgradeNotification},\n metadata,\n ] = await Promise.all([\n import('../../common/version.js'),\n import('../version.js'),\n import('../output.js'),\n import('../upgrade.js'),\n import('../metadata.js'),\n ])\n\n if (isMajorVersionChange(CLI_KIT_VERSION, newerVersion)) {\n outputWarn(getOutputUpdateCLIReminder(newerVersion, true))\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'major_version',\n }))\n return\n }\n\n // Notification kill switch: an `error`-type notification on the `autoupgrade` surface\n // silently disables auto-upgrade. Checked last — after every other gate, including the\n // daily rate limit and the major-version check — so the network fetch only happens when\n // we're about to actually run the upgrade.\n if (await hasBlockingAutoUpgradeNotification()) {\n await metadata.addPublicMetadata(() => ({\n env_auto_upgrade_skipped_reason: 'blocked_by_notification',\n }))\n return\n }\n\n try {\n await runCLIUpgrade({autoupgrade: true})\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: true}))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n const errorMessage = `Auto-upgrade failed: ${error}`\n outputDebug(errorMessage)\n outputWarn(getOutputUpdateCLIReminder(newerVersion))\n await metadata.addPublicMetadata(() => ({env_auto_upgrade_success: false}))\n // Report to Observe as a handled error without showing anything extra to the user\n const [{sendErrorToBugsnag}, {inferPackageManagerForGlobalCLI}] = await Promise.all([\n import('../error-handler.js'),\n import('../is-global.js'),\n ])\n const enrichedError = Object.assign(new Error(errorMessage), {\n packageManager: inferPackageManagerForGlobalCLI(),\n platform: process.platform,\n cliVersion: CLI_KIT_VERSION,\n })\n await sendErrorToBugsnag(enrichedError, 'expected_error')\n }\n}\n\n/**\n * Override the command name with the stop one for analytics purposes.\n *\n * @param commandClass - Command.Class.\n */\nasync function detectStopCommand(commandClass: Command.Class): Promise<void> {\n const currentTime = new Date().getTime()\n // Check for analyticsStopCommand without importing BaseCommand\n if (\n commandClass &&\n 'analyticsStopCommand' in commandClass &&\n typeof commandClass.analyticsStopCommand === 'function'\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stopCommand = (commandClass as any).analyticsStopCommand()\n if (stopCommand) {\n const metadata = await import('../metadata.js')\n const {commandStartOptions} = metadata.getAllSensitiveMetadata()\n if (!commandStartOptions) return\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n ...commandStartOptions,\n startTime: currentTime,\n startCommand: stopCommand,\n },\n }))\n }\n }\n}\n"]}
@@ -9,6 +9,7 @@ import { simpleRequestWithDebugLog } from '../../private/node/api.js';
9
9
  import { DEFAULT_MAX_TIME_MS } from '../../private/node/sleep-with-backoff.js';
10
10
  import FormData from 'form-data';
11
11
  import nodeFetch from 'node-fetch';
12
+ import { pipeline } from 'stream/promises';
12
13
  export { FetchError, Request, Response } from 'node-fetch';
13
14
  /**
14
15
  * Create a new FormData object.
@@ -170,39 +171,34 @@ export async function shopifyFetch(url, init, preferredBehaviour) {
170
171
  export function downloadFile(url, to) {
171
172
  const sanitizedUrl = sanitizeURL(url);
172
173
  outputDebug(`Downloading ${sanitizedUrl} to ${to}`);
173
- return runWithTimer('cmd_all_timing_network_ms')(() => {
174
- return new Promise((resolve, reject) => {
175
- if (!fileExistsSync(dirname(to))) {
176
- mkdirSync(dirname(to));
177
- }
178
- const file = createFileWriteStream(to);
179
- // if we can't remove the file for some reason (seen on windows), that's ok -- it's in a temporary directory
180
- const tryToRemoveFile = () => {
181
- try {
174
+ return runWithTimer('cmd_all_timing_network_ms')(async () => {
175
+ if (!fileExistsSync(dirname(to))) {
176
+ mkdirSync(dirname(to));
177
+ }
178
+ // if we can't remove the file for some reason (seen on windows), that's ok -- it's in a temporary directory
179
+ const tryToRemoveFile = () => {
180
+ try {
181
+ if (fileExistsSync(to)) {
182
182
  unlinkFileSync(to);
183
- // eslint-disable-next-line no-catch-all/no-catch-all
184
183
  }
185
- catch (err) {
186
- outputDebug(outputContent `Failed to remove file ${outputToken.path(to)}: ${outputToken.raw(String(err))}`);
187
- }
188
- };
189
- file.on('finish', () => {
190
- file.close();
191
- resolve(to);
192
- });
193
- file.on('error', (err) => {
194
- tryToRemoveFile();
195
- reject(err);
196
- });
197
- nodeFetch(url, { redirect: 'follow' })
198
- .then((res) => {
199
- res.body?.pipe(file);
200
- })
201
- .catch((err) => {
202
- tryToRemoveFile();
203
- reject(err instanceof Error ? err : new Error(String(err)));
204
- });
205
- });
184
+ // eslint-disable-next-line no-catch-all/no-catch-all
185
+ }
186
+ catch (err) {
187
+ outputDebug(outputContent `Failed to remove file ${outputToken.path(to)}: ${outputToken.raw(String(err))}`);
188
+ }
189
+ };
190
+ try {
191
+ const res = await nodeFetch(url, { redirect: 'follow' });
192
+ if (!res.body) {
193
+ throw new Error(`No response body received when downloading ${sanitizedUrl}`);
194
+ }
195
+ await pipeline(res.body, createFileWriteStream(to));
196
+ return to;
197
+ }
198
+ catch (err) {
199
+ tryToRemoveFile();
200
+ throw err instanceof Error ? err : new Error(String(err));
201
+ }
206
202
  });
207
203
  }
208
204
  //# sourceMappingURL=http.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/public/node/http.ts"],"names":[],"mappings":"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","sourcesContent":["import {dirname} from './path.js'\nimport {createFileWriteStream, fileExistsSync, mkdirSync, unlinkFileSync} from './fs.js'\nimport {runWithTimer} from './metadata.js'\nimport {maxRequestTimeForNetworkCallsMs, skipNetworkLevelRetry} from './environment.js'\nimport {outputContent, outputDebug, outputToken} from './output.js'\nimport {sanitizeURL} from '../../private/node/api/urls.js'\nimport {httpsAgent, sanitizedHeadersOutput} from '../../private/node/api/headers.js'\nimport {NetworkRetryBehaviour, simpleRequestWithDebugLog} from '../../private/node/api.js'\nimport {DEFAULT_MAX_TIME_MS} from '../../private/node/sleep-with-backoff.js'\n\nimport FormData from 'form-data'\nimport nodeFetch, {RequestInfo, RequestInit, Response} from 'node-fetch'\n\nexport {FetchError, Request, Response} from 'node-fetch'\n\n/**\n * Create a new FormData object.\n *\n * @returns A FormData object.\n */\nexport function formData(): FormData {\n return new FormData()\n}\n\ntype AbortSignal = RequestInit['signal']\n\ntype PresetFetchBehaviour = 'default' | 'non-blocking' | 'slow-request'\n\ntype AutomaticCancellationBehaviour =\n | {\n useAbortSignal: true\n timeoutMs: number\n }\n | {\n useAbortSignal: false\n }\n | {\n useAbortSignal: AbortSignal | (() => AbortSignal)\n }\n\nexport type RequestBehaviour = NetworkRetryBehaviour & AutomaticCancellationBehaviour\n\nexport type RequestModeInput = PresetFetchBehaviour | RequestBehaviour\n\n/**\n * Specify the behaviour of a network request.\n *\n * - default: Requests are automatically retried, and are subject to automatic cancellation if they're taking too long.\n * This is generally desirable.\n * - non-blocking: Requests are not retried if they fail with a network error, and are automatically cancelled if\n * they're taking too long. This is good for throwaway requests, like polling or tracking.\n * - slow-request: Requests are not retried if they fail with a network error, and are not automatically cancelled.\n * This is good for slow requests that should be give the chance to complete, and are unlikely to be safe to retry.\n *\n * Some request behaviours may be de-activated by the environment, and this function takes care of that concern. You\n * can also provide a customised request behaviour.\n *\n * @param preset - The preset to use.\n * @param env - Process environment variables.\n * @returns A request behaviour object.\n */\nexport function requestMode(\n preset: RequestModeInput = 'default',\n env: NodeJS.ProcessEnv = process.env,\n): RequestBehaviour {\n const networkLevelRetryIsSupported = !skipNetworkLevelRetry(env)\n switch (preset) {\n case 'default':\n return {\n useNetworkLevelRetry: networkLevelRetryIsSupported,\n maxRetryTimeMs: DEFAULT_MAX_TIME_MS,\n useAbortSignal: true,\n timeoutMs: maxRequestTimeForNetworkCallsMs(env),\n }\n case 'non-blocking':\n return {\n useNetworkLevelRetry: false,\n useAbortSignal: true,\n timeoutMs: maxRequestTimeForNetworkCallsMs(env),\n }\n case 'slow-request':\n return {\n useNetworkLevelRetry: false,\n useAbortSignal: false,\n }\n }\n return {\n ...preset,\n useNetworkLevelRetry: networkLevelRetryIsSupported && preset.useNetworkLevelRetry,\n } as RequestBehaviour\n}\n\ninterface FetchOptions {\n url: RequestInfo\n behaviour: RequestBehaviour\n init?: RequestInit\n logRequest: boolean\n useHttpsAgent: boolean\n}\n\n/**\n * Create an AbortSignal for automatic request cancellation, from a request behaviour.\n *\n * @param behaviour - The request behaviour.\n * @returns An AbortSignal.\n */\nexport function abortSignalFromRequestBehaviour(behaviour: RequestBehaviour): AbortSignal {\n let signal: AbortSignal\n if (behaviour.useAbortSignal === true) {\n signal = AbortSignal.timeout(behaviour.timeoutMs)\n } else if (behaviour.useAbortSignal && typeof behaviour.useAbortSignal === 'function') {\n signal = behaviour.useAbortSignal()\n } else if (behaviour.useAbortSignal) {\n signal = behaviour.useAbortSignal\n }\n return signal\n}\n\nasync function innerFetch({url, behaviour, init, logRequest, useHttpsAgent}: FetchOptions): Promise<Response> {\n if (logRequest) {\n outputDebug(outputContent`Sending ${init?.method ?? 'GET'} request to URL ${sanitizeURL(url.toString())}\nWith request headers:\n${sanitizedHeadersOutput((init?.headers ?? {}) as Record<string, string>)}\n`)\n }\n\n let agent: RequestInit['agent']\n if (useHttpsAgent) {\n agent = await httpsAgent()\n }\n\n const request = async () => {\n // each time we make the request, we need to potentially reset the abort signal, as the request logic may make\n // the same request multiple times.\n let signal = abortSignalFromRequestBehaviour(behaviour)\n\n // it's possible to provide a signal through the request's init structure.\n if (init?.signal) {\n signal = init.signal\n }\n\n return nodeFetch(url, {...init, agent, signal})\n }\n\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n return simpleRequestWithDebugLog({\n url: url.toString(),\n request,\n ...behaviour,\n })\n })\n}\n\n/**\n * An interface that abstracts way node-fetch. When Node has built-in\n * support for \"fetch\" in the standard library, we can drop the node-fetch\n * dependency from here.\n * Note that we are exposing types from \"node-fetch\". The reason being is that\n * they are consistent with the Web API so if we drop node-fetch in the future\n * it won't require changes from the callers.\n *\n * The CLI's fetch function supports special behaviours, like automatic retries. These are disabled by default through\n * this function.\n *\n * @param url - This defines the resource that you wish to fetch.\n * @param init - An object containing any custom settings that you want to apply to the request.\n * @param preferredBehaviour - A request behaviour object that overrides the default behaviour.\n * @returns A promise that resolves with the response.\n */\nexport async function fetch(\n url: RequestInfo,\n init?: RequestInit,\n preferredBehaviour?: RequestModeInput,\n): Promise<Response> {\n const options = {\n url,\n init,\n logRequest: false,\n useHttpsAgent: false,\n // all special behaviours are disabled by default\n behaviour: preferredBehaviour ? requestMode(preferredBehaviour) : requestMode('non-blocking'),\n } as const\n\n return innerFetch(options)\n}\n\n/**\n * A fetch function to use with Shopify services. The function ensures the right\n * TLS configuragion is used based on the environment in which the service is running\n * (e.g. Local). NB: headers/auth are the responsibility of the caller.\n *\n * By default, the CLI's fetch function's special behaviours, like automatic retries, are enabled.\n *\n * @param url - This defines the resource that you wish to fetch.\n * @param init - An object containing any custom settings that you want to apply to the request.\n * @param preferredBehaviour - A request behaviour object that overrides the default behaviour.\n * @returns A promise that resolves with the response.\n */\nexport async function shopifyFetch(\n url: RequestInfo,\n init?: RequestInit,\n preferredBehaviour?: RequestModeInput,\n): Promise<Response> {\n const options = {\n url,\n init,\n logRequest: true,\n useHttpsAgent: true,\n // special behaviours enabled by default\n behaviour: preferredBehaviour ? requestMode(preferredBehaviour) : requestMode(),\n }\n\n return innerFetch(options)\n}\n\n/**\n * Download a file from a URL to a local path.\n *\n * @param url - The URL to download from.\n * @param to - The local path to download to.\n * @returns - A promise that resolves with the local path.\n */\nexport function downloadFile(url: string, to: string): Promise<string> {\n const sanitizedUrl = sanitizeURL(url)\n outputDebug(`Downloading ${sanitizedUrl} to ${to}`)\n\n return runWithTimer('cmd_all_timing_network_ms')(() => {\n return new Promise<string>((resolve, reject) => {\n if (!fileExistsSync(dirname(to))) {\n mkdirSync(dirname(to))\n }\n\n const file = createFileWriteStream(to)\n\n // if we can't remove the file for some reason (seen on windows), that's ok -- it's in a temporary directory\n const tryToRemoveFile = () => {\n try {\n unlinkFileSync(to)\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err: unknown) {\n outputDebug(outputContent`Failed to remove file ${outputToken.path(to)}: ${outputToken.raw(String(err))}`)\n }\n }\n\n file.on('finish', () => {\n file.close()\n resolve(to)\n })\n\n file.on('error', (err) => {\n tryToRemoveFile()\n reject(err)\n })\n\n nodeFetch(url, {redirect: 'follow'})\n .then((res) => {\n res.body?.pipe(file)\n })\n .catch((err) => {\n tryToRemoveFile()\n reject(err instanceof Error ? err : new Error(String(err)))\n })\n })\n })\n}\n"]}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/public/node/http.ts"],"names":[],"mappings":"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","sourcesContent":["import {dirname} from './path.js'\nimport {createFileWriteStream, fileExistsSync, mkdirSync, unlinkFileSync} from './fs.js'\nimport {runWithTimer} from './metadata.js'\nimport {maxRequestTimeForNetworkCallsMs, skipNetworkLevelRetry} from './environment.js'\nimport {outputContent, outputDebug, outputToken} from './output.js'\nimport {sanitizeURL} from '../../private/node/api/urls.js'\nimport {httpsAgent, sanitizedHeadersOutput} from '../../private/node/api/headers.js'\nimport {NetworkRetryBehaviour, simpleRequestWithDebugLog} from '../../private/node/api.js'\nimport {DEFAULT_MAX_TIME_MS} from '../../private/node/sleep-with-backoff.js'\n\nimport FormData from 'form-data'\nimport nodeFetch, {RequestInfo, RequestInit, Response} from 'node-fetch'\nimport {pipeline} from 'stream/promises'\n\nexport {FetchError, Request, Response} from 'node-fetch'\n\n/**\n * Create a new FormData object.\n *\n * @returns A FormData object.\n */\nexport function formData(): FormData {\n return new FormData()\n}\n\ntype AbortSignal = RequestInit['signal']\n\ntype PresetFetchBehaviour = 'default' | 'non-blocking' | 'slow-request'\n\ntype AutomaticCancellationBehaviour =\n | {\n useAbortSignal: true\n timeoutMs: number\n }\n | {\n useAbortSignal: false\n }\n | {\n useAbortSignal: AbortSignal | (() => AbortSignal)\n }\n\nexport type RequestBehaviour = NetworkRetryBehaviour & AutomaticCancellationBehaviour\n\nexport type RequestModeInput = PresetFetchBehaviour | RequestBehaviour\n\n/**\n * Specify the behaviour of a network request.\n *\n * - default: Requests are automatically retried, and are subject to automatic cancellation if they're taking too long.\n * This is generally desirable.\n * - non-blocking: Requests are not retried if they fail with a network error, and are automatically cancelled if\n * they're taking too long. This is good for throwaway requests, like polling or tracking.\n * - slow-request: Requests are not retried if they fail with a network error, and are not automatically cancelled.\n * This is good for slow requests that should be give the chance to complete, and are unlikely to be safe to retry.\n *\n * Some request behaviours may be de-activated by the environment, and this function takes care of that concern. You\n * can also provide a customised request behaviour.\n *\n * @param preset - The preset to use.\n * @param env - Process environment variables.\n * @returns A request behaviour object.\n */\nexport function requestMode(\n preset: RequestModeInput = 'default',\n env: NodeJS.ProcessEnv = process.env,\n): RequestBehaviour {\n const networkLevelRetryIsSupported = !skipNetworkLevelRetry(env)\n switch (preset) {\n case 'default':\n return {\n useNetworkLevelRetry: networkLevelRetryIsSupported,\n maxRetryTimeMs: DEFAULT_MAX_TIME_MS,\n useAbortSignal: true,\n timeoutMs: maxRequestTimeForNetworkCallsMs(env),\n }\n case 'non-blocking':\n return {\n useNetworkLevelRetry: false,\n useAbortSignal: true,\n timeoutMs: maxRequestTimeForNetworkCallsMs(env),\n }\n case 'slow-request':\n return {\n useNetworkLevelRetry: false,\n useAbortSignal: false,\n }\n }\n return {\n ...preset,\n useNetworkLevelRetry: networkLevelRetryIsSupported && preset.useNetworkLevelRetry,\n } as RequestBehaviour\n}\n\ninterface FetchOptions {\n url: RequestInfo\n behaviour: RequestBehaviour\n init?: RequestInit\n logRequest: boolean\n useHttpsAgent: boolean\n}\n\n/**\n * Create an AbortSignal for automatic request cancellation, from a request behaviour.\n *\n * @param behaviour - The request behaviour.\n * @returns An AbortSignal.\n */\nexport function abortSignalFromRequestBehaviour(behaviour: RequestBehaviour): AbortSignal {\n let signal: AbortSignal\n if (behaviour.useAbortSignal === true) {\n signal = AbortSignal.timeout(behaviour.timeoutMs)\n } else if (behaviour.useAbortSignal && typeof behaviour.useAbortSignal === 'function') {\n signal = behaviour.useAbortSignal()\n } else if (behaviour.useAbortSignal) {\n signal = behaviour.useAbortSignal\n }\n return signal\n}\n\nasync function innerFetch({url, behaviour, init, logRequest, useHttpsAgent}: FetchOptions): Promise<Response> {\n if (logRequest) {\n outputDebug(outputContent`Sending ${init?.method ?? 'GET'} request to URL ${sanitizeURL(url.toString())}\nWith request headers:\n${sanitizedHeadersOutput((init?.headers ?? {}) as Record<string, string>)}\n`)\n }\n\n let agent: RequestInit['agent']\n if (useHttpsAgent) {\n agent = await httpsAgent()\n }\n\n const request = async () => {\n // each time we make the request, we need to potentially reset the abort signal, as the request logic may make\n // the same request multiple times.\n let signal = abortSignalFromRequestBehaviour(behaviour)\n\n // it's possible to provide a signal through the request's init structure.\n if (init?.signal) {\n signal = init.signal\n }\n\n return nodeFetch(url, {...init, agent, signal})\n }\n\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n return simpleRequestWithDebugLog({\n url: url.toString(),\n request,\n ...behaviour,\n })\n })\n}\n\n/**\n * An interface that abstracts way node-fetch. When Node has built-in\n * support for \"fetch\" in the standard library, we can drop the node-fetch\n * dependency from here.\n * Note that we are exposing types from \"node-fetch\". The reason being is that\n * they are consistent with the Web API so if we drop node-fetch in the future\n * it won't require changes from the callers.\n *\n * The CLI's fetch function supports special behaviours, like automatic retries. These are disabled by default through\n * this function.\n *\n * @param url - This defines the resource that you wish to fetch.\n * @param init - An object containing any custom settings that you want to apply to the request.\n * @param preferredBehaviour - A request behaviour object that overrides the default behaviour.\n * @returns A promise that resolves with the response.\n */\nexport async function fetch(\n url: RequestInfo,\n init?: RequestInit,\n preferredBehaviour?: RequestModeInput,\n): Promise<Response> {\n const options = {\n url,\n init,\n logRequest: false,\n useHttpsAgent: false,\n // all special behaviours are disabled by default\n behaviour: preferredBehaviour ? requestMode(preferredBehaviour) : requestMode('non-blocking'),\n } as const\n\n return innerFetch(options)\n}\n\n/**\n * A fetch function to use with Shopify services. The function ensures the right\n * TLS configuragion is used based on the environment in which the service is running\n * (e.g. Local). NB: headers/auth are the responsibility of the caller.\n *\n * By default, the CLI's fetch function's special behaviours, like automatic retries, are enabled.\n *\n * @param url - This defines the resource that you wish to fetch.\n * @param init - An object containing any custom settings that you want to apply to the request.\n * @param preferredBehaviour - A request behaviour object that overrides the default behaviour.\n * @returns A promise that resolves with the response.\n */\nexport async function shopifyFetch(\n url: RequestInfo,\n init?: RequestInit,\n preferredBehaviour?: RequestModeInput,\n): Promise<Response> {\n const options = {\n url,\n init,\n logRequest: true,\n useHttpsAgent: true,\n // special behaviours enabled by default\n behaviour: preferredBehaviour ? requestMode(preferredBehaviour) : requestMode(),\n }\n\n return innerFetch(options)\n}\n\n/**\n * Download a file from a URL to a local path.\n *\n * @param url - The URL to download from.\n * @param to - The local path to download to.\n * @returns - A promise that resolves with the local path.\n */\nexport function downloadFile(url: string, to: string): Promise<string> {\n const sanitizedUrl = sanitizeURL(url)\n outputDebug(`Downloading ${sanitizedUrl} to ${to}`)\n\n return runWithTimer('cmd_all_timing_network_ms')(async () => {\n if (!fileExistsSync(dirname(to))) {\n mkdirSync(dirname(to))\n }\n\n // if we can't remove the file for some reason (seen on windows), that's ok -- it's in a temporary directory\n const tryToRemoveFile = () => {\n try {\n if (fileExistsSync(to)) {\n unlinkFileSync(to)\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err: unknown) {\n outputDebug(outputContent`Failed to remove file ${outputToken.path(to)}: ${outputToken.raw(String(err))}`)\n }\n }\n\n try {\n const res = await nodeFetch(url, {redirect: 'follow'})\n if (!res.body) {\n throw new Error(`No response body received when downloading ${sanitizedUrl}`)\n }\n await pipeline(res.body, createFileWriteStream(to))\n return to\n } catch (err) {\n tryToRemoveFile()\n throw err instanceof Error ? err : new Error(String(err))\n }\n })\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { fileExistsSync, isDirectorySync } from './fs.js';
2
2
  import { dirname, joinPath } from './path.js';
3
+ import { uniq } from '../common/array.js';
3
4
  import { openSync, readSync, closeSync } from 'fs';
4
5
  // Only read the first 128KB of each file for import scanning. This covers
5
6
  // ~3,000+ lines which is more than enough to capture all static imports.
@@ -114,7 +115,7 @@ export function extractImportPathsRecursively(filePath, visited = new Set()) {
114
115
  throw error;
115
116
  }
116
117
  }
117
- return [...new Set(allImports)];
118
+ return uniq(allImports);
118
119
  }
119
120
  /**
120
121
  * Returns diagnostic information about the import scanning caches.
@@ -166,7 +167,7 @@ function extractJSLikeImports(content, filePath) {
166
167
  }
167
168
  }
168
169
  }
169
- return [...new Set(imports)];
170
+ return uniq(imports);
170
171
  }
171
172
  function extractRustImports(content, filePath) {
172
173
  const imports = [];
@@ -193,7 +194,7 @@ function extractRustImports(content, filePath) {
193
194
  }
194
195
  }
195
196
  }
196
- return [...new Set(imports)];
197
+ return uniq(imports);
197
198
  }
198
199
  function resolveJSImport(importPath, fromFile) {
199
200
  const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile);
@@ -1 +1 @@
1
- {"version":3,"file":"import-extractor.js","sourceRoot":"","sources":["../../../src/public/node/import-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExistsSync, isDirectorySync} from './fs.js'\nimport {dirname, joinPath} from './path.js'\nimport {openSync, readSync, closeSync} from 'fs'\n\n// Only read the first 128KB of each file for import scanning. This covers\n// ~3,000+ lines which is more than enough to capture all static imports.\n// Generated type files (e.g. graphql-codegen) can be tens of megabytes and\n// reading them fully takes several seconds on some machines.\nconst MAX_READ_SIZE = 128 * 1024\n\n// Caches direct import results per file path to avoid redundant file reads and parsing\n// when multiple extensions import the same shared code.\nconst directImportsCache = new Map<string, string[]>()\n\n// Caches filesystem stat results to avoid redundant synchronous I/O.\n// Each stat call also triggers outputDebug overhead, so caching here\n// avoids both the kernel round-trip and the debug string construction.\nconst fileExistsCache = new Map<string, boolean>()\nconst isDirCache = new Map<string, boolean>()\n\nfunction cachedFileExists(path: string): boolean {\n const cached = fileExistsCache.get(path)\n if (cached !== undefined) return cached\n const result = fileExistsSync(path)\n fileExistsCache.set(path, result)\n return result\n}\n\nfunction cachedIsDir(path: string): boolean {\n const cached = isDirCache.get(path)\n if (cached !== undefined) return cached\n const result = isDirectorySync(path)\n isDirCache.set(path, result)\n return result\n}\n\nfunction readFileContent(filePath: string): string {\n const fd = openSync(filePath, 'r')\n try {\n const buffer = Buffer.alloc(MAX_READ_SIZE)\n const bytesRead = readSync(fd, buffer, 0, MAX_READ_SIZE, 0)\n return buffer.subarray(0, bytesRead).toString()\n } finally {\n closeSync(fd)\n }\n}\n\n/**\n * Clears all import-scanning caches (direct imports, recursive results, and filesystem stats).\n * Should be called when watched files change so that rescanning picks up updated imports.\n */\nexport function clearImportPathsCache(): void {\n directImportsCache.clear()\n fileExistsCache.clear()\n isDirCache.clear()\n}\n\n/**\n * Extracts import paths from a source file.\n * Supports JavaScript, TypeScript, and Rust files.\n * Results are cached per file path to avoid redundant I/O.\n *\n * @param filePath - Path to the file to analyze.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractImportPaths(filePath: string): string[] {\n const cached = directImportsCache.get(filePath)\n if (cached) return cached\n\n const content = readFileContent(filePath)\n const ext = filePath.substring(filePath.lastIndexOf('.'))\n\n let result: string[]\n switch (ext) {\n case '.js':\n case '.mjs':\n case '.cjs':\n case '.ts':\n case '.tsx':\n case '.jsx':\n result = extractJSLikeImports(content, filePath)\n break\n case '.rs':\n result = extractRustImports(content, filePath)\n break\n default:\n result = []\n }\n\n directImportsCache.set(filePath, result)\n return result\n}\n\n/**\n * Recursively extracts import paths from a source file and all its dependencies.\n * Supports JavaScript, TypeScript, and Rust files.\n * Handles circular dependencies by tracking visited files.\n *\n * @param filePath - Path to the file to analyze.\n * @param visited - Set of already visited files to prevent infinite recursion.\n * @returns Array of absolute paths to the provided file and all imported files there (including nested imports).\n * @throws If an unexpected error occurs while processing files (not including ENOENT file not found errors).\n */\nexport function extractImportPathsRecursively(filePath: string, visited: Set<string> = new Set<string>()): string[] {\n if (visited.has(filePath)) {\n return []\n }\n\n visited.add(filePath)\n\n const directImports = extractImportPaths(filePath)\n const allImports = [filePath, ...directImports]\n\n for (const importedFile of directImports) {\n try {\n if (cachedFileExists(importedFile) && !cachedIsDir(importedFile)) {\n const nestedImports = extractImportPathsRecursively(importedFile, visited)\n allImports.push(...nestedImports)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n continue\n }\n throw error\n }\n }\n\n return [...new Set(allImports)]\n}\n\n/**\n * Returns diagnostic information about the import scanning caches.\n * Useful for debugging performance issues with --verbose.\n *\n * @returns Cache size stats for directImports, fileExists, and isDir.\n */\nexport function getImportScanningCacheStats(): {directImports: number; fileExists: number; isDir: number} {\n return {\n directImports: directImportsCache.size,\n fileExists: fileExistsCache.size,\n isDir: isDirCache.size,\n }\n}\n\n/**\n * Extracts import paths from a JavaScript content.\n *\n * @param content - The content to extract imports from.\n * @param filePath - The path to the file to extract imports from.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractJSImports(content: string, filePath: string): string[] {\n return extractJSLikeImports(content, filePath)\n}\n\nfunction extractJSLikeImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Regular expressions for different import types\n const patterns = [\n // ES6 imports: import ... from './path'\n /import\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // ES6 side-effect imports: import './path'\n /import\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/g,\n // ES6 exports: export ... from './path'\n /export\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // Dynamic imports: import('./path')\n /import\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n // CommonJS requires: require('./path')\n /require\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n ]\n\n for (const pattern of patterns) {\n let match\n while ((match = pattern.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && importPath.startsWith('.')) {\n const resolvedPath = resolveJSImport(importPath, filePath)\n if (resolvedPath) {\n imports.push(resolvedPath)\n }\n }\n }\n }\n\n return [...new Set(imports)]\n}\n\nfunction extractRustImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Basic Rust mod declarations: mod module_name;\n const modPattern = /^\\s*(?:pub\\s+)?mod\\s+([a-z_][a-z0-9_]*)\\s*;/gm\n\n let match\n while ((match = modPattern.exec(content)) !== null) {\n const modName = match[1]\n if (modName) {\n const modPath = resolveRustModule(modName, filePath)\n if (modPath) {\n imports.push(modPath)\n }\n }\n }\n\n // Handle #[path = \"...\"] attributes\n const pathPattern = /#\\[path\\s*=\\s*\"([^\"]+)\"\\]/g\n while ((match = pathPattern.exec(content)) !== null) {\n const pathValue = match[1]\n if (pathValue) {\n const resolvedPath = joinPath(dirname(filePath), pathValue)\n if (cachedFileExists(resolvedPath)) {\n imports.push(resolvedPath)\n }\n }\n }\n\n return [...new Set(imports)]\n}\n\nfunction resolveJSImport(importPath: string, fromFile: string): string | null {\n const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile)\n const resolvedPath = joinPath(basePath, importPath)\n\n if (cachedFileExists(resolvedPath) && cachedIsDir(resolvedPath)) {\n const indexPaths = [\n joinPath(resolvedPath, 'index.js'),\n joinPath(resolvedPath, 'index.ts'),\n joinPath(resolvedPath, 'index.tsx'),\n joinPath(resolvedPath, 'index.jsx'),\n ]\n\n for (const indexPath of indexPaths) {\n if (cachedFileExists(indexPath) && !cachedIsDir(indexPath)) {\n return indexPath\n }\n }\n return null\n }\n\n const possiblePaths = [\n resolvedPath,\n `${resolvedPath}.js`,\n `${resolvedPath}.ts`,\n `${resolvedPath}.tsx`,\n `${resolvedPath}.jsx`,\n ]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path) && !cachedIsDir(path)) {\n return path\n }\n }\n\n return null\n}\n\nfunction resolveRustModule(modName: string, fromFile: string): string | null {\n const basePath = dirname(fromFile)\n const possiblePaths = [joinPath(basePath, `${modName}.rs`), joinPath(basePath, modName, 'mod.rs')]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path)) {\n return path\n }\n }\n\n return null\n}\n"]}
1
+ {"version":3,"file":"import-extractor.js","sourceRoot":"","sources":["../../../src/public/node/import-extractor.ts"],"names":[],"mappings":"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","sourcesContent":["import {fileExistsSync, isDirectorySync} from './fs.js'\nimport {dirname, joinPath} from './path.js'\nimport {uniq} from '../common/array.js'\nimport {openSync, readSync, closeSync} from 'fs'\n\n// Only read the first 128KB of each file for import scanning. This covers\n// ~3,000+ lines which is more than enough to capture all static imports.\n// Generated type files (e.g. graphql-codegen) can be tens of megabytes and\n// reading them fully takes several seconds on some machines.\nconst MAX_READ_SIZE = 128 * 1024\n\n// Caches direct import results per file path to avoid redundant file reads and parsing\n// when multiple extensions import the same shared code.\nconst directImportsCache = new Map<string, string[]>()\n\n// Caches filesystem stat results to avoid redundant synchronous I/O.\n// Each stat call also triggers outputDebug overhead, so caching here\n// avoids both the kernel round-trip and the debug string construction.\nconst fileExistsCache = new Map<string, boolean>()\nconst isDirCache = new Map<string, boolean>()\n\nfunction cachedFileExists(path: string): boolean {\n const cached = fileExistsCache.get(path)\n if (cached !== undefined) return cached\n const result = fileExistsSync(path)\n fileExistsCache.set(path, result)\n return result\n}\n\nfunction cachedIsDir(path: string): boolean {\n const cached = isDirCache.get(path)\n if (cached !== undefined) return cached\n const result = isDirectorySync(path)\n isDirCache.set(path, result)\n return result\n}\n\nfunction readFileContent(filePath: string): string {\n const fd = openSync(filePath, 'r')\n try {\n const buffer = Buffer.alloc(MAX_READ_SIZE)\n const bytesRead = readSync(fd, buffer, 0, MAX_READ_SIZE, 0)\n return buffer.subarray(0, bytesRead).toString()\n } finally {\n closeSync(fd)\n }\n}\n\n/**\n * Clears all import-scanning caches (direct imports, recursive results, and filesystem stats).\n * Should be called when watched files change so that rescanning picks up updated imports.\n */\nexport function clearImportPathsCache(): void {\n directImportsCache.clear()\n fileExistsCache.clear()\n isDirCache.clear()\n}\n\n/**\n * Extracts import paths from a source file.\n * Supports JavaScript, TypeScript, and Rust files.\n * Results are cached per file path to avoid redundant I/O.\n *\n * @param filePath - Path to the file to analyze.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractImportPaths(filePath: string): string[] {\n const cached = directImportsCache.get(filePath)\n if (cached) return cached\n\n const content = readFileContent(filePath)\n const ext = filePath.substring(filePath.lastIndexOf('.'))\n\n let result: string[]\n switch (ext) {\n case '.js':\n case '.mjs':\n case '.cjs':\n case '.ts':\n case '.tsx':\n case '.jsx':\n result = extractJSLikeImports(content, filePath)\n break\n case '.rs':\n result = extractRustImports(content, filePath)\n break\n default:\n result = []\n }\n\n directImportsCache.set(filePath, result)\n return result\n}\n\n/**\n * Recursively extracts import paths from a source file and all its dependencies.\n * Supports JavaScript, TypeScript, and Rust files.\n * Handles circular dependencies by tracking visited files.\n *\n * @param filePath - Path to the file to analyze.\n * @param visited - Set of already visited files to prevent infinite recursion.\n * @returns Array of absolute paths to the provided file and all imported files there (including nested imports).\n * @throws If an unexpected error occurs while processing files (not including ENOENT file not found errors).\n */\nexport function extractImportPathsRecursively(filePath: string, visited: Set<string> = new Set<string>()): string[] {\n if (visited.has(filePath)) {\n return []\n }\n\n visited.add(filePath)\n\n const directImports = extractImportPaths(filePath)\n const allImports = [filePath, ...directImports]\n\n for (const importedFile of directImports) {\n try {\n if (cachedFileExists(importedFile) && !cachedIsDir(importedFile)) {\n const nestedImports = extractImportPathsRecursively(importedFile, visited)\n allImports.push(...nestedImports)\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('ENOENT')) {\n continue\n }\n throw error\n }\n }\n\n return uniq(allImports)\n}\n\n/**\n * Returns diagnostic information about the import scanning caches.\n * Useful for debugging performance issues with --verbose.\n *\n * @returns Cache size stats for directImports, fileExists, and isDir.\n */\nexport function getImportScanningCacheStats(): {directImports: number; fileExists: number; isDir: number} {\n return {\n directImports: directImportsCache.size,\n fileExists: fileExistsCache.size,\n isDir: isDirCache.size,\n }\n}\n\n/**\n * Extracts import paths from a JavaScript content.\n *\n * @param content - The content to extract imports from.\n * @param filePath - The path to the file to extract imports from.\n * @returns Array of absolute paths to imported files.\n */\nexport function extractJSImports(content: string, filePath: string): string[] {\n return extractJSLikeImports(content, filePath)\n}\n\nfunction extractJSLikeImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Regular expressions for different import types\n const patterns = [\n // ES6 imports: import ... from './path'\n /import\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // ES6 side-effect imports: import './path'\n /import\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/g,\n // ES6 exports: export ... from './path'\n /export\\s+(?:[\\s\\S]*?)\\s+from\\s+['\"](\\.\\.?\\/[^'\"]+)['\"]/gm,\n // Dynamic imports: import('./path')\n /import\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n // CommonJS requires: require('./path')\n /require\\s*\\(\\s*['\"](\\.\\.?\\/[^'\"]+)['\"]\\s*\\)/g,\n ]\n\n for (const pattern of patterns) {\n let match\n while ((match = pattern.exec(content)) !== null) {\n const importPath = match[1]\n if (importPath && importPath.startsWith('.')) {\n const resolvedPath = resolveJSImport(importPath, filePath)\n if (resolvedPath) {\n imports.push(resolvedPath)\n }\n }\n }\n }\n\n return uniq(imports)\n}\n\nfunction extractRustImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n\n // Basic Rust mod declarations: mod module_name;\n const modPattern = /^\\s*(?:pub\\s+)?mod\\s+([a-z_][a-z0-9_]*)\\s*;/gm\n\n let match\n while ((match = modPattern.exec(content)) !== null) {\n const modName = match[1]\n if (modName) {\n const modPath = resolveRustModule(modName, filePath)\n if (modPath) {\n imports.push(modPath)\n }\n }\n }\n\n // Handle #[path = \"...\"] attributes\n const pathPattern = /#\\[path\\s*=\\s*\"([^\"]+)\"\\]/g\n while ((match = pathPattern.exec(content)) !== null) {\n const pathValue = match[1]\n if (pathValue) {\n const resolvedPath = joinPath(dirname(filePath), pathValue)\n if (cachedFileExists(resolvedPath)) {\n imports.push(resolvedPath)\n }\n }\n }\n\n return uniq(imports)\n}\n\nfunction resolveJSImport(importPath: string, fromFile: string): string | null {\n const basePath = cachedFileExists(fromFile) && cachedIsDir(fromFile) ? fromFile : dirname(fromFile)\n const resolvedPath = joinPath(basePath, importPath)\n\n if (cachedFileExists(resolvedPath) && cachedIsDir(resolvedPath)) {\n const indexPaths = [\n joinPath(resolvedPath, 'index.js'),\n joinPath(resolvedPath, 'index.ts'),\n joinPath(resolvedPath, 'index.tsx'),\n joinPath(resolvedPath, 'index.jsx'),\n ]\n\n for (const indexPath of indexPaths) {\n if (cachedFileExists(indexPath) && !cachedIsDir(indexPath)) {\n return indexPath\n }\n }\n return null\n }\n\n const possiblePaths = [\n resolvedPath,\n `${resolvedPath}.js`,\n `${resolvedPath}.ts`,\n `${resolvedPath}.tsx`,\n `${resolvedPath}.jsx`,\n ]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path) && !cachedIsDir(path)) {\n return path\n }\n }\n\n return null\n}\n\nfunction resolveRustModule(modName: string, fromFile: string): string | null {\n const basePath = dirname(fromFile)\n const possiblePaths = [joinPath(basePath, `${modName}.rs`), joinPath(basePath, modName, 'mod.rs')]\n\n for (const path of possiblePaths) {\n if (cachedFileExists(path)) {\n return path\n }\n }\n\n return null\n}\n"]}
@@ -38,6 +38,7 @@ type CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> & Pic
38
38
  declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
39
39
  commandStartOptions: {
40
40
  startTime: number;
41
+ endTime?: number;
41
42
  startCommand: string;
42
43
  startTopic?: string;
43
44
  startArgs: string[];
@@ -58,6 +59,7 @@ declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
58
59
  export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>, getAllSensitiveMetadata: () => Partial<{
59
60
  commandStartOptions: {
60
61
  startTime: number;
62
+ endTime?: number;
61
63
  startCommand: string;
62
64
  startTopic?: string;
63
65
  startArgs: string[];
@@ -77,6 +79,7 @@ export declare const getAllPublicMetadata: () => Partial<CmdFieldsFromMonorail>,
77
79
  }, "store_", never>>, addPublicMetadata: (getData: ProvideMetadata<CmdFieldsFromMonorail>, onError?: MetadataErrorHandling) => Promise<void>, addSensitiveMetadata: (getData: ProvideMetadata<{
78
80
  commandStartOptions: {
79
81
  startTime: number;
82
+ endTime?: number;
80
83
  startCommand: string;
81
84
  startTopic?: string;
82
85
  startArgs: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/public/node/metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import {isUnitTest} from './context/local.js'\nimport {performance} from 'node:perf_hooks'\nimport type {PickByPrefix} from '../common/ts/pick-by-prefix.js'\nimport type {AnyJson} from '../../private/common/json.js'\nimport type {MonorailEventPublic, MonorailEventSensitive} from './monorail.js'\n\ntype ProvideMetadata<T> = () => Partial<T> | Promise<Partial<T>>\n\ntype MetadataErrorHandling =\n // Mute & report errors in production, throw them whilst testing\n | 'auto'\n // Errors are not reported to the user and do not stop execution, but they are reported to Bugsnag\n | 'mute-and-report'\n // Errors are not caught and will bubble out as normal\n | 'bubble'\n\n/**\n * Get the error handling strategy for metadata.\n *\n * @returns 'mute-and-report' in production, 'bubble' in tests.\n */\nfunction getMetadataErrorHandlingStrategy(): 'mute-and-report' | 'bubble' {\n if (isUnitTest()) {\n return 'bubble'\n }\n return 'mute-and-report'\n}\n\n/**\n * Any key in T that has a numeric value.\n */\ntype NumericKeyOf<T> = {\n [K in keyof T]: T[K] extends number ? (K extends string ? K : never) : never\n}[keyof T]\n\nexport interface RuntimeMetadataManager<TPublic extends AnyJson, TSensitive extends AnyJson> {\n /** Add some public metadata -- this should not contain any PII. */\n addPublicMetadata: (getData: ProvideMetadata<TPublic>, onError?: MetadataErrorHandling) => Promise<void>\n /**\n * Add some potentially sensitive metadata -- this may include PII, but unnecessary data should never be tracked\n * (this is a good fit for command args for instance).\n */\n addSensitiveMetadata: (getData: ProvideMetadata<TSensitive>, onError?: MetadataErrorHandling) => Promise<void>\n /** Get a snapshot of the tracked public data. */\n getAllPublicMetadata: () => Partial<TPublic>\n /** Get a snapshot of the tracked sensitive data. */\n getAllSensitiveMetadata: () => Partial<TSensitive>\n /** Run a function, monitoring how long it takes, and adding the elapsed time to a running total. */\n runWithTimer: (field: NumericKeyOf<TPublic>) => <T>(fn: () => Promise<T>) => Promise<T>\n}\n\nexport type PublicSchema<T> = T extends RuntimeMetadataManager<infer TPublic, infer _TSensitive> ? TPublic : never\nexport type SensitiveSchema<T> = T extends RuntimeMetadataManager<infer _TPublic, infer TSensitive> ? TSensitive : never\n\n/**\n * Creates a container for metadata collected at runtime.\n * The container provides async-safe functions for extracting the gathered metadata, and for setting it.\n *\n * @param defaultPublicMetadata - Optional, default data for the container.\n * @returns A container for the metadata.\n */\nexport function createRuntimeMetadataContainer<\n TPublic extends AnyJson,\n TSensitive extends AnyJson = Record<string, never>,\n>(defaultPublicMetadata: Partial<TPublic> = {}): RuntimeMetadataManager<TPublic, TSensitive> {\n const raw: {sensitive: Partial<TSensitive>; public: Partial<TPublic>} = {\n sensitive: {},\n public: {\n ...defaultPublicMetadata,\n },\n }\n const addPublic = (data: Partial<TPublic>) => {\n Object.assign(raw.public, data)\n }\n const addSensitive = (data: Partial<TSensitive>) => {\n Object.assign(raw.sensitive, data)\n }\n\n const addMetadata = async <T>(\n addFn: (data: Partial<T>) => void,\n getFn: ProvideMetadata<T>,\n onError: MetadataErrorHandling,\n ) => {\n const errorHandling = onError === 'auto' ? getMetadataErrorHandlingStrategy() : onError\n const getAndSet = async () => {\n const data = await getFn()\n addFn(data)\n }\n\n if (errorHandling === 'bubble') {\n await getAndSet()\n } else {\n try {\n await getAndSet()\n // eslint-disable-next-line no-catch-all/no-catch-all, @typescript-eslint/no-explicit-any\n } catch (error: any) {\n // This is very prone to becoming a circular dependency, so we import it dynamically\n const {sendErrorToBugsnag} = await import('./error-handler.js')\n await sendErrorToBugsnag(error, 'unexpected_error')\n }\n }\n }\n\n // See `runWithTimer` below.\n const durationStack: number[] = []\n\n return {\n getAllPublicMetadata: () => {\n return {...raw.public}\n },\n getAllSensitiveMetadata: () => {\n return {...raw.sensitive}\n },\n addPublicMetadata: async (getData: ProvideMetadata<TPublic>, onError: MetadataErrorHandling = 'auto') => {\n return addMetadata(addPublic, getData, onError)\n },\n addSensitiveMetadata: async (getData: ProvideMetadata<TSensitive>, onError: MetadataErrorHandling = 'auto') => {\n return addMetadata(addSensitive, getData, onError)\n },\n runWithTimer: (field: NumericKeyOf<TPublic>): (<T>(fn: () => Promise<T>) => Promise<T>) => {\n return async (fn) => {\n /**\n * For nested timers, we subtract the inner timer's duration from the outer timer's. We use a stack to track the\n * cumulative durations of nested timers. On starting a timer, we push a zero onto the stack to initialize the total\n * duration for subsequent nested timers. Before logging, we pop the stack to get the total nested timers' duration.\n * We subtract this from the current timer's actual duration to get its measurable duration. We then add the current\n * timer's actual duration to the stack's top, allowing any parent timer to deduct it from its own duration.\n */\n\n // Initialise the running total duration for all nested timers\n durationStack.push(0)\n\n // Do the work, and time it\n const start = performance.now()\n try {\n const result = await fn()\n return result\n } finally {\n let end = performance.now()\n // For very short durations, the end time can be before the start time(!) - we flatten this out to zero.\n end = Math.max(start, end)\n\n // The top of the stack is the total time for all nested timers\n const wallClockDuration = Math.max(end - start, 0)\n\n const childDurations = durationStack.pop()!\n const duration = Math.max(wallClockDuration - childDurations, 0)\n\n // If this is the topmost timer, the stack will be empty.\n if (durationStack.length > 0) {\n durationStack[durationStack.length - 1] = (durationStack[durationStack.length - 1] ?? 0) + wallClockDuration\n }\n\n // Log it -- we include it in the metadata, but also log via the standard performance API. The TS types for this library are not quite right, so we have to cast to `any` here.\n performance.measure(`${field}#measurable`, {\n start,\n duration,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any)\n performance.measure(`${field}#wall`, {\n start,\n end,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any)\n\n // There might not be a value set, yet\n let currentValue = (raw.public[field] || 0) as number\n currentValue += duration\n\n // TS is not quite smart enough to realise that raw.public[field] must be a numeric type\n raw.public[field] = currentValue as TPublic[NumericKeyOf<TPublic>]\n }\n }\n },\n }\n}\n\n// We want to track anything that ends up getting sent to monorail as `cmd_all_*`,\n// `cmd_app_*`, `cmd_theme_*`, `store_*`, and `env_auto_upgrade_*`\ntype CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_app_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_theme_'> &\n PickByPrefix<MonorailEventPublic, 'store_'> &\n PickByPrefix<MonorailEventPublic, 'env_auto_upgrade_'>\n\nconst coreData = createRuntimeMetadataContainer<\n CmdFieldsFromMonorail,\n {\n commandStartOptions: {\n startTime: number\n startCommand: string\n startTopic?: string\n startArgs: string[]\n }\n } & {environmentFlags: string} & PickByPrefix<MonorailEventSensitive, 'store_'>\n>({cmd_all_timing_network_ms: 0, cmd_all_timing_prompts_ms: 0})\n\nexport const {getAllPublicMetadata, getAllSensitiveMetadata, addPublicMetadata, addSensitiveMetadata, runWithTimer} =\n coreData\n\nexport type Public = PublicSchema<typeof coreData>\nexport type Sensitive = SensitiveSchema<typeof coreData>\n"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/public/node/metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import {isUnitTest} from './context/local.js'\nimport {performance} from 'node:perf_hooks'\nimport type {PickByPrefix} from '../common/ts/pick-by-prefix.js'\nimport type {AnyJson} from '../../private/common/json.js'\nimport type {MonorailEventPublic, MonorailEventSensitive} from './monorail.js'\n\ntype ProvideMetadata<T> = () => Partial<T> | Promise<Partial<T>>\n\ntype MetadataErrorHandling =\n // Mute & report errors in production, throw them whilst testing\n | 'auto'\n // Errors are not reported to the user and do not stop execution, but they are reported to Bugsnag\n | 'mute-and-report'\n // Errors are not caught and will bubble out as normal\n | 'bubble'\n\n/**\n * Get the error handling strategy for metadata.\n *\n * @returns 'mute-and-report' in production, 'bubble' in tests.\n */\nfunction getMetadataErrorHandlingStrategy(): 'mute-and-report' | 'bubble' {\n if (isUnitTest()) {\n return 'bubble'\n }\n return 'mute-and-report'\n}\n\n/**\n * Any key in T that has a numeric value.\n */\ntype NumericKeyOf<T> = {\n [K in keyof T]: T[K] extends number ? (K extends string ? K : never) : never\n}[keyof T]\n\nexport interface RuntimeMetadataManager<TPublic extends AnyJson, TSensitive extends AnyJson> {\n /** Add some public metadata -- this should not contain any PII. */\n addPublicMetadata: (getData: ProvideMetadata<TPublic>, onError?: MetadataErrorHandling) => Promise<void>\n /**\n * Add some potentially sensitive metadata -- this may include PII, but unnecessary data should never be tracked\n * (this is a good fit for command args for instance).\n */\n addSensitiveMetadata: (getData: ProvideMetadata<TSensitive>, onError?: MetadataErrorHandling) => Promise<void>\n /** Get a snapshot of the tracked public data. */\n getAllPublicMetadata: () => Partial<TPublic>\n /** Get a snapshot of the tracked sensitive data. */\n getAllSensitiveMetadata: () => Partial<TSensitive>\n /** Run a function, monitoring how long it takes, and adding the elapsed time to a running total. */\n runWithTimer: (field: NumericKeyOf<TPublic>) => <T>(fn: () => Promise<T>) => Promise<T>\n}\n\nexport type PublicSchema<T> = T extends RuntimeMetadataManager<infer TPublic, infer _TSensitive> ? TPublic : never\nexport type SensitiveSchema<T> = T extends RuntimeMetadataManager<infer _TPublic, infer TSensitive> ? TSensitive : never\n\n/**\n * Creates a container for metadata collected at runtime.\n * The container provides async-safe functions for extracting the gathered metadata, and for setting it.\n *\n * @param defaultPublicMetadata - Optional, default data for the container.\n * @returns A container for the metadata.\n */\nexport function createRuntimeMetadataContainer<\n TPublic extends AnyJson,\n TSensitive extends AnyJson = Record<string, never>,\n>(defaultPublicMetadata: Partial<TPublic> = {}): RuntimeMetadataManager<TPublic, TSensitive> {\n const raw: {sensitive: Partial<TSensitive>; public: Partial<TPublic>} = {\n sensitive: {},\n public: {\n ...defaultPublicMetadata,\n },\n }\n const addPublic = (data: Partial<TPublic>) => {\n Object.assign(raw.public, data)\n }\n const addSensitive = (data: Partial<TSensitive>) => {\n Object.assign(raw.sensitive, data)\n }\n\n const addMetadata = async <T>(\n addFn: (data: Partial<T>) => void,\n getFn: ProvideMetadata<T>,\n onError: MetadataErrorHandling,\n ) => {\n const errorHandling = onError === 'auto' ? getMetadataErrorHandlingStrategy() : onError\n const getAndSet = async () => {\n const data = await getFn()\n addFn(data)\n }\n\n if (errorHandling === 'bubble') {\n await getAndSet()\n } else {\n try {\n await getAndSet()\n // eslint-disable-next-line no-catch-all/no-catch-all, @typescript-eslint/no-explicit-any\n } catch (error: any) {\n // This is very prone to becoming a circular dependency, so we import it dynamically\n const {sendErrorToBugsnag} = await import('./error-handler.js')\n await sendErrorToBugsnag(error, 'unexpected_error')\n }\n }\n }\n\n // See `runWithTimer` below.\n const durationStack: number[] = []\n\n return {\n getAllPublicMetadata: () => {\n return {...raw.public}\n },\n getAllSensitiveMetadata: () => {\n return {...raw.sensitive}\n },\n addPublicMetadata: async (getData: ProvideMetadata<TPublic>, onError: MetadataErrorHandling = 'auto') => {\n return addMetadata(addPublic, getData, onError)\n },\n addSensitiveMetadata: async (getData: ProvideMetadata<TSensitive>, onError: MetadataErrorHandling = 'auto') => {\n return addMetadata(addSensitive, getData, onError)\n },\n runWithTimer: (field: NumericKeyOf<TPublic>): (<T>(fn: () => Promise<T>) => Promise<T>) => {\n return async (fn) => {\n /**\n * For nested timers, we subtract the inner timer's duration from the outer timer's. We use a stack to track the\n * cumulative durations of nested timers. On starting a timer, we push a zero onto the stack to initialize the total\n * duration for subsequent nested timers. Before logging, we pop the stack to get the total nested timers' duration.\n * We subtract this from the current timer's actual duration to get its measurable duration. We then add the current\n * timer's actual duration to the stack's top, allowing any parent timer to deduct it from its own duration.\n */\n\n // Initialise the running total duration for all nested timers\n durationStack.push(0)\n\n // Do the work, and time it\n const start = performance.now()\n try {\n const result = await fn()\n return result\n } finally {\n let end = performance.now()\n // For very short durations, the end time can be before the start time(!) - we flatten this out to zero.\n end = Math.max(start, end)\n\n // The top of the stack is the total time for all nested timers\n const wallClockDuration = Math.max(end - start, 0)\n\n const childDurations = durationStack.pop()!\n const duration = Math.max(wallClockDuration - childDurations, 0)\n\n // If this is the topmost timer, the stack will be empty.\n if (durationStack.length > 0) {\n durationStack[durationStack.length - 1] = (durationStack[durationStack.length - 1] ?? 0) + wallClockDuration\n }\n\n // Log it -- we include it in the metadata, but also log via the standard performance API. The TS types for this library are not quite right, so we have to cast to `any` here.\n performance.measure(`${field}#measurable`, {\n start,\n duration,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any)\n performance.measure(`${field}#wall`, {\n start,\n end,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any)\n\n // There might not be a value set, yet\n let currentValue = (raw.public[field] || 0) as number\n currentValue += duration\n\n // TS is not quite smart enough to realise that raw.public[field] must be a numeric type\n raw.public[field] = currentValue as TPublic[NumericKeyOf<TPublic>]\n }\n }\n },\n }\n}\n\n// We want to track anything that ends up getting sent to monorail as `cmd_all_*`,\n// `cmd_app_*`, `cmd_theme_*`, `store_*`, and `env_auto_upgrade_*`\ntype CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_app_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_theme_'> &\n PickByPrefix<MonorailEventPublic, 'store_'> &\n PickByPrefix<MonorailEventPublic, 'env_auto_upgrade_'>\n\nconst coreData = createRuntimeMetadataContainer<\n CmdFieldsFromMonorail,\n {\n commandStartOptions: {\n startTime: number\n endTime?: number\n startCommand: string\n startTopic?: string\n startArgs: string[]\n }\n } & {environmentFlags: string} & PickByPrefix<MonorailEventSensitive, 'store_'>\n>({cmd_all_timing_network_ms: 0, cmd_all_timing_prompts_ms: 0})\n\nexport const {getAllPublicMetadata, getAllSensitiveMetadata, addPublicMetadata, addSensitiveMetadata, runWithTimer} =\n coreData\n\nexport type Public = PublicSchema<typeof coreData>\nexport type Sensitive = SensitiveSchema<typeof coreData>\n"]}
@@ -2,7 +2,7 @@ import { JsonMap } from '../../private/common/json.js';
2
2
  import { DeepRequired } from '../common/ts/deep-required.js';
3
3
  export { DeepRequired };
4
4
  type Optional<T> = T | null;
5
- export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.24";
5
+ export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.26";
6
6
  export interface Schemas {
7
7
  [MONORAIL_COMMAND_TOPIC]: {
8
8
  sensitive: {
@@ -33,6 +33,7 @@ export interface Schemas {
33
33
  is_employee: boolean;
34
34
  store_fqdn_hash?: Optional<string>;
35
35
  store_fqdn_validated?: Optional<boolean>;
36
+ store_domain?: Optional<string>;
36
37
  user_id: string;
37
38
  cmd_all_alias_used?: Optional<string>;
38
39
  cmd_all_launcher?: Optional<string>;
@@ -2,7 +2,7 @@ import { fetch } from './http.js';
2
2
  import { outputDebug, outputContent, outputToken } from './output.js';
3
3
  const url = 'https://monorail-edge.shopifysvc.com/v1/produce';
4
4
  // This is the topic name of the main event we log to Monorail, the command tracker
5
- export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.24';
5
+ export const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.26';
6
6
  const publishedCommandNames = new Set();
7
7
  /**
8
8
  * Publishes an event to Monorail.
@@ -1 +1 @@
1
- {"version":3,"file":"monorail.js","sourceRoot":"","sources":["../../../src/public/node/monorail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,WAAW,CAAA;AAC/B,OAAO,EAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAMnE,MAAM,GAAG,GAAG,iDAAiD,CAAA;AAI7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAA;AAmL7D,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAA;AAE/C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAmB,EACnB,UAA8B,EAC9B,aAAoC;IAEpC,qHAAqH;IACrH,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAA;IACtC,IAAI,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QACnD,IAAI,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAC,IAAI,EAAE,IAAI,EAAC,CAAA;QACrB,CAAC;QACD,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;QACxC,MAAM,OAAO,GAAG,EAAC,GAAG,UAAU,EAAE,GAAG,aAAa,EAAC,CAAA;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;QAEzC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAC,EAAE,cAAc,CAAC,CAAA;QAElF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,WAAW,CAAC,aAAa,CAAA,yBAAyB,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;YAC/F,OAAO,EAAC,IAAI,EAAE,IAAI,EAAC,CAAA;QACrB,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,qCAAqC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;YACvE,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAC,CAAA;QACtD,CAAC;QACD,qDAAqD;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,GAAG,kCAAkC,CAAA;QAChD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAChD,CAAC;QACD,WAAW,CAAC,OAAO,CAAC,CAAA;QACpB,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAmB,OAAU;IACnD,MAAM,MAAM,GAAG,EAAC,GAAG,OAAO,EAAC,CAAA;IAC3B,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,CAAC,OAAO,GAAG,MAAM,CAAA;IACzB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,EAAE;IAC3C,OAAO;QACL,cAAc,EAAE,iCAAiC;QACjD,qCAAqC,EAAE,WAAW,CAAC,QAAQ,EAAE;QAC7D,kCAAkC,EAAE,WAAW,CAAC,QAAQ,EAAE;KAC3D,CAAA;AACH,CAAC,CAAA","sourcesContent":["import {fetch} from './http.js'\nimport {outputDebug, outputContent, outputToken} from './output.js'\nimport {JsonMap} from '../../private/common/json.js'\nimport {DeepRequired} from '../common/ts/deep-required.js'\n\nexport {DeepRequired}\n\nconst url = 'https://monorail-edge.shopifysvc.com/v1/produce'\n\ntype Optional<T> = T | null\n\n// This is the topic name of the main event we log to Monorail, the command tracker\nexport const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.24'\n\nexport interface Schemas {\n [MONORAIL_COMMAND_TOPIC]: {\n sensitive: {\n args: string\n error_message?: Optional<string>\n app_name?: Optional<string>\n metadata?: Optional<string>\n store_fqdn?: Optional<string>\n cmd_all_environment_flags?: Optional<string>\n\n // Dev related commands\n cmd_dev_tunnel_custom?: Optional<string>\n\n // Environment\n env_plugin_installed_all?: Optional<string>\n env_shopify_variables?: Optional<string>\n }\n public: {\n business_platform_id?: Optional<number>\n partner_id?: Optional<number>\n command: string\n project_type?: Optional<string>\n time_start: number\n time_end: number\n total_time: number\n success: boolean\n api_key?: Optional<string>\n cli_version: string\n uname: string\n ruby_version: string\n node_version: string\n is_employee: boolean\n store_fqdn_hash?: Optional<string>\n store_fqdn_validated?: Optional<boolean>\n user_id: string\n\n // Any and all commands\n cmd_all_alias_used?: Optional<string>\n cmd_all_launcher?: Optional<string>\n cmd_all_path_override?: Optional<boolean>\n cmd_all_path_override_hash?: Optional<string>\n cmd_all_plugin?: Optional<string>\n cmd_all_topic?: Optional<string>\n cmd_all_verbose?: Optional<boolean>\n cmd_all_exit?: Optional<string>\n cmd_all_force?: Optional<boolean>\n cmd_all_last_graphql_request_id?: Optional<string>\n\n cmd_all_timing_network_ms?: Optional<number>\n cmd_all_timing_prompts_ms?: Optional<number>\n cmd_all_timing_active_ms?: Optional<number>\n\n // Auto-upgrade\n env_auto_upgrade_enabled?: Optional<boolean>\n env_auto_upgrade_accepted?: Optional<boolean>\n env_auto_upgrade_skipped_reason?: Optional<string>\n env_auto_upgrade_success?: Optional<boolean>\n\n // Any extension related command\n cmd_extensions_binary_from_source?: Optional<boolean>\n\n // Scaffolding related commands\n cmd_scaffold_required_auth?: Optional<boolean>\n cmd_scaffold_template_custom?: Optional<boolean>\n cmd_scaffold_template_flavor?: Optional<string>\n cmd_scaffold_type?: Optional<string>\n cmd_scaffold_type_category?: Optional<string>\n cmd_scaffold_type_gated?: Optional<boolean>\n cmd_scaffold_type_owner?: Optional<string>\n cmd_scaffold_used_prompts_for_type?: Optional<boolean>\n\n // Used in several but not all commands\n cmd_app_dependency_installation_skipped?: Optional<boolean>\n cmd_app_reset_used?: Optional<boolean>\n cmd_app_linked_config_used?: Optional<boolean>\n cmd_app_linked_config_name?: Optional<string>\n cmd_app_linked_config_git_tracked?: Optional<boolean>\n cmd_app_all_configs_any?: Optional<boolean>\n cmd_app_all_configs_clients?: Optional<string>\n cmd_app_linked_config_source?: Optional<string>\n cmd_app_linked_config_uses_cli_managed_urls?: Optional<boolean>\n cmd_app_warning_api_key_deprecation_displayed?: Optional<boolean>\n cmd_app_deployment_mode?: Optional<string>\n cmd_app_validate_json?: Optional<boolean>\n cmd_app_validate_valid?: Optional<boolean>\n cmd_app_validate_issue_count?: Optional<number>\n cmd_app_validate_file_count?: Optional<number>\n\n // Dev related commands\n cmd_dev_tunnel_type?: Optional<string>\n cmd_dev_tunnel_custom_hash?: Optional<string>\n cmd_dev_urls_updated?: Optional<boolean>\n cmd_dev_preview_url_opened?: Optional<boolean>\n cmd_dev_graphiql_opened?: Optional<boolean>\n cmd_dev_dev_preview_toggle_used?: Optional<boolean>\n\n // Create-app related commands\n cmd_create_app_template?: Optional<string>\n cmd_create_app_template_url?: Optional<string>\n\n // Deploy related commands\n cmd_deploy_flag_message_used?: Optional<boolean>\n cmd_deploy_flag_version_used?: Optional<boolean>\n cmd_deploy_flag_source_url_used?: Optional<boolean>\n cmd_deploy_confirm_new_registrations?: Optional<number>\n cmd_deploy_confirm_updated_registrations?: Optional<number>\n cmd_deploy_confirm_removed_registrations?: Optional<number>\n cmd_deploy_confirm_cancelled?: Optional<boolean>\n cmd_deploy_confirm_time_to_complete_ms?: Optional<number>\n cmd_deploy_prompt_upgrade_to_unified_displayed?: Optional<boolean>\n cmd_deploy_prompt_upgrade_to_unified_response?: Optional<string>\n cmd_deploy_confirm_include_config_used?: Optional<boolean>\n cmd_deploy_include_config_used?: Optional<boolean>\n cmd_deploy_config_modules_breakdown?: Optional<string>\n cmd_deploy_config_modules_updated?: Optional<string>\n cmd_deploy_config_modules_added?: Optional<string>\n cmd_deploy_config_modules_deleted?: Optional<string>\n\n // Release related commands\n cmd_release_confirm_cancelled?: Optional<boolean>\n\n // App setup\n app_extensions_any?: Optional<boolean>\n app_extensions_breakdown?: Optional<string>\n app_extensions_count?: Optional<number>\n app_extensions_custom_layout?: Optional<boolean>\n app_extensions_function_any?: Optional<boolean>\n app_extensions_function_count?: Optional<number>\n app_extensions_function_custom_layout?: Optional<boolean>\n app_extensions_theme_any?: Optional<boolean>\n app_extensions_theme_count?: Optional<number>\n app_extensions_theme_custom_layout?: Optional<boolean>\n app_extensions_ui_any?: Optional<boolean>\n app_extensions_ui_count?: Optional<number>\n app_extensions_ui_custom_layout?: Optional<boolean>\n app_name_hash?: Optional<string>\n app_path_hash?: Optional<string>\n app_scopes?: Optional<string>\n app_web_backend_any?: Optional<boolean>\n app_web_backend_count?: Optional<number>\n app_web_custom_layout?: Optional<boolean>\n app_web_framework?: Optional<string>\n app_web_frontend_any?: Optional<boolean>\n app_web_frontend_count?: Optional<number>\n\n // Theme related commands\n cmd_theme_timings?: Optional<string>\n cmd_theme_errors?: Optional<string>\n cmd_theme_retries?: Optional<string>\n cmd_theme_events?: Optional<string>\n\n // Environment\n env_ci?: Optional<boolean>\n env_ci_platform?: Optional<string>\n env_device_id?: Optional<string>\n env_package_manager?: Optional<string>\n env_install_package_manager?: Optional<string>\n env_package_manager_workspaces?: Optional<boolean>\n env_plugin_installed_any_custom?: Optional<boolean>\n env_plugin_installed_shopify?: Optional<string>\n env_shell?: Optional<string>\n env_web_ide?: Optional<string>\n env_cloud?: Optional<string>\n env_is_global?: Optional<boolean>\n env_auth_method?: Optional<string>\n }\n }\n [schemaId: string]: {sensitive: JsonMap; public: JsonMap}\n}\n\n// In reality, we're normally most interested in just this from Schemas, so export it for ease of use.\n// The monorail schema itself has lots of optional values as it must be backwards-compatible. For our schema we want mandatory values instead.\nexport type MonorailEventPublic = DeepRequired<Schemas[typeof MONORAIL_COMMAND_TOPIC]['public']>\nexport type MonorailEventSensitive = Schemas[typeof MONORAIL_COMMAND_TOPIC]['sensitive']\n\ntype MonorailResult = {type: 'ok'} | {type: 'error'; message: string}\n\nconst publishedCommandNames = new Set<string>()\n\n/**\n * Publishes an event to Monorail.\n *\n * @param schemaId - The schema ID of the event to publish.\n * @param publicData - The public data to publish.\n * @param sensitiveData - The sensitive data to publish.\n * @returns A result indicating whether the event was successfully published.\n */\nexport async function publishMonorailEvent<TSchemaId extends keyof Schemas, TPayload extends Schemas[TSchemaId]>(\n schemaId: TSchemaId,\n publicData: TPayload['public'],\n sensitiveData: TPayload['sensitive'],\n): Promise<MonorailResult> {\n // If a command has already been logged, never re-log it. This is to prevent duplication caused by unexpected errors.\n const commandName = publicData.command\n if (commandName && typeof commandName === 'string') {\n if (publishedCommandNames.has(commandName)) {\n return {type: 'ok'}\n }\n publishedCommandNames.add(commandName)\n }\n\n try {\n const currentTime = new Date().getTime()\n const payload = {...publicData, ...sensitiveData}\n const body = JSON.stringify({schema_id: schemaId, payload})\n const headers = buildHeaders(currentTime)\n\n const response = await fetch(url, {method: 'POST', body, headers}, 'non-blocking')\n\n if (response.status === 200) {\n outputDebug(outputContent`Analytics event sent: ${outputToken.json(sanitizePayload(payload))}`)\n return {type: 'ok'}\n } else {\n outputDebug(`Failed to report usage analytics: ${response.statusText}`)\n return {type: 'error', message: response.statusText}\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n outputDebug(message)\n return {type: 'error', message}\n }\n}\n\n/**\n * Sanitizies the api_key from the payload and returns a new hash.\n *\n * @param payload - The public and sensitive data.\n * @returns A copy of the payload with the api_key sanitized.\n */\nfunction sanitizePayload<T extends object>(payload: T): T {\n const result = {...payload}\n if ('api_key' in result) {\n result.api_key = '****'\n }\n\n return result\n}\n\nconst buildHeaders = (currentTime: number) => {\n return {\n 'Content-Type': 'application/json; charset=utf-8',\n 'X-Monorail-Edge-Event-Created-At-Ms': currentTime.toString(),\n 'X-Monorail-Edge-Event-Sent-At-Ms': currentTime.toString(),\n }\n}\n"]}
1
+ {"version":3,"file":"monorail.js","sourceRoot":"","sources":["../../../src/public/node/monorail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,WAAW,CAAA;AAC/B,OAAO,EAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAMnE,MAAM,GAAG,GAAG,iDAAiD,CAAA;AAI7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAA;AAoL7D,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAA;AAE/C;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAmB,EACnB,UAA8B,EAC9B,aAAoC;IAEpC,qHAAqH;IACrH,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAA;IACtC,IAAI,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QACnD,IAAI,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,OAAO,EAAC,IAAI,EAAE,IAAI,EAAC,CAAA;QACrB,CAAC;QACD,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;QACxC,MAAM,OAAO,GAAG,EAAC,GAAG,UAAU,EAAE,GAAG,aAAa,EAAC,CAAA;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;QAEzC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAC,EAAE,cAAc,CAAC,CAAA;QAElF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,WAAW,CAAC,aAAa,CAAA,yBAAyB,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;YAC/F,OAAO,EAAC,IAAI,EAAE,IAAI,EAAC,CAAA;QACrB,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,qCAAqC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;YACvE,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAC,CAAA;QACtD,CAAC;QACD,qDAAqD;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,GAAG,kCAAkC,CAAA;QAChD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAChD,CAAC;QACD,WAAW,CAAC,OAAO,CAAC,CAAA;QACpB,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAmB,OAAU;IACnD,MAAM,MAAM,GAAG,EAAC,GAAG,OAAO,EAAC,CAAA;IAC3B,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,CAAC,OAAO,GAAG,MAAM,CAAA;IACzB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,EAAE;IAC3C,OAAO;QACL,cAAc,EAAE,iCAAiC;QACjD,qCAAqC,EAAE,WAAW,CAAC,QAAQ,EAAE;QAC7D,kCAAkC,EAAE,WAAW,CAAC,QAAQ,EAAE;KAC3D,CAAA;AACH,CAAC,CAAA","sourcesContent":["import {fetch} from './http.js'\nimport {outputDebug, outputContent, outputToken} from './output.js'\nimport {JsonMap} from '../../private/common/json.js'\nimport {DeepRequired} from '../common/ts/deep-required.js'\n\nexport {DeepRequired}\n\nconst url = 'https://monorail-edge.shopifysvc.com/v1/produce'\n\ntype Optional<T> = T | null\n\n// This is the topic name of the main event we log to Monorail, the command tracker\nexport const MONORAIL_COMMAND_TOPIC = 'app_cli3_command/1.26'\n\nexport interface Schemas {\n [MONORAIL_COMMAND_TOPIC]: {\n sensitive: {\n args: string\n error_message?: Optional<string>\n app_name?: Optional<string>\n metadata?: Optional<string>\n store_fqdn?: Optional<string>\n cmd_all_environment_flags?: Optional<string>\n\n // Dev related commands\n cmd_dev_tunnel_custom?: Optional<string>\n\n // Environment\n env_plugin_installed_all?: Optional<string>\n env_shopify_variables?: Optional<string>\n }\n public: {\n business_platform_id?: Optional<number>\n partner_id?: Optional<number>\n command: string\n project_type?: Optional<string>\n time_start: number\n time_end: number\n total_time: number\n success: boolean\n api_key?: Optional<string>\n cli_version: string\n uname: string\n ruby_version: string\n node_version: string\n is_employee: boolean\n store_fqdn_hash?: Optional<string>\n store_fqdn_validated?: Optional<boolean>\n store_domain?: Optional<string>\n user_id: string\n\n // Any and all commands\n cmd_all_alias_used?: Optional<string>\n cmd_all_launcher?: Optional<string>\n cmd_all_path_override?: Optional<boolean>\n cmd_all_path_override_hash?: Optional<string>\n cmd_all_plugin?: Optional<string>\n cmd_all_topic?: Optional<string>\n cmd_all_verbose?: Optional<boolean>\n cmd_all_exit?: Optional<string>\n cmd_all_force?: Optional<boolean>\n cmd_all_last_graphql_request_id?: Optional<string>\n\n cmd_all_timing_network_ms?: Optional<number>\n cmd_all_timing_prompts_ms?: Optional<number>\n cmd_all_timing_active_ms?: Optional<number>\n\n // Auto-upgrade\n env_auto_upgrade_enabled?: Optional<boolean>\n env_auto_upgrade_accepted?: Optional<boolean>\n env_auto_upgrade_skipped_reason?: Optional<string>\n env_auto_upgrade_success?: Optional<boolean>\n\n // Any extension related command\n cmd_extensions_binary_from_source?: Optional<boolean>\n\n // Scaffolding related commands\n cmd_scaffold_required_auth?: Optional<boolean>\n cmd_scaffold_template_custom?: Optional<boolean>\n cmd_scaffold_template_flavor?: Optional<string>\n cmd_scaffold_type?: Optional<string>\n cmd_scaffold_type_category?: Optional<string>\n cmd_scaffold_type_gated?: Optional<boolean>\n cmd_scaffold_type_owner?: Optional<string>\n cmd_scaffold_used_prompts_for_type?: Optional<boolean>\n\n // Used in several but not all commands\n cmd_app_dependency_installation_skipped?: Optional<boolean>\n cmd_app_reset_used?: Optional<boolean>\n cmd_app_linked_config_used?: Optional<boolean>\n cmd_app_linked_config_name?: Optional<string>\n cmd_app_linked_config_git_tracked?: Optional<boolean>\n cmd_app_all_configs_any?: Optional<boolean>\n cmd_app_all_configs_clients?: Optional<string>\n cmd_app_linked_config_source?: Optional<string>\n cmd_app_linked_config_uses_cli_managed_urls?: Optional<boolean>\n cmd_app_warning_api_key_deprecation_displayed?: Optional<boolean>\n cmd_app_deployment_mode?: Optional<string>\n cmd_app_validate_json?: Optional<boolean>\n cmd_app_validate_valid?: Optional<boolean>\n cmd_app_validate_issue_count?: Optional<number>\n cmd_app_validate_file_count?: Optional<number>\n\n // Dev related commands\n cmd_dev_tunnel_type?: Optional<string>\n cmd_dev_tunnel_custom_hash?: Optional<string>\n cmd_dev_urls_updated?: Optional<boolean>\n cmd_dev_preview_url_opened?: Optional<boolean>\n cmd_dev_graphiql_opened?: Optional<boolean>\n cmd_dev_dev_preview_toggle_used?: Optional<boolean>\n\n // Create-app related commands\n cmd_create_app_template?: Optional<string>\n cmd_create_app_template_url?: Optional<string>\n\n // Deploy related commands\n cmd_deploy_flag_message_used?: Optional<boolean>\n cmd_deploy_flag_version_used?: Optional<boolean>\n cmd_deploy_flag_source_url_used?: Optional<boolean>\n cmd_deploy_confirm_new_registrations?: Optional<number>\n cmd_deploy_confirm_updated_registrations?: Optional<number>\n cmd_deploy_confirm_removed_registrations?: Optional<number>\n cmd_deploy_confirm_cancelled?: Optional<boolean>\n cmd_deploy_confirm_time_to_complete_ms?: Optional<number>\n cmd_deploy_prompt_upgrade_to_unified_displayed?: Optional<boolean>\n cmd_deploy_prompt_upgrade_to_unified_response?: Optional<string>\n cmd_deploy_confirm_include_config_used?: Optional<boolean>\n cmd_deploy_include_config_used?: Optional<boolean>\n cmd_deploy_config_modules_breakdown?: Optional<string>\n cmd_deploy_config_modules_updated?: Optional<string>\n cmd_deploy_config_modules_added?: Optional<string>\n cmd_deploy_config_modules_deleted?: Optional<string>\n\n // Release related commands\n cmd_release_confirm_cancelled?: Optional<boolean>\n\n // App setup\n app_extensions_any?: Optional<boolean>\n app_extensions_breakdown?: Optional<string>\n app_extensions_count?: Optional<number>\n app_extensions_custom_layout?: Optional<boolean>\n app_extensions_function_any?: Optional<boolean>\n app_extensions_function_count?: Optional<number>\n app_extensions_function_custom_layout?: Optional<boolean>\n app_extensions_theme_any?: Optional<boolean>\n app_extensions_theme_count?: Optional<number>\n app_extensions_theme_custom_layout?: Optional<boolean>\n app_extensions_ui_any?: Optional<boolean>\n app_extensions_ui_count?: Optional<number>\n app_extensions_ui_custom_layout?: Optional<boolean>\n app_name_hash?: Optional<string>\n app_path_hash?: Optional<string>\n app_scopes?: Optional<string>\n app_web_backend_any?: Optional<boolean>\n app_web_backend_count?: Optional<number>\n app_web_custom_layout?: Optional<boolean>\n app_web_framework?: Optional<string>\n app_web_frontend_any?: Optional<boolean>\n app_web_frontend_count?: Optional<number>\n\n // Theme related commands\n cmd_theme_timings?: Optional<string>\n cmd_theme_errors?: Optional<string>\n cmd_theme_retries?: Optional<string>\n cmd_theme_events?: Optional<string>\n\n // Environment\n env_ci?: Optional<boolean>\n env_ci_platform?: Optional<string>\n env_device_id?: Optional<string>\n env_package_manager?: Optional<string>\n env_install_package_manager?: Optional<string>\n env_package_manager_workspaces?: Optional<boolean>\n env_plugin_installed_any_custom?: Optional<boolean>\n env_plugin_installed_shopify?: Optional<string>\n env_shell?: Optional<string>\n env_web_ide?: Optional<string>\n env_cloud?: Optional<string>\n env_is_global?: Optional<boolean>\n env_auth_method?: Optional<string>\n }\n }\n [schemaId: string]: {sensitive: JsonMap; public: JsonMap}\n}\n\n// In reality, we're normally most interested in just this from Schemas, so export it for ease of use.\n// The monorail schema itself has lots of optional values as it must be backwards-compatible. For our schema we want mandatory values instead.\nexport type MonorailEventPublic = DeepRequired<Schemas[typeof MONORAIL_COMMAND_TOPIC]['public']>\nexport type MonorailEventSensitive = Schemas[typeof MONORAIL_COMMAND_TOPIC]['sensitive']\n\ntype MonorailResult = {type: 'ok'} | {type: 'error'; message: string}\n\nconst publishedCommandNames = new Set<string>()\n\n/**\n * Publishes an event to Monorail.\n *\n * @param schemaId - The schema ID of the event to publish.\n * @param publicData - The public data to publish.\n * @param sensitiveData - The sensitive data to publish.\n * @returns A result indicating whether the event was successfully published.\n */\nexport async function publishMonorailEvent<TSchemaId extends keyof Schemas, TPayload extends Schemas[TSchemaId]>(\n schemaId: TSchemaId,\n publicData: TPayload['public'],\n sensitiveData: TPayload['sensitive'],\n): Promise<MonorailResult> {\n // If a command has already been logged, never re-log it. This is to prevent duplication caused by unexpected errors.\n const commandName = publicData.command\n if (commandName && typeof commandName === 'string') {\n if (publishedCommandNames.has(commandName)) {\n return {type: 'ok'}\n }\n publishedCommandNames.add(commandName)\n }\n\n try {\n const currentTime = new Date().getTime()\n const payload = {...publicData, ...sensitiveData}\n const body = JSON.stringify({schema_id: schemaId, payload})\n const headers = buildHeaders(currentTime)\n\n const response = await fetch(url, {method: 'POST', body, headers}, 'non-blocking')\n\n if (response.status === 200) {\n outputDebug(outputContent`Analytics event sent: ${outputToken.json(sanitizePayload(payload))}`)\n return {type: 'ok'}\n } else {\n outputDebug(`Failed to report usage analytics: ${response.statusText}`)\n return {type: 'error', message: response.statusText}\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n outputDebug(message)\n return {type: 'error', message}\n }\n}\n\n/**\n * Sanitizies the api_key from the payload and returns a new hash.\n *\n * @param payload - The public and sensitive data.\n * @returns A copy of the payload with the api_key sanitized.\n */\nfunction sanitizePayload<T extends object>(payload: T): T {\n const result = {...payload}\n if ('api_key' in result) {\n result.api_key = '****'\n }\n\n return result\n}\n\nconst buildHeaders = (currentTime: number) => {\n return {\n 'Content-Type': 'application/json; charset=utf-8',\n 'X-Monorail-Edge-Event-Created-At-Ms': currentTime.toString(),\n 'X-Monorail-Edge-Event-Sent-At-Ms': currentTime.toString(),\n }\n}\n"]}
@@ -187,6 +187,10 @@ function shouldOutput(logLevel) {
187
187
  }
188
188
  // eslint-disable-next-line import-x/no-mutable-exports
189
189
  export let collectedLogs = {};
190
+ /**
191
+ * Memoized value for the color check.
192
+ */
193
+ let memoizedShouldDisplayColors;
190
194
  /**
191
195
  * This is only used during UnitTesting.
192
196
  * If we are in a testing context, instead of printing the logs to the console,
@@ -196,12 +200,11 @@ export let collectedLogs = {};
196
200
  * @param content - The content of the log.
197
201
  */
198
202
  export function collectLog(key, content) {
199
- const output = collectedLogs.output ?? [];
200
- const data = collectedLogs[key] ?? [];
201
- data.push(stripAnsi(stringifyMessage(content) ?? ''));
202
- output.push(stripAnsi(stringifyMessage(content) ?? ''));
203
- collectedLogs[key] = data;
204
- collectedLogs.output = output;
203
+ const message = stripAnsi(stringifyMessage(content));
204
+ collectedLogs.output ?? (collectedLogs.output = []);
205
+ collectedLogs[key] ?? (collectedLogs[key] = []);
206
+ collectedLogs.output.push(message);
207
+ collectedLogs[key].push(message);
205
208
  }
206
209
  export const clearCollectedLogs = () => {
207
210
  collectedLogs = {};
@@ -269,6 +272,8 @@ export function outputCompleted(content, logger = consoleWarn) {
269
272
  export function outputDebug(content, logger = consoleWarn) {
270
273
  if (isUnitTest())
271
274
  collectLog('debug', content);
275
+ if (!shouldOutput('debug'))
276
+ return;
272
277
  const message = colors.gray(stringifyMessage(content));
273
278
  outputWhereAppropriate('debug', logger, `${new Date().toISOString()}: ${message}`);
274
279
  }
@@ -339,6 +344,10 @@ export function outputWhereAppropriate(logLevel, logger, message) {
339
344
  * @returns The message without styles.
340
345
  */
341
346
  export function unstyled(message) {
347
+ // Optimization: skip regex execution for strings that don't have ANSI escape codes.
348
+ // In high-frequency paths like terminal layout calculations, this can save significant CPU time.
349
+ if (!message.includes('\u001b'))
350
+ return message;
342
351
  return stripAnsi(message);
343
352
  }
344
353
  /**
@@ -348,13 +357,15 @@ export function unstyled(message) {
348
357
  * @returns True if the console outputs should display colors, false otherwise.
349
358
  */
350
359
  export function shouldDisplayColors(_process = process) {
351
- const { env, stdout } = _process;
352
- if (Object.hasOwnProperty.call(env, 'FORCE_COLOR')) {
353
- return isTruthy(env.FORCE_COLOR);
360
+ if (_process === process && memoizedShouldDisplayColors !== undefined) {
361
+ return memoizedShouldDisplayColors;
354
362
  }
355
- else {
356
- return Boolean(stdout.isTTY);
363
+ const { env, stdout } = _process;
364
+ const result = Object.hasOwnProperty.call(env, 'FORCE_COLOR') ? isTruthy(env.FORCE_COLOR) : Boolean(stdout.isTTY);
365
+ if (_process === process) {
366
+ memoizedShouldDisplayColors = result;
357
367
  }
368
+ return result;
358
369
  }
359
370
  /**
360
371
  * Parse title and body to be a single formatted string.