@shopify/cli-kit 3.73.2 → 3.74.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 (179) hide show
  1. package/dist/cli/api/graphql/admin/generated/get_theme.d.ts +1 -3
  2. package/dist/cli/api/graphql/admin/generated/get_theme_file_bodies.d.ts +1 -5
  3. package/dist/cli/api/graphql/admin/generated/get_theme_file_checksums.d.ts +1 -4
  4. package/dist/cli/api/graphql/admin/generated/get_themes.d.ts +1 -3
  5. package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.d.ts +1 -3
  6. package/dist/cli/api/graphql/admin/generated/online_store_password_protection.d.ts +13 -0
  7. package/dist/cli/api/graphql/admin/generated/online_store_password_protection.js +37 -0
  8. package/dist/cli/api/graphql/admin/generated/online_store_password_protection.js.map +1 -0
  9. package/dist/cli/api/graphql/admin/generated/public_api_versions.d.ts +1 -3
  10. package/dist/cli/api/graphql/admin/generated/theme_delete.d.ts +1 -3
  11. package/dist/cli/api/graphql/admin/generated/theme_files_upsert.d.ts +1 -4
  12. package/dist/cli/api/graphql/admin/generated/theme_publish.d.ts +1 -3
  13. package/dist/cli/api/graphql/admin/generated/theme_update.d.ts +1 -4
  14. package/dist/private/node/analytics.js.map +1 -1
  15. package/dist/private/node/api/graphql.js.map +1 -1
  16. package/dist/private/node/api/headers.d.ts +2 -2
  17. package/dist/private/node/api/headers.js +1 -1
  18. package/dist/private/node/api/headers.js.map +1 -1
  19. package/dist/private/node/api/rest.js.map +1 -1
  20. package/dist/private/node/api/urls.js.map +1 -1
  21. package/dist/private/node/api.js.map +1 -1
  22. package/dist/private/node/conf-store.js.map +1 -1
  23. package/dist/private/node/constants.d.ts +0 -1
  24. package/dist/private/node/constants.js +0 -1
  25. package/dist/private/node/constants.js.map +1 -1
  26. package/dist/private/node/content-tokens.js.map +1 -1
  27. package/dist/private/node/context/deprecations-store.js.map +1 -1
  28. package/dist/private/node/context/service.d.ts +0 -1
  29. package/dist/private/node/context/service.js.map +1 -1
  30. package/dist/private/node/context/utilities.d.ts +0 -1
  31. package/dist/private/node/context/utilities.js.map +1 -1
  32. package/dist/private/node/otel-metrics.js.map +1 -1
  33. package/dist/private/node/request-ids.js.map +1 -1
  34. package/dist/private/node/session/device-authorization.js.map +1 -1
  35. package/dist/private/node/session/exchange.js +2 -3
  36. package/dist/private/node/session/exchange.js.map +1 -1
  37. package/dist/private/node/session/identity-token-validation.js.map +1 -1
  38. package/dist/private/node/session/identity.js.map +1 -1
  39. package/dist/private/node/session/scopes.d.ts +2 -3
  40. package/dist/private/node/session/scopes.js +7 -8
  41. package/dist/private/node/session/scopes.js.map +1 -1
  42. package/dist/private/node/session/store.js.map +1 -1
  43. package/dist/private/node/session/validate.js.map +1 -1
  44. package/dist/private/node/session.d.ts +0 -1
  45. package/dist/private/node/session.js +3 -74
  46. package/dist/private/node/session.js.map +1 -1
  47. package/dist/private/node/testing/ui.d.ts +0 -1
  48. package/dist/private/node/testing/ui.js.map +1 -1
  49. package/dist/private/node/themes/replace-invalid-characters.js +3 -3
  50. package/dist/private/node/themes/replace-invalid-characters.js.map +1 -1
  51. package/dist/private/node/ui/components/Alert.d.ts +2 -1
  52. package/dist/private/node/ui/components/Alert.js +2 -1
  53. package/dist/private/node/ui/components/Alert.js.map +1 -1
  54. package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
  55. package/dist/private/node/ui/components/Banner.js.map +1 -1
  56. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  57. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
  58. package/dist/private/node/ui/components/FatalError.js +2 -1
  59. package/dist/private/node/ui/components/FatalError.js.map +1 -1
  60. package/dist/private/node/ui/components/Link.js.map +1 -1
  61. package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
  62. package/dist/private/node/ui/components/Scrollbar.js.map +1 -1
  63. package/dist/private/node/ui/components/SelectInput.js.map +1 -1
  64. package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
  65. package/dist/private/node/ui/components/Table/Row.d.ts +0 -1
  66. package/dist/private/node/ui/components/Table/Row.js.map +1 -1
  67. package/dist/private/node/ui/components/Table/Table.d.ts +0 -1
  68. package/dist/private/node/ui/components/Table/Table.js.map +1 -1
  69. package/dist/private/node/ui/components/TabularData.d.ts +8 -0
  70. package/dist/private/node/ui/components/TabularData.js +16 -0
  71. package/dist/private/node/ui/components/TabularData.js.map +1 -0
  72. package/dist/private/node/ui/components/Tasks.d.ts +1 -1
  73. package/dist/private/node/ui/components/Tasks.js.map +1 -1
  74. package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
  75. package/dist/private/node/ui/components/TextInput.js.map +1 -1
  76. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  77. package/dist/private/node/ui/components/TokenizedText.d.ts +12 -19
  78. package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
  79. package/dist/private/node/ui/hooks/use-layout.d.ts +0 -1
  80. package/dist/private/node/ui/hooks/use-layout.js.map +1 -1
  81. package/dist/private/node/ui/hooks/use-prompt.d.ts +0 -1
  82. package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
  83. package/dist/private/node/ui/utilities.d.ts +15 -1
  84. package/dist/private/node/ui.d.ts +0 -2
  85. package/dist/private/node/ui.js.map +1 -1
  86. package/dist/public/common/retry.js.map +1 -1
  87. package/dist/public/common/string.js.map +1 -1
  88. package/dist/public/common/ts/json-narrowing.js.map +1 -1
  89. package/dist/public/common/url.js.map +1 -1
  90. package/dist/public/common/version.d.ts +1 -1
  91. package/dist/public/common/version.js +1 -1
  92. package/dist/public/common/version.js.map +1 -1
  93. package/dist/public/node/analytics.js.map +1 -1
  94. package/dist/public/node/api/admin.js.map +1 -1
  95. package/dist/public/node/api/app-management.js.map +1 -1
  96. package/dist/public/node/api/graphql.js.map +1 -1
  97. package/dist/public/node/api/partners.js.map +1 -1
  98. package/dist/public/node/api/rest-api-throttler.js.map +1 -1
  99. package/dist/public/node/archiver.js.map +1 -1
  100. package/dist/public/node/base-command.js.map +1 -1
  101. package/dist/public/node/cli-launcher.js.map +1 -1
  102. package/dist/public/node/cli.d.ts +0 -1
  103. package/dist/public/node/cli.js.map +1 -1
  104. package/dist/public/node/context/fqdn.js.map +1 -1
  105. package/dist/public/node/context/local.d.ts +4 -5
  106. package/dist/public/node/context/local.js +6 -5
  107. package/dist/public/node/context/local.js.map +1 -1
  108. package/dist/public/node/context/spin.d.ts +0 -1
  109. package/dist/public/node/context/spin.js.map +1 -1
  110. package/dist/public/node/context/utilities.js.map +1 -1
  111. package/dist/public/node/crypto.d.ts +0 -1
  112. package/dist/public/node/custom-oclif-loader.js.map +1 -1
  113. package/dist/public/node/dot-env.js.map +1 -1
  114. package/dist/public/node/environment.d.ts +0 -1
  115. package/dist/public/node/environment.js.map +1 -1
  116. package/dist/public/node/environments.js.map +1 -1
  117. package/dist/public/node/error-handler.js +1 -1
  118. package/dist/public/node/error-handler.js.map +1 -1
  119. package/dist/public/node/error.js.map +1 -1
  120. package/dist/public/node/framework.js.map +1 -1
  121. package/dist/public/node/fs.d.ts +20 -2
  122. package/dist/public/node/fs.js +24 -0
  123. package/dist/public/node/fs.js.map +1 -1
  124. package/dist/public/node/git.js.map +1 -1
  125. package/dist/public/node/github.js.map +1 -1
  126. package/dist/public/node/global-context.js.map +1 -1
  127. package/dist/public/node/hooks/deprecations.js.map +1 -1
  128. package/dist/public/node/hooks/postrun.js.map +1 -1
  129. package/dist/public/node/hooks/prerun.js.map +1 -1
  130. package/dist/public/node/http.js.map +1 -1
  131. package/dist/public/node/is-global.js.map +1 -1
  132. package/dist/public/node/json-schema.js.map +1 -1
  133. package/dist/public/node/liquid.js.map +1 -1
  134. package/dist/public/node/metadata.js +1 -1
  135. package/dist/public/node/metadata.js.map +1 -1
  136. package/dist/public/node/monorail.d.ts +1 -0
  137. package/dist/public/node/monorail.js.map +1 -1
  138. package/dist/public/node/node-package-manager.d.ts +0 -2
  139. package/dist/public/node/node-package-manager.js.map +1 -1
  140. package/dist/public/node/notifications-system.d.ts +6 -7
  141. package/dist/public/node/notifications-system.js.map +1 -1
  142. package/dist/public/node/os.js.map +1 -1
  143. package/dist/public/node/output.d.ts +0 -2
  144. package/dist/public/node/output.js +3 -3
  145. package/dist/public/node/output.js.map +1 -1
  146. package/dist/public/node/path.d.ts +0 -1
  147. package/dist/public/node/path.js.map +1 -1
  148. package/dist/public/node/plugins.d.ts +1 -1
  149. package/dist/public/node/plugins.js.map +1 -1
  150. package/dist/public/node/result.js.map +1 -1
  151. package/dist/public/node/schema.js.map +1 -1
  152. package/dist/public/node/session.d.ts +0 -1
  153. package/dist/public/node/session.js.map +1 -1
  154. package/dist/public/node/system.d.ts +0 -1
  155. package/dist/public/node/system.js.map +1 -1
  156. package/dist/public/node/tcp.js.map +1 -1
  157. package/dist/public/node/themes/api.d.ts +1 -0
  158. package/dist/public/node/themes/api.js +10 -0
  159. package/dist/public/node/themes/api.js.map +1 -1
  160. package/dist/public/node/themes/conf.js.map +1 -1
  161. package/dist/public/node/themes/theme-manager.js.map +1 -1
  162. package/dist/public/node/themes/types.d.ts +4 -1
  163. package/dist/public/node/themes/types.js.map +1 -1
  164. package/dist/public/node/themes/urls.js.map +1 -1
  165. package/dist/public/node/themes/utils.js.map +1 -1
  166. package/dist/public/node/tree-kill.js.map +1 -1
  167. package/dist/public/node/ui.d.ts +0 -1
  168. package/dist/public/node/ui.js.map +1 -1
  169. package/dist/public/node/upgrade.js.map +1 -1
  170. package/dist/public/node/vendor/dev_server/DevServer.js.map +1 -1
  171. package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
  172. package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
  173. package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultMeterProvider.js.map +1 -1
  174. package/dist/public/node/vendor/otel-js/utils/throttle.js.map +1 -1
  175. package/dist/public/node/vendor/otel-js/utils/validators.js.map +1 -1
  176. package/dist/public/node/version.js.map +1 -1
  177. package/dist/public/node/vscode.js.map +1 -1
  178. package/dist/tsconfig.tsbuildinfo +1 -1
  179. package/package.json +27 -29
@@ -1 +1 @@
1
- {"version":3,"file":"otel-metrics.js","sourceRoot":"","sources":["../../../src/private/node/otel-metrics.ts"],"names":[],"mappings":"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","sourcesContent":["import {MetricInstrumentType, OtelService} from '../../public/node/vendor/otel-js/service/types.js'\nimport {outputContent, outputDebug, outputToken} from '../../public/node/output.js'\nimport {\n DefaultOtelService,\n DefaultOtelServiceOptions,\n} from '../../public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js'\nimport {isUnitTest, opentelemetryDomain} from '../../public/node/context/local.js'\nimport {isSpinEnvironment} from '../../public/node/context/spin.js'\nimport {ValueType} from '@opentelemetry/api'\n\ntype MetricRecorder =\n | 'console'\n | {\n type: 'otel'\n otel: Pick<OtelService, 'record'>\n }\n\n// this should be type, not interface\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ntype Labels = {\n exit: string\n job: string\n cli_version: string\n}\n\ninterface Timing {\n active: number\n network: number\n prompt: number\n}\n\nenum Name {\n Counter = 'cli_commands_total',\n Duration = 'cli_commands_duration_ms',\n Elapsed = 'cli_commands_wall_clock_elapsed_ms',\n}\n\ninterface CreateMetricRecorderOptions {\n skipMetricAnalytics: boolean\n otelOptions: Omit<DefaultOtelServiceOptions, 'env' | 'otelEndpoint'>\n}\n\ninterface RecordMetricsOptions {\n /** If true, don't log anything */\n skipMetricAnalytics: boolean\n /** The CLI version running the command */\n cliVersion: string\n /** The plug-in that owns the command */\n owningPlugin: string\n /** The command name, e.g. `app dev` */\n command: string\n /** The exit mode for the command */\n exitMode: string\n}\n\n/**\n * Record reliability metrics.\n */\nexport async function recordMetrics(\n options: RecordMetricsOptions,\n timing: Timing,\n recorderFactory: (options: CreateMetricRecorderOptions) => MetricRecorder = createMetricRecorder,\n) {\n const recorder = recorderFactory({\n skipMetricAnalytics: options.skipMetricAnalytics,\n otelOptions: defaultOtelOptions(),\n })\n\n let regularisedCliVersion = options.cliVersion\n\n if (options.cliVersion.includes('nightly')) {\n regularisedCliVersion = 'nightly'\n } else if (options.cliVersion.includes('pre')) {\n regularisedCliVersion = 'pre'\n }\n const labels = {\n exit: options.exitMode,\n job: `${options.owningPlugin}::${options.command}`,\n cli_version: regularisedCliVersion,\n }\n\n recordCommandCounter(recorder, labels)\n recordCommandTiming(recorder, labels, timing)\n}\n\n/**\n * Get the default options for the OTEL service. These are the same across environments.\n */\nfunction defaultOtelOptions(): Omit<DefaultOtelServiceOptions, 'env' | 'otelEndpoint'> {\n return {\n serviceName: 'shopify-cli',\n throttleLimit: 1000,\n prefixMetric: false,\n metrics: {\n [Name.Counter]: {\n type: MetricInstrumentType.Counter,\n description: 'Total number of CLI commands executed',\n valueType: ValueType.INT,\n },\n [Name.Duration]: {\n type: MetricInstrumentType.Histogram,\n description:\n 'Total time spent in execution of CLI commands. Does not include time spent waiting for network, prompts, etc.',\n valueType: ValueType.INT,\n boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10_000, 20_000, 50_000],\n },\n [Name.Elapsed]: {\n type: MetricInstrumentType.Histogram,\n description:\n 'Total time elapsed from start to finish of CLI commands. Includes time spent waiting for network, prompts, etc.',\n valueType: ValueType.INT,\n boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10_000, 20_000, 50_000],\n },\n },\n }\n}\n\n/**\n * Create the metric recorder for this command.\n *\n * If metric logging is disabled, or we are running in a unit test or Spin, we record to the console.\n *\n */\nfunction createMetricRecorder(options: CreateMetricRecorderOptions): MetricRecorder {\n let recorder: MetricRecorder = 'console'\n if (!(options.skipMetricAnalytics || isUnitTest() || isSpinEnvironment())) {\n recorder = {\n type: 'otel',\n otel: globalOtelService(options),\n }\n }\n return recorder\n}\n\nlet _otelService: OtelService | undefined\n\n/**\n * OTEL service singleton.\n *\n * The service is a singleton as it uses a global diagnostic logger that assumes its the only one in the process.\n */\nfunction globalOtelService(options: CreateMetricRecorderOptions): OtelService {\n if (!_otelService) {\n _otelService = new DefaultOtelService({\n ...options.otelOptions,\n env: undefined,\n otelEndpoint: `${opentelemetryDomain()}/v1/metrics`,\n })\n }\n return _otelService\n}\n\n/**\n * Log command counter metrics.\n */\nfunction recordCommandCounter(recorder: MetricRecorder, labels: Labels) {\n if (recorder === 'console') {\n outputDebug(outputContent`[OTEL] record ${Name.Counter} counter ${outputToken.json({labels})}`)\n return\n }\n recorder.otel.record(Name.Counter, 1, labels)\n}\n\n/**\n * Log command timing metrics.\n */\nfunction recordCommandTiming(recorder: MetricRecorder, labels: Labels, timing: Timing) {\n if (recorder === 'console') {\n outputDebug(\n outputContent`[OTEL] record ${Name.Duration} histogram ${timing.active.toString()}ms ${outputToken.json({\n labels,\n })}`,\n )\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"active\" ${timing.active.toString()}ms`)\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"network\" ${timing.network.toString()}ms`)\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"prompt\" ${timing.prompt.toString()}ms`)\n return\n }\n\n if (timing.active > 0) {\n recorder.otel.record(Name.Duration, timing.active, labels)\n recorder.otel.record(Name.Elapsed, timing.active, {...labels, stage: 'active'})\n }\n if (timing.network > 0) {\n recorder.otel.record(Name.Elapsed, timing.network, {...labels, stage: 'network'})\n }\n if (timing.prompt > 0) {\n recorder.otel.record(Name.Elapsed, timing.prompt, {...labels, stage: 'prompt'})\n }\n}\n"]}
1
+ {"version":3,"file":"otel-metrics.js","sourceRoot":"","sources":["../../../src/private/node/otel-metrics.ts"],"names":[],"mappings":"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","sourcesContent":["import {MetricInstrumentType, OtelService} from '../../public/node/vendor/otel-js/service/types.js'\nimport {outputContent, outputDebug, outputToken} from '../../public/node/output.js'\nimport {\n DefaultOtelService,\n DefaultOtelServiceOptions,\n} from '../../public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js'\nimport {isUnitTest, opentelemetryDomain} from '../../public/node/context/local.js'\nimport {isSpinEnvironment} from '../../public/node/context/spin.js'\nimport {ValueType} from '@opentelemetry/api'\n\ntype MetricRecorder =\n | 'console'\n | {\n type: 'otel'\n otel: Pick<OtelService, 'record'>\n }\n\n// this should be type, not interface\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ntype Labels = {\n exit: string\n job: string\n cli_version: string\n}\n\ninterface Timing {\n active: number\n network: number\n prompt: number\n}\n\nenum Name {\n Counter = 'cli_commands_total',\n Duration = 'cli_commands_duration_ms',\n Elapsed = 'cli_commands_wall_clock_elapsed_ms',\n}\n\ninterface CreateMetricRecorderOptions {\n skipMetricAnalytics: boolean\n otelOptions: Omit<DefaultOtelServiceOptions, 'env' | 'otelEndpoint'>\n}\n\ninterface RecordMetricsOptions {\n /** If true, don't log anything */\n skipMetricAnalytics: boolean\n /** The CLI version running the command */\n cliVersion: string\n /** The plug-in that owns the command */\n owningPlugin: string\n /** The command name, e.g. `app dev` */\n command: string\n /** The exit mode for the command */\n exitMode: string\n}\n\n/**\n * Record reliability metrics.\n */\nexport async function recordMetrics(\n options: RecordMetricsOptions,\n timing: Timing,\n recorderFactory: (options: CreateMetricRecorderOptions) => MetricRecorder = createMetricRecorder,\n) {\n const recorder = recorderFactory({\n skipMetricAnalytics: options.skipMetricAnalytics,\n otelOptions: defaultOtelOptions(),\n })\n\n let regularisedCliVersion = options.cliVersion\n\n if (options.cliVersion.includes('nightly')) {\n regularisedCliVersion = 'nightly'\n } else if (options.cliVersion.includes('pre')) {\n regularisedCliVersion = 'pre'\n }\n const labels = {\n exit: options.exitMode,\n job: `${options.owningPlugin}::${options.command}`,\n cli_version: regularisedCliVersion,\n }\n\n recordCommandCounter(recorder, labels)\n recordCommandTiming(recorder, labels, timing)\n}\n\n/**\n * Get the default options for the OTEL service. These are the same across environments.\n */\nfunction defaultOtelOptions(): Omit<DefaultOtelServiceOptions, 'env' | 'otelEndpoint'> {\n return {\n serviceName: 'shopify-cli',\n throttleLimit: 1000,\n prefixMetric: false,\n metrics: {\n [Name.Counter]: {\n type: MetricInstrumentType.Counter,\n description: 'Total number of CLI commands executed',\n valueType: ValueType.INT,\n },\n [Name.Duration]: {\n type: MetricInstrumentType.Histogram,\n description:\n 'Total time spent in execution of CLI commands. Does not include time spent waiting for network, prompts, etc.',\n valueType: ValueType.INT,\n boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10_000, 20_000, 50_000],\n },\n [Name.Elapsed]: {\n type: MetricInstrumentType.Histogram,\n description:\n 'Total time elapsed from start to finish of CLI commands. Includes time spent waiting for network, prompts, etc.',\n valueType: ValueType.INT,\n boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10_000, 20_000, 50_000],\n },\n },\n }\n}\n\n/**\n * Create the metric recorder for this command.\n *\n * If metric logging is disabled, or we are running in a unit test or Spin, we record to the console.\n *\n */\nfunction createMetricRecorder(options: CreateMetricRecorderOptions): MetricRecorder {\n let recorder: MetricRecorder = 'console'\n if (!(options.skipMetricAnalytics || isUnitTest() || isSpinEnvironment())) {\n recorder = {\n type: 'otel',\n otel: globalOtelService(options),\n }\n }\n return recorder\n}\n\nlet _otelService: OtelService | undefined\n\n/**\n * OTEL service singleton.\n *\n * The service is a singleton as it uses a global diagnostic logger that assumes its the only one in the process.\n */\nfunction globalOtelService(options: CreateMetricRecorderOptions): OtelService {\n if (!_otelService) {\n _otelService = new DefaultOtelService({\n ...options.otelOptions,\n env: undefined,\n otelEndpoint: `${opentelemetryDomain()}/v1/metrics`,\n })\n }\n return _otelService\n}\n\n/**\n * Log command counter metrics.\n */\nfunction recordCommandCounter(recorder: MetricRecorder, labels: Labels) {\n if (recorder === 'console') {\n outputDebug(outputContent`[OTEL] record ${Name.Counter} counter ${outputToken.json({labels})}`)\n return\n }\n recorder.otel.record(Name.Counter, 1, labels)\n}\n\n/**\n * Log command timing metrics.\n */\nfunction recordCommandTiming(recorder: MetricRecorder, labels: Labels, timing: Timing) {\n if (recorder === 'console') {\n outputDebug(\n outputContent`[OTEL] record ${Name.Duration} histogram ${timing.active.toString()}ms ${outputToken.json({\n labels,\n })}`,\n )\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"active\" ${timing.active.toString()}ms`)\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"network\" ${timing.network.toString()}ms`)\n outputDebug(outputContent`[OTEL] record ${Name.Elapsed} histogram stage=\"prompt\" ${timing.prompt.toString()}ms`)\n return\n }\n\n if (timing.active > 0) {\n recorder.otel.record(Name.Duration, timing.active, labels)\n recorder.otel.record(Name.Elapsed, timing.active, {...labels, stage: 'active'})\n }\n if (timing.network > 0) {\n recorder.otel.record(Name.Elapsed, timing.network, {...labels, stage: 'network'})\n }\n if (timing.prompt > 0) {\n recorder.otel.record(Name.Elapsed, timing.prompt, {...labels, stage: 'prompt'})\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"request-ids.js","sourceRoot":"","sources":["../../../src/private/node/request-ids.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC;;GAEG;AACH,MAAM,mBAAmB;IAAzB;QAUU,eAAU,GAAa,EAAE,CAAA;IAyBnC,CAAC;IAhCC,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE;YACjC,mBAAmB,CAAC,QAAQ,GAAG,IAAI,mBAAmB,EAAE,CAAA;SACzD;QACD,OAAO,mBAAmB,CAAC,QAAQ,CAAA;IACrC,CAAC;IAID;;;OAGG;IACH,YAAY,CAAC,SAAoC;QAC/C,IAAI,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,eAAe,EAAE;YACzD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;SAChC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;IACtB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAA","sourcesContent":["export const MAX_REQUEST_IDS = 100\n\n/**\n * Manages collection of request IDs during command execution\n */\nclass RequestIDCollection {\n private static instance: RequestIDCollection\n\n static getInstance(): RequestIDCollection {\n if (!RequestIDCollection.instance) {\n RequestIDCollection.instance = new RequestIDCollection()\n }\n return RequestIDCollection.instance\n }\n\n private requestIds: string[] = []\n\n /**\n * Add a request ID to the collection\n * We only report the first MAX_REQUEST_IDS request IDs.\n */\n addRequestId(requestId: string | undefined | null) {\n if (requestId && this.requestIds.length < MAX_REQUEST_IDS) {\n this.requestIds.push(requestId)\n }\n }\n\n /**\n * Get all collected request IDs\n */\n getRequestIds(): string[] {\n return this.requestIds\n }\n\n /**\n * Clear all stored request IDs\n */\n clear() {\n this.requestIds = []\n }\n}\n\nexport const requestIdsCollection = RequestIDCollection.getInstance()\n"]}
1
+ {"version":3,"file":"request-ids.js","sourceRoot":"","sources":["../../../src/private/node/request-ids.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAA;AAElC;;GAEG;AACH,MAAM,mBAAmB;IAAzB;QAUU,eAAU,GAAa,EAAE,CAAA;IAyBnC,CAAC;IAhCC,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC;YAClC,mBAAmB,CAAC,QAAQ,GAAG,IAAI,mBAAmB,EAAE,CAAA;QAC1D,CAAC;QACD,OAAO,mBAAmB,CAAC,QAAQ,CAAA;IACrC,CAAC;IAID;;;OAGG;IACH,YAAY,CAAC,SAAoC;QAC/C,IAAI,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;YAC1D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;IACtB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAA","sourcesContent":["export const MAX_REQUEST_IDS = 100\n\n/**\n * Manages collection of request IDs during command execution\n */\nclass RequestIDCollection {\n private static instance: RequestIDCollection\n\n static getInstance(): RequestIDCollection {\n if (!RequestIDCollection.instance) {\n RequestIDCollection.instance = new RequestIDCollection()\n }\n return RequestIDCollection.instance\n }\n\n private requestIds: string[] = []\n\n /**\n * Add a request ID to the collection\n * We only report the first MAX_REQUEST_IDS request IDs.\n */\n addRequestId(requestId: string | undefined | null) {\n if (requestId && this.requestIds.length < MAX_REQUEST_IDS) {\n this.requestIds.push(requestId)\n }\n }\n\n /**\n * Get all collected request IDs\n */\n getRequestIds(): string[] {\n return this.requestIds\n }\n\n /**\n * Clear all stored request IDs\n */\n clear() {\n this.requestIds = []\n }\n}\n\nexport const requestIdsCollection = RequestIDCollection.getInstance()\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"device-authorization.js","sourceRoot":"","sources":["../../../../src/private/node/session/device-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import {clientId} from './identity.js'\nimport {exchangeDeviceCodeForAccessToken} from './exchange.js'\nimport {IdentityToken} from './schema.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {outputContent, outputDebug, outputInfo, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../../../public/node/error.js'\nimport {isCloudEnvironment} from '../../../public/node/context/local.js'\nimport {openURL} from '../../../public/node/system.js'\nimport {isTTY, keypress} from '../../../public/node/ui.js'\n\nexport interface DeviceAuthorizationResponse {\n deviceCode: string\n userCode: string\n verificationUri: string\n expiresIn: number\n verificationUriComplete?: string\n interval?: number\n}\n\n/**\n * Initiate a device authorization flow.\n * This will return a DeviceAuthorizationResponse containing the URL where user\n * should go to authorize the device without the need of a callback to the CLI.\n *\n * Also returns a `deviceCode` used for polling the token endpoint in the next step.\n *\n * @param scopes - The scopes to request\n * @returns An object with the device authorization response.\n */\nexport async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {\n const fqdn = await identityFqdn()\n const identityClientId = clientId()\n const queryParams = {client_id: identityClientId, scope: scopes.join(' ')}\n const url = `https://${fqdn}/oauth/device_authorization`\n\n const response = await shopifyFetch(url, {\n method: 'POST',\n headers: {'Content-type': 'application/x-www-form-urlencoded'},\n body: convertRequestToParams(queryParams),\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonResult: any = await response.json()\n\n outputDebug(outputContent`Received device authorization code: ${outputToken.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) {\n throw new BugError('Failed to start authorization process')\n }\n\n outputInfo('\\nTo run this command, log in to Shopify.')\n\n if (!isTTY()) {\n throw new AbortError(\n 'Authorization is required to continue, but the current environment does not support interactive prompts.',\n 'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.',\n )\n }\n\n outputInfo(outputContent`User verification code: ${jsonResult.user_code}`)\n const linkToken = outputToken.link(jsonResult.verification_uri_complete)\n\n if (isCloudEnvironment()) {\n outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`)\n } else {\n outputInfo('👉 Press any key to open the login page on your browser')\n await keypress()\n await openURL(jsonResult.verification_uri_complete)\n outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`)\n }\n\n return {\n deviceCode: jsonResult.device_code,\n userCode: jsonResult.user_code,\n verificationUri: jsonResult.verification_uri,\n expiresIn: jsonResult.expires_in,\n verificationUriComplete: jsonResult.verification_uri_complete,\n interval: jsonResult.interval,\n }\n}\n\n/**\n * Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.\n * The endpoint will return `authorization_pending` until the user completes the auth flow in the browser.\n * Once the user completes the auth flow, the endpoint will return the identity token.\n *\n * Timeout for the polling is defined by the server and is around 600 seconds.\n *\n * @param code - The device code obtained after starting a device identity flow\n * @param interval - The interval to poll the token endpoint\n * @returns The identity token\n */\nexport async function pollForDeviceAuthorization(code: string, interval = 5): Promise<IdentityToken> {\n let currentIntervalInSeconds = interval\n\n return new Promise<IdentityToken>((resolve, reject) => {\n const onPoll = async () => {\n const result = await exchangeDeviceCodeForAccessToken(code)\n if (!result.isErr()) {\n resolve(result.value)\n return\n }\n\n const error = result.error ?? 'unknown_failure'\n\n outputDebug(outputContent`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending': {\n startPolling()\n return\n }\n case 'slow_down':\n currentIntervalInSeconds += 5\n {\n startPolling()\n return\n }\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure': {\n reject(result)\n }\n }\n }\n\n const startPolling = () => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n setTimeout(onPoll, currentIntervalInSeconds * 1000)\n }\n\n startPolling()\n })\n}\n\nfunction convertRequestToParams(queryParams: {client_id: string; scope: string}): string {\n return Object.entries(queryParams)\n .map(([key, value]) => value && `${key}=${value}`)\n .filter((hasValue) => Boolean(hasValue))\n .join('&')\n}\n"]}
1
+ {"version":3,"file":"device-authorization.js","sourceRoot":"","sources":["../../../../src/private/node/session/device-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import {clientId} from './identity.js'\nimport {exchangeDeviceCodeForAccessToken} from './exchange.js'\nimport {IdentityToken} from './schema.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {outputContent, outputDebug, outputInfo, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../../../public/node/error.js'\nimport {isCloudEnvironment} from '../../../public/node/context/local.js'\nimport {openURL} from '../../../public/node/system.js'\nimport {isTTY, keypress} from '../../../public/node/ui.js'\n\nexport interface DeviceAuthorizationResponse {\n deviceCode: string\n userCode: string\n verificationUri: string\n expiresIn: number\n verificationUriComplete?: string\n interval?: number\n}\n\n/**\n * Initiate a device authorization flow.\n * This will return a DeviceAuthorizationResponse containing the URL where user\n * should go to authorize the device without the need of a callback to the CLI.\n *\n * Also returns a `deviceCode` used for polling the token endpoint in the next step.\n *\n * @param scopes - The scopes to request\n * @returns An object with the device authorization response.\n */\nexport async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {\n const fqdn = await identityFqdn()\n const identityClientId = clientId()\n const queryParams = {client_id: identityClientId, scope: scopes.join(' ')}\n const url = `https://${fqdn}/oauth/device_authorization`\n\n const response = await shopifyFetch(url, {\n method: 'POST',\n headers: {'Content-type': 'application/x-www-form-urlencoded'},\n body: convertRequestToParams(queryParams),\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonResult: any = await response.json()\n\n outputDebug(outputContent`Received device authorization code: ${outputToken.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) {\n throw new BugError('Failed to start authorization process')\n }\n\n outputInfo('\\nTo run this command, log in to Shopify.')\n\n if (!isTTY()) {\n throw new AbortError(\n 'Authorization is required to continue, but the current environment does not support interactive prompts.',\n 'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.',\n )\n }\n\n outputInfo(outputContent`User verification code: ${jsonResult.user_code}`)\n const linkToken = outputToken.link(jsonResult.verification_uri_complete)\n\n if (isCloudEnvironment()) {\n outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`)\n } else {\n outputInfo('👉 Press any key to open the login page on your browser')\n await keypress()\n await openURL(jsonResult.verification_uri_complete)\n outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`)\n }\n\n return {\n deviceCode: jsonResult.device_code,\n userCode: jsonResult.user_code,\n verificationUri: jsonResult.verification_uri,\n expiresIn: jsonResult.expires_in,\n verificationUriComplete: jsonResult.verification_uri_complete,\n interval: jsonResult.interval,\n }\n}\n\n/**\n * Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.\n * The endpoint will return `authorization_pending` until the user completes the auth flow in the browser.\n * Once the user completes the auth flow, the endpoint will return the identity token.\n *\n * Timeout for the polling is defined by the server and is around 600 seconds.\n *\n * @param code - The device code obtained after starting a device identity flow\n * @param interval - The interval to poll the token endpoint\n * @returns The identity token\n */\nexport async function pollForDeviceAuthorization(code: string, interval = 5): Promise<IdentityToken> {\n let currentIntervalInSeconds = interval\n\n return new Promise<IdentityToken>((resolve, reject) => {\n const onPoll = async () => {\n const result = await exchangeDeviceCodeForAccessToken(code)\n if (!result.isErr()) {\n resolve(result.value)\n return\n }\n\n const error = result.error ?? 'unknown_failure'\n\n outputDebug(outputContent`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending': {\n startPolling()\n return\n }\n case 'slow_down':\n currentIntervalInSeconds += 5\n {\n startPolling()\n return\n }\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure': {\n reject(result)\n }\n }\n }\n\n const startPolling = () => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n setTimeout(onPoll, currentIntervalInSeconds * 1000)\n }\n\n startPolling()\n })\n}\n\nfunction convertRequestToParams(queryParams: {client_id: string; scope: string}): string {\n return Object.entries(queryParams)\n .map(([key, value]) => value && `${key}=${value}`)\n .filter((hasValue) => Boolean(hasValue))\n .join('&')\n}\n"]}
@@ -3,7 +3,7 @@ import { identityFqdn } from '../../../public/node/context/fqdn.js';
3
3
  import { shopifyFetch } from '../../../public/node/http.js';
4
4
  import { err, ok } from '../../../public/node/result.js';
5
5
  import { AbortError, BugError, ExtendableError } from '../../../public/node/error.js';
6
- import { isAppManagementEnabled } from '../../../public/node/context/local.js';
6
+ import { isAppManagementDisabled } from '../../../public/node/context/local.js';
7
7
  import { setLastSeenAuthMethod, setLastSeenUserIdAfterAuth } from '../session.js';
8
8
  import * as jose from 'jose';
9
9
  import { nonRandomUUID } from '@shopify/cli-kit/node/crypto';
@@ -21,13 +21,12 @@ class InvalidTargetError extends AbortError {
21
21
  */
22
22
  export async function exchangeAccessForApplicationTokens(identityToken, scopes, store) {
23
23
  const token = identityToken.accessToken;
24
- const appManagementEnabled = isAppManagementEnabled();
25
24
  const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([
26
25
  requestAppToken('partners', token, scopes.partners),
27
26
  requestAppToken('storefront-renderer', token, scopes.storefront),
28
27
  requestAppToken('business-platform', token, scopes.businessPlatform),
29
28
  store ? requestAppToken('admin', token, scopes.admin, store) : {},
30
- appManagementEnabled ? requestAppToken('app-management', token, scopes.appManagement) : {},
29
+ isAppManagementDisabled() ? {} : requestAppToken('app-management', token, scopes.appManagement),
31
30
  ]);
32
31
  return {
33
32
  ...partners,
@@ -1 +1 @@
1
- {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, BugError, ExtendableError} from '../../../public/node/error.js'\nimport {isAppManagementEnabled} from '../../../public/node/context/local.js'\nimport {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../session.js'\nimport * as jose from 'jose'\nimport {nonRandomUUID} from '@shopify/cli-kit/node/crypto'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\nclass InvalidTargetError extends AbortError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n appManagement: string[]\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n const appManagementEnabled = isAppManagementEnabled()\n\n const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n appManagementEnabled ? requestAppToken('app-management', token, scopes.appManagement) : {},\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n ...appManagement,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value, currentToken.userId)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<{accessToken: string; userId: string}> {\n const appId = applicationId('partners')\n try {\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const accessToken = newToken[appId]!.accessToken\n const userId = nonRandomUUID(token)\n setLastSeenUserIdAfterAuth(userId)\n setLastSeenAuthMethod('partners_token')\n return {accessToken, userId}\n } catch (error) {\n throw new AbortError('The custom token provided is invalid.', 'Ensure the token is correct and not expired.')\n }\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n id_token?: string\n}\n\nfunction tokenRequestErrorHandler(error: string) {\n const invalidTargetErrorMessage =\n 'You are not authorized to use the CLI to develop in the provided store.' +\n '\\n\\n' +\n \"You can't use Shopify CLI with development stores if you only have Partner \" +\n 'staff member access. If you want to use Shopify CLI to work on a development store, then ' +\n 'you should be the store owner or create a staff account on the store.' +\n '\\n\\n' +\n \"If you're the store owner, then you need to log in to the store directly using the \" +\n 'store URL at least once before you log in using Shopify CLI.' +\n 'Logging in to the Shopify admin directly connects the development ' +\n 'store with your Shopify login.'\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n if (error === 'invalid_target') {\n return new InvalidTargetError(invalidTargetErrorMessage)\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult, existingUserId?: string): IdentityToken {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const userId = existingUserId ?? (result.id_token ? jose.decodeJwt(result.id_token).sub! : undefined)\n\n if (!userId) {\n throw new BugError('Error setting userId for session. No id_token or pre-existing user ID provided.')\n }\n\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n userId,\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
1
+ {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, BugError, ExtendableError} from '../../../public/node/error.js'\nimport {isAppManagementDisabled} from '../../../public/node/context/local.js'\nimport {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../session.js'\nimport * as jose from 'jose'\nimport {nonRandomUUID} from '@shopify/cli-kit/node/crypto'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\nclass InvalidTargetError extends AbortError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n appManagement: string[]\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n isAppManagementDisabled() ? {} : requestAppToken('app-management', token, scopes.appManagement),\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n ...appManagement,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value, currentToken.userId)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<{accessToken: string; userId: string}> {\n const appId = applicationId('partners')\n try {\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const accessToken = newToken[appId]!.accessToken\n const userId = nonRandomUUID(token)\n setLastSeenUserIdAfterAuth(userId)\n setLastSeenAuthMethod('partners_token')\n return {accessToken, userId}\n } catch (error) {\n throw new AbortError('The custom token provided is invalid.', 'Ensure the token is correct and not expired.')\n }\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n id_token?: string\n}\n\nfunction tokenRequestErrorHandler(error: string) {\n const invalidTargetErrorMessage =\n 'You are not authorized to use the CLI to develop in the provided store.' +\n '\\n\\n' +\n \"You can't use Shopify CLI with development stores if you only have Partner \" +\n 'staff member access. If you want to use Shopify CLI to work on a development store, then ' +\n 'you should be the store owner or create a staff account on the store.' +\n '\\n\\n' +\n \"If you're the store owner, then you need to log in to the store directly using the \" +\n 'store URL at least once before you log in using Shopify CLI.' +\n 'Logging in to the Shopify admin directly connects the development ' +\n 'store with your Shopify login.'\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n if (error === 'invalid_target') {\n return new InvalidTargetError(invalidTargetErrorMessage)\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult, existingUserId?: string): IdentityToken {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const userId = existingUserId ?? (result.id_token ? jose.decodeJwt(result.id_token).sub! : undefined)\n\n if (!userId) {\n throw new BugError('Error setting userId for session. No id_token or pre-existing user ID provided.')\n }\n\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n userId,\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {cacheRetrieveOrRepopulate, IntrospectionUrlKey} from '../conf-store.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {firstPartyDev} from '@shopify/cli-kit/node/context/local'\nimport {isSpin} from '@shopify/cli-kit/node/context/spin'\n\nexport async function validateIdentityToken(token: string): Promise<boolean> {\n if (isSpin() && firstPartyDev()) return true\n\n try {\n return withIntrospectionURL<boolean>(async (introspectionURL: string) => {\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`)\n\n const response = await shopifyFetch(introspectionURL, options)\n\n if (response.ok && response.headers.get('content-type')?.includes('json')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n outputDebug(`The identity token is valid: ${json.valid}`)\n return ok(json.valid)\n } else if (response.status === 404 || response.status > 500) {\n // If the status is 404 or 5xx, most likely the introspection endpoint\n // has changed. We should invalidate the cache and try again.\n return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`))\n } else {\n const text = await response.text()\n outputDebug(`The Introspection request failed with:\n - status: ${response.status}\n - www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}\n - body: ${JSON.stringify(text)}`)\n return ok(false)\n }\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function withIntrospectionURL<T>(fn: (introspectionUrl: string) => Promise<Result<T, AbortError>>): Promise<T> {\n const week = 7 * 24 * 60 * 60 * 1000\n const cacheKey: IntrospectionUrlKey = `identity-introspection-url-${await identityFqdn()}`\n let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week)\n let result: Result<T, AbortError> = await fn(introspectionURL)\n if (result.isErr()) {\n introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0)\n result = await fn(introspectionURL)\n }\n if (result.isErr()) {\n throw result.error\n } else {\n return result.value\n }\n}\n\nasync function getIntrospectionURL(): Promise<string> {\n const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n return json.introspection_endpoint\n}\n"]}
1
+ {"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {cacheRetrieveOrRepopulate, IntrospectionUrlKey} from '../conf-store.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {firstPartyDev} from '@shopify/cli-kit/node/context/local'\nimport {isSpin} from '@shopify/cli-kit/node/context/spin'\n\nexport async function validateIdentityToken(token: string): Promise<boolean> {\n if (isSpin() && firstPartyDev()) return true\n\n try {\n return withIntrospectionURL<boolean>(async (introspectionURL: string) => {\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`)\n\n const response = await shopifyFetch(introspectionURL, options)\n\n if (response.ok && response.headers.get('content-type')?.includes('json')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n outputDebug(`The identity token is valid: ${json.valid}`)\n return ok(json.valid)\n } else if (response.status === 404 || response.status > 500) {\n // If the status is 404 or 5xx, most likely the introspection endpoint\n // has changed. We should invalidate the cache and try again.\n return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`))\n } else {\n const text = await response.text()\n outputDebug(`The Introspection request failed with:\n - status: ${response.status}\n - www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}\n - body: ${JSON.stringify(text)}`)\n return ok(false)\n }\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function withIntrospectionURL<T>(fn: (introspectionUrl: string) => Promise<Result<T, AbortError>>): Promise<T> {\n const week = 7 * 24 * 60 * 60 * 1000\n const cacheKey: IntrospectionUrlKey = `identity-introspection-url-${await identityFqdn()}`\n let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week)\n let result: Result<T, AbortError> = await fn(introspectionURL)\n if (result.isErr()) {\n introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0)\n result = await fn(introspectionURL)\n }\n if (result.isErr()) {\n throw result.error\n } else {\n return result.value\n }\n}\n\nasync function getIntrospectionURL(): Promise<string> {\n const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n return json.introspection_endpoint\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,uBAAuB,CAAA;AAErE,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;IACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;QACrC,OAAO,sCAAsC,CAAA;KAC9C;SAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;QACjD,OAAO,sCAAsC,CAAA;KAC9C;SAAM;QACL,OAAO,sCAAsC,CAAA;KAC9C;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO,CAAC,CAAC;YACZ,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,UAAU,CAAC,CAAC;YACf,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,qBAAqB,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD,KAAK,mBAAmB,CAAC,CAAC;YACxB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD,KAAK,gBAAgB,CAAC,CAAC;YACrB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBAC1C,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD;YACE,MAAM,IAAI,QAAQ,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAA;KAC/D;AACH,CAAC","sourcesContent":["import {API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {Environment, serviceEnvironment} from '../context/service.js'\n\nexport function clientId(): string {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n } else if (environment === Environment.Production) {\n return 'fbdb2649-e327-4907-8f67-908d24cfd7e3'\n } else {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n }\n}\n\nexport function applicationId(api: API): string {\n switch (api) {\n case 'admin': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n } else if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n case 'partners': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n } else if (environment === Environment.Production) {\n return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6'\n } else {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n }\n }\n case 'storefront-renderer': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return '46f603de-894f-488d-9471-5b721280ff49'\n } else if (environment === Environment.Production) {\n return 'ee139b3d-5861-4d45-b387-1bc3ada7811c'\n } else {\n return '46f603de-894f-488d-9471-5b721280ff49'\n }\n }\n case 'business-platform': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n } else if (environment === Environment.Production) {\n return '32ff8ee5-82b8-4d93-9f8a-c6997cefb7dc'\n } else {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n }\n }\n case 'app-management': {\n const environment = serviceEnvironment()\n if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n default:\n throw new BugError(`Application id for API of type: ${api}`)\n }\n}\n"]}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,uBAAuB,CAAA;AAErE,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;IACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;QACtC,OAAO,sCAAsC,CAAA;IAC/C,CAAC;SAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;QAClD,OAAO,sCAAsC,CAAA;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,sCAAsC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtC,OAAO,kEAAkE,CAAA;YAC3E,CAAC;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,kEAAkE,CAAA;YAC3E,CAAC;iBAAM,CAAC;gBACN,OAAO,kEAAkE,CAAA;YAC3E,CAAC;QACH,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtC,OAAO,kEAAkE,CAAA;YAC3E,CAAC;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,kEAAkE,CAAA;YAC3E,CAAC;iBAAM,CAAC;gBACN,OAAO,kEAAkE,CAAA;YAC3E,CAAC;QACH,CAAC;QACD,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtC,OAAO,sCAAsC,CAAA;YAC/C,CAAC;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,sCAAsC,CAAA;YAC/C,CAAC;iBAAM,CAAC;gBACN,OAAO,sCAAsC,CAAA;YAC/C,CAAC;QACH,CAAC;QACD,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtC,OAAO,sCAAsC,CAAA;YAC/C,CAAC;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAClD,OAAO,sCAAsC,CAAA;YAC/C,CAAC;iBAAM,CAAC;gBACN,OAAO,sCAAsC,CAAA;YAC/C,CAAC;QACH,CAAC;QACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAC3C,OAAO,kEAAkE,CAAA;YAC3E,CAAC;iBAAM,CAAC;gBACN,OAAO,kEAAkE,CAAA;YAC3E,CAAC;QACH,CAAC;QACD;YACE,MAAM,IAAI,QAAQ,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAA;IAChE,CAAC;AACH,CAAC","sourcesContent":["import {API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {Environment, serviceEnvironment} from '../context/service.js'\n\nexport function clientId(): string {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n } else if (environment === Environment.Production) {\n return 'fbdb2649-e327-4907-8f67-908d24cfd7e3'\n } else {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n }\n}\n\nexport function applicationId(api: API): string {\n switch (api) {\n case 'admin': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n } else if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n case 'partners': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n } else if (environment === Environment.Production) {\n return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6'\n } else {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n }\n }\n case 'storefront-renderer': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return '46f603de-894f-488d-9471-5b721280ff49'\n } else if (environment === Environment.Production) {\n return 'ee139b3d-5861-4d45-b387-1bc3ada7811c'\n } else {\n return '46f603de-894f-488d-9471-5b721280ff49'\n }\n }\n case 'business-platform': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n } else if (environment === Environment.Production) {\n return '32ff8ee5-82b8-4d93-9f8a-c6997cefb7dc'\n } else {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n }\n }\n case 'app-management': {\n const environment = serviceEnvironment()\n if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n default:\n throw new BugError(`Application id for API of type: ${api}`)\n }\n}\n"]}
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { API } from '../api.js';
3
2
  /**
4
3
  * Generate a flat array with all the default scopes for all the APIs plus
@@ -6,7 +5,7 @@ import { API } from '../api.js';
6
5
  * @param extraScopes - custom user-defined scopes
7
6
  * @returns Array of scopes
8
7
  */
9
- export declare function allDefaultScopes(extraScopes?: string[], systemEnvironment?: NodeJS.ProcessEnv): string[];
8
+ export declare function allDefaultScopes(extraScopes?: string[]): string[];
10
9
  /**
11
10
  * Generate a flat array with the default scopes for the given API plus
12
11
  * any custom scope defined by the user
@@ -14,4 +13,4 @@ export declare function allDefaultScopes(extraScopes?: string[], systemEnvironme
14
13
  * @param extraScopes - custom user-defined scopes
15
14
  * @returns Array of scopes
16
15
  */
17
- export declare function apiScopes(api: API, extraScopes?: string[], systemEnvironment?: NodeJS.ProcessEnv): string[];
16
+ export declare function apiScopes(api: API, extraScopes?: string[]): string[];
@@ -1,14 +1,13 @@
1
1
  import { allAPIs } from '../api.js';
2
2
  import { BugError } from '../../../public/node/error.js';
3
- import { isAppManagementEnabled } from '../../../public/node/context/local.js';
4
3
  /**
5
4
  * Generate a flat array with all the default scopes for all the APIs plus
6
5
  * any custom scope defined by the user.
7
6
  * @param extraScopes - custom user-defined scopes
8
7
  * @returns Array of scopes
9
8
  */
10
- export function allDefaultScopes(extraScopes = [], systemEnvironment = process.env) {
11
- let scopes = allAPIs.map((api) => defaultApiScopes(api, systemEnvironment)).flat();
9
+ export function allDefaultScopes(extraScopes = []) {
10
+ let scopes = allAPIs.map((api) => defaultApiScopes(api)).flat();
12
11
  scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform);
13
12
  return Array.from(new Set(scopes));
14
13
  }
@@ -19,11 +18,11 @@ export function allDefaultScopes(extraScopes = [], systemEnvironment = process.e
19
18
  * @param extraScopes - custom user-defined scopes
20
19
  * @returns Array of scopes
21
20
  */
22
- export function apiScopes(api, extraScopes = [], systemEnvironment = process.env) {
23
- const scopes = [...defaultApiScopes(api, systemEnvironment), ...extraScopes.map(scopeTransform)].map(scopeTransform);
21
+ export function apiScopes(api, extraScopes = []) {
22
+ const scopes = [...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform);
24
23
  return Array.from(new Set(scopes));
25
24
  }
26
- function defaultApiScopes(api, systemEnvironment = process.env) {
25
+ function defaultApiScopes(api) {
27
26
  switch (api) {
28
27
  case 'admin':
29
28
  return ['graphql', 'themes', 'collaborator'];
@@ -32,9 +31,9 @@ function defaultApiScopes(api, systemEnvironment = process.env) {
32
31
  case 'partners':
33
32
  return ['cli'];
34
33
  case 'business-platform':
35
- return isAppManagementEnabled(systemEnvironment) ? ['destinations', 'store-management'] : ['destinations'];
34
+ return ['destinations', 'store-management'];
36
35
  case 'app-management':
37
- return isAppManagementEnabled(systemEnvironment) ? ['app-management'] : [];
36
+ return ['app-management'];
38
37
  default:
39
38
  throw new BugError(`Unknown API: ${api}`);
40
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../../src/private/node/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAM,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,sBAAsB,EAAC,MAAM,uCAAuC,CAAA;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwB,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IAC1F,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAClF,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,cAAwB,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IAC7F,MAAM,MAAM,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IACpH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IACjE,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO;YACV,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QAC9C,KAAK,qBAAqB;YACxB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,KAAK,UAAU;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,KAAK,mBAAmB;YACtB,OAAO,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAA;QAC5G,KAAK,gBAAgB;YACnB,OAAO,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC5E;YACE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;KAC5C;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,QAAQ,KAAK,EAAE;QACb,KAAK,SAAS;YACZ,OAAO,iDAAiD,CAAA;QAC1D,KAAK,QAAQ;YACX,OAAO,gDAAgD,CAAA;QACzD,KAAK,cAAc;YACjB,OAAO,2EAA2E,CAAA;QACpF,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAA;QAC/D,KAAK,UAAU;YACb,OAAO,gEAAgE,CAAA;QACzE,KAAK,cAAc;YACjB,OAAO,oDAAoD,CAAA;QAC7D,KAAK,kBAAkB;YACrB,OAAO,4DAA4D,CAAA;QACrE,KAAK,gBAAgB;YACnB,OAAO,uDAAuD,CAAA;QAChE;YACE,OAAO,KAAK,CAAA;KACf;AACH,CAAC","sourcesContent":["import {allAPIs, API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {isAppManagementEnabled} from '../../../public/node/context/local.js'\n\n/**\n * Generate a flat array with all the default scopes for all the APIs plus\n * any custom scope defined by the user.\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function allDefaultScopes(extraScopes: string[] = [], systemEnvironment = process.env): string[] {\n let scopes = allAPIs.map((api) => defaultApiScopes(api, systemEnvironment)).flat()\n scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\n/**\n * Generate a flat array with the default scopes for the given API plus\n * any custom scope defined by the user\n * @param api - API to get the scopes for\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function apiScopes(api: API, extraScopes: string[] = [], systemEnvironment = process.env): string[] {\n const scopes = [...defaultApiScopes(api, systemEnvironment), ...extraScopes.map(scopeTransform)].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\nfunction defaultApiScopes(api: API, systemEnvironment = process.env): string[] {\n switch (api) {\n case 'admin':\n return ['graphql', 'themes', 'collaborator']\n case 'storefront-renderer':\n return ['devtools']\n case 'partners':\n return ['cli']\n case 'business-platform':\n return isAppManagementEnabled(systemEnvironment) ? ['destinations', 'store-management'] : ['destinations']\n case 'app-management':\n return isAppManagementEnabled(systemEnvironment) ? ['app-management'] : []\n default:\n throw new BugError(`Unknown API: ${api}`)\n }\n}\n\nfunction scopeTransform(scope: string): string {\n switch (scope) {\n case 'graphql':\n return 'https://api.shopify.com/auth/shop.admin.graphql'\n case 'themes':\n return 'https://api.shopify.com/auth/shop.admin.themes'\n case 'collaborator':\n return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly'\n case 'cli':\n return 'https://api.shopify.com/auth/partners.app.cli.access'\n case 'devtools':\n return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools'\n case 'destinations':\n return 'https://api.shopify.com/auth/destinations.readonly'\n case 'store-management':\n return 'https://api.shopify.com/auth/organization.store-management'\n case 'app-management':\n return 'https://api.shopify.com/auth/organization.apps.manage'\n default:\n return scope\n }\n}\n"]}
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../../src/private/node/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAM,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwB,EAAE;IACzD,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC/D,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,cAAwB,EAAE;IAC5D,MAAM,MAAM,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IACjG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ;IAChC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QAC9C,KAAK,qBAAqB;YACxB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,KAAK,UAAU;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,KAAK,mBAAmB;YACtB,OAAO,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;QAC7C,KAAK,gBAAgB;YACnB,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC3B;YACE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,iDAAiD,CAAA;QAC1D,KAAK,QAAQ;YACX,OAAO,gDAAgD,CAAA;QACzD,KAAK,cAAc;YACjB,OAAO,2EAA2E,CAAA;QACpF,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAA;QAC/D,KAAK,UAAU;YACb,OAAO,gEAAgE,CAAA;QACzE,KAAK,cAAc;YACjB,OAAO,oDAAoD,CAAA;QAC7D,KAAK,kBAAkB;YACrB,OAAO,4DAA4D,CAAA;QACrE,KAAK,gBAAgB;YACnB,OAAO,uDAAuD,CAAA;QAChE;YACE,OAAO,KAAK,CAAA;IAChB,CAAC;AACH,CAAC","sourcesContent":["import {allAPIs, API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\n\n/**\n * Generate a flat array with all the default scopes for all the APIs plus\n * any custom scope defined by the user.\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function allDefaultScopes(extraScopes: string[] = []): string[] {\n let scopes = allAPIs.map((api) => defaultApiScopes(api)).flat()\n scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\n/**\n * Generate a flat array with the default scopes for the given API plus\n * any custom scope defined by the user\n * @param api - API to get the scopes for\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function apiScopes(api: API, extraScopes: string[] = []): string[] {\n const scopes = [...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\nfunction defaultApiScopes(api: API): string[] {\n switch (api) {\n case 'admin':\n return ['graphql', 'themes', 'collaborator']\n case 'storefront-renderer':\n return ['devtools']\n case 'partners':\n return ['cli']\n case 'business-platform':\n return ['destinations', 'store-management']\n case 'app-management':\n return ['app-management']\n default:\n throw new BugError(`Unknown API: ${api}`)\n }\n}\n\nfunction scopeTransform(scope: string): string {\n switch (scope) {\n case 'graphql':\n return 'https://api.shopify.com/auth/shop.admin.graphql'\n case 'themes':\n return 'https://api.shopify.com/auth/shop.admin.themes'\n case 'collaborator':\n return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly'\n case 'cli':\n return 'https://api.shopify.com/auth/partners.app.cli.access'\n case 'devtools':\n return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools'\n case 'destinations':\n return 'https://api.shopify.com/auth/destinations.readonly'\n case 'store-management':\n return 'https://api.shopify.com/auth/organization.store-management'\n case 'app-management':\n return 'https://api.shopify.com/auth/organization.apps.manage'\n default:\n return scope\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/private/node/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAGtE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAgB;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3C,UAAU,CAAC,WAAW,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAE5B,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,SAAS,CAAA;KACjB;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IACrE,IAAI,aAAa,CAAC,OAAO,EAAE;QACzB,OAAO,aAAa,CAAC,IAAI,CAAA;KAC1B;SAAM;QACL,MAAM,MAAM,EAAE,CAAA;QACd,OAAO,SAAS,CAAA;KACjB;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,aAAa,EAAE,CAAA;AACjB,CAAC","sourcesContent":["import {SessionSchema} from './schema.js'\nimport {getSession, removeSession, setSession} from '../conf-store.js'\nimport type {Session} from './schema.js'\n\n/**\n * Serializes the session as a JSON and stores it securely in the system.\n * If the secure store is not available, the session is stored in the local config.\n * @param session - the session to store.\n */\nexport async function store(session: Session) {\n const jsonSession = JSON.stringify(session)\n setSession(jsonSession)\n}\n\n/**\n * Fetches the session from the secure store and returns it.\n * If the secure store is not available, the session is fetched from the local config.\n * If the format of the session is invalid, the method will discard it.\n * In the future might add some logic for supporting migrating the schema\n * of already-persisted sessions.\n * @returns Returns a promise that resolves with the session if it exists and is valid.\n */\nexport async function fetch(): Promise<Session | undefined> {\n const content = getSession()\n\n if (!content) {\n return undefined\n }\n const contentJson = JSON.parse(content)\n const parsedSession = await SessionSchema.safeParseAsync(contentJson)\n if (parsedSession.success) {\n return parsedSession.data\n } else {\n await remove()\n return undefined\n }\n}\n\n/**\n * Removes a session from the system.\n */\nexport async function remove() {\n removeSession()\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/private/node/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAGtE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAgB;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3C,UAAU,CAAC,WAAW,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAE5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IACrE,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,OAAO,aAAa,CAAC,IAAI,CAAA;IAC3B,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,EAAE,CAAA;QACd,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,aAAa,EAAE,CAAA;AACjB,CAAC","sourcesContent":["import {SessionSchema} from './schema.js'\nimport {getSession, removeSession, setSession} from '../conf-store.js'\nimport type {Session} from './schema.js'\n\n/**\n * Serializes the session as a JSON and stores it securely in the system.\n * If the secure store is not available, the session is stored in the local config.\n * @param session - the session to store.\n */\nexport async function store(session: Session) {\n const jsonSession = JSON.stringify(session)\n setSession(jsonSession)\n}\n\n/**\n * Fetches the session from the secure store and returns it.\n * If the secure store is not available, the session is fetched from the local config.\n * If the format of the session is invalid, the method will discard it.\n * In the future might add some logic for supporting migrating the schema\n * of already-persisted sessions.\n * @returns Returns a promise that resolves with the session if it exists and is valid.\n */\nexport async function fetch(): Promise<Session | undefined> {\n const content = getSession()\n\n if (!content) {\n return undefined\n }\n const contentJson = JSON.parse(content)\n const parsedSession = await SessionSchema.safeParseAsync(contentJson)\n if (parsedSession.success) {\n return parsedSession.data\n } else {\n await remove()\n return undefined\n }\n}\n\n/**\n * Removes a session from the system.\n */\nexport async function remove() {\n removeSession()\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken, validateCachedIdentityTokenStructure} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate\n * @param scopes - requested scopes to validate\n * @param applications - requested applications\n * @param session - current session with identity and application tokens\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(\n scopes: string[],\n applications: OAuthApplications,\n session: {\n identity: IdentityToken\n applications: {[x: string]: ApplicationToken}\n },\n): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n if (!scopesAreValid) return 'needs_full_auth'\n let tokensAreExpired = isTokenExpired(session.identity)\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.appManagementApi) {\n const appId = applicationId('app-management')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.applications[realAppId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n outputDebug(`\nThe validation of the token for application/identity completed with the following results:\n- It's expired: ${tokensAreExpired}\n- It's invalid in identity: ${!identityIsValid}\n `)\n\n if (!validateCachedIdentityTokenStructure(session.identity)) {\n return 'needs_full_auth'\n }\n\n if (tokensAreExpired) return 'needs_refresh'\n if (!identityIsValid) return 'needs_full_auth'\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken, validateCachedIdentityTokenStructure} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate\n * @param scopes - requested scopes to validate\n * @param applications - requested applications\n * @param session - current session with identity and application tokens\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(\n scopes: string[],\n applications: OAuthApplications,\n session: {\n identity: IdentityToken\n applications: {[x: string]: ApplicationToken}\n },\n): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n if (!scopesAreValid) return 'needs_full_auth'\n let tokensAreExpired = isTokenExpired(session.identity)\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.appManagementApi) {\n const appId = applicationId('app-management')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.applications[realAppId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n outputDebug(`\nThe validation of the token for application/identity completed with the following results:\n- It's expired: ${tokensAreExpired}\n- It's invalid in identity: ${!identityIsValid}\n `)\n\n if (!validateCachedIdentityTokenStructure(session.identity)) {\n return 'needs_full_auth'\n }\n\n if (tokensAreExpired) return 'needs_refresh'\n if (!identityIsValid) return 'needs_full_auth'\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { AdminSession } from '@shopify/cli-kit/node/session';
3
2
  /**
4
3
  * A scope supported by the Shopify Admin API.
@@ -4,19 +4,13 @@ import { allDefaultScopes, apiScopes } from './session/scopes.js';
4
4
  import { exchangeAccessForApplicationTokens, exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError, InvalidRequestError, } from './session/exchange.js';
5
5
  import * as secureStore from './session/store.js';
6
6
  import { pollForDeviceAuthorization, requestDeviceAuthorization } from './session/device-authorization.js';
7
- import { RequestClientError } from './api/headers.js';
8
- import { getCachedPartnerAccountStatus, setCachedPartnerAccountStatus } from './conf-store.js';
9
7
  import { isThemeAccessSession } from './api/rest.js';
10
8
  import { outputContent, outputToken, outputDebug } from '../../public/node/output.js';
11
- import { firstPartyDev, isAppManagementEnabled, themeToken } from '../../public/node/context/local.js';
9
+ import { firstPartyDev, themeToken } from '../../public/node/context/local.js';
12
10
  import { AbortError, BugError } from '../../public/node/error.js';
13
- import { partnersRequest } from '../../public/node/api/partners.js';
14
- import { normalizeStoreFqdn, partnersFqdn, identityFqdn } from '../../public/node/context/fqdn.js';
15
- import { openURL } from '../../public/node/system.js';
16
- import { keypress } from '../../public/node/ui.js';
11
+ import { normalizeStoreFqdn, identityFqdn } from '../../public/node/context/fqdn.js';
17
12
  import { getIdentityTokenInformation, getPartnersToken } from '../../public/node/environment.js';
18
- import { gql } from 'graphql-request';
19
- import { outputCompleted, outputInfo, outputWarn } from '@shopify/cli-kit/node/output';
13
+ import { outputCompleted } from '@shopify/cli-kit/node/output';
20
14
  import { isSpin } from '@shopify/cli-kit/node/context/spin';
21
15
  import { nonRandomUUID } from '@shopify/cli-kit/node/crypto';
22
16
  let userId;
@@ -148,9 +142,6 @@ The CLI is currently unable to prompt for reauthentication.`, 'Restart the CLI p
148
142
  if (envToken && applications.partnersApi) {
149
143
  tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken;
150
144
  }
151
- if (!envToken && tokens.partners) {
152
- await ensureUserHasPartnerAccount(tokens.partners, tokens.userId);
153
- }
154
145
  setLastSeenAuthMethod(envToken ? 'partners_token' : 'device_auth');
155
146
  setLastSeenUserIdAfterAuth(tokens.userId);
156
147
  return tokens;
@@ -194,68 +185,6 @@ async function executeCompleteFlow(applications, identityFqdn) {
194
185
  outputCompleted('Logged in.');
195
186
  return session;
196
187
  }
197
- /**
198
- * If the user creates an account from the Identity website, the created
199
- * account won't get a Partner organization created. We need to detect that
200
- * and take the user to create a partner organization.
201
- *
202
- * @param partnersToken - Partners token.
203
- */
204
- async function ensureUserHasPartnerAccount(partnersToken, userId) {
205
- if (isAppManagementEnabled())
206
- return;
207
- outputDebug(outputContent `Verifying that the user has a Partner organization`);
208
- if (!(await hasPartnerAccount(partnersToken, userId))) {
209
- outputInfo(`\nA Shopify Partners organization is needed to proceed.`);
210
- outputInfo(`👉 Press any key to create one`);
211
- await keypress();
212
- await openURL(`https://${await partnersFqdn()}/signup`);
213
- outputInfo(outputContent `👉 Press any key when you have ${outputToken.cyan('created the organization')}`);
214
- outputWarn(outputContent `Make sure you've confirmed your Shopify and the Partner organization from the email`);
215
- await keypress();
216
- if (!(await hasPartnerAccount(partnersToken, userId))) {
217
- throw new AbortError(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
218
- }
219
- }
220
- }
221
- // eslint-disable-next-line @shopify/cli/no-inline-graphql
222
- const getFirstOrganization = gql `
223
- {
224
- organizations(first: 1) {
225
- nodes {
226
- id
227
- }
228
- }
229
- }
230
- `;
231
- /**
232
- * Validate if the current token is valid for partners API.
233
- *
234
- * @param partnersToken - Partners token.
235
- * @returns A promise that resolves to true if the token is valid for partners API.
236
- */
237
- async function hasPartnerAccount(partnersToken, userId) {
238
- const cacheKey = userId ?? partnersToken;
239
- const cachedStatus = getCachedPartnerAccountStatus(cacheKey);
240
- if (cachedStatus) {
241
- outputDebug(`Confirmed partner account exists from cache`);
242
- return true;
243
- }
244
- try {
245
- await partnersRequest(getFirstOrganization, partnersToken);
246
- setCachedPartnerAccountStatus(cacheKey);
247
- return true;
248
- // eslint-disable-next-line no-catch-all/no-catch-all
249
- }
250
- catch (error) {
251
- if (error instanceof RequestClientError && error.statusCode === 404) {
252
- return false;
253
- }
254
- else {
255
- return true;
256
- }
257
- }
258
- }
259
188
  /**
260
189
  * Refresh the tokens for a given session.
261
190
  *