@shopify/cli-kit 3.16.2 → 3.17.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 (156) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/dist/analytics.d.ts +5 -5
  4. package/dist/analytics.js +5 -5
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/api/common.d.ts +2 -2
  7. package/dist/api/common.js +2 -2
  8. package/dist/api/common.js.map +1 -1
  9. package/dist/api/graphql/functions/app_function_set.js +0 -7
  10. package/dist/api/graphql/functions/app_function_set.js.map +1 -1
  11. package/dist/api/graphql/index.d.ts +0 -2
  12. package/dist/api/graphql/index.js +0 -2
  13. package/dist/api/graphql/index.js.map +1 -1
  14. package/dist/api/oxygen.d.ts +5 -0
  15. package/dist/api/oxygen.js +30 -0
  16. package/dist/api/oxygen.js.map +1 -0
  17. package/dist/api/partners.d.ts +7 -7
  18. package/dist/api/partners.js +7 -7
  19. package/dist/api/partners.js.map +1 -1
  20. package/dist/api.d.ts +2 -2
  21. package/dist/api.js +2 -2
  22. package/dist/api.js.map +1 -1
  23. package/dist/common/object.d.ts +3 -3
  24. package/dist/common/object.js +3 -3
  25. package/dist/common/object.js.map +1 -1
  26. package/dist/environment/fqdn.d.ts +3 -3
  27. package/dist/environment/fqdn.js +3 -3
  28. package/dist/environment/fqdn.js.map +1 -1
  29. package/dist/environment/local.d.ts +13 -13
  30. package/dist/environment/local.js +16 -16
  31. package/dist/environment/local.js.map +1 -1
  32. package/dist/environment/spin.d.ts +12 -12
  33. package/dist/environment/spin.js +12 -12
  34. package/dist/environment/spin.js.map +1 -1
  35. package/dist/environment/utilities.d.ts +0 -2
  36. package/dist/environment/utilities.js +0 -2
  37. package/dist/environment/utilities.js.map +1 -1
  38. package/dist/error.d.ts +1 -1
  39. package/dist/error.js +1 -1
  40. package/dist/error.js.map +1 -1
  41. package/dist/file.d.ts +17 -18
  42. package/dist/file.js +17 -18
  43. package/dist/file.js.map +1 -1
  44. package/dist/git.d.ts +1 -1
  45. package/dist/git.js +2 -2
  46. package/dist/git.js.map +1 -1
  47. package/dist/http/fetch.d.ts +2 -2
  48. package/dist/http/fetch.js +2 -2
  49. package/dist/http/fetch.js.map +1 -1
  50. package/dist/http.d.ts +1 -1
  51. package/dist/http.js +1 -1
  52. package/dist/http.js.map +1 -1
  53. package/dist/id.d.ts +1 -1
  54. package/dist/id.js +1 -1
  55. package/dist/id.js.map +1 -1
  56. package/dist/network/service.d.ts +0 -2
  57. package/dist/network/service.js +0 -1
  58. package/dist/network/service.js.map +1 -1
  59. package/dist/node/archiver.d.ts +2 -2
  60. package/dist/node/archiver.js +2 -2
  61. package/dist/node/archiver.js.map +1 -1
  62. package/dist/node/checksum.d.ts +2 -2
  63. package/dist/node/checksum.js +2 -2
  64. package/dist/node/checksum.js.map +1 -1
  65. package/dist/node/cli.d.ts +1 -2
  66. package/dist/node/cli.js +1 -7
  67. package/dist/node/cli.js.map +1 -1
  68. package/dist/node/dot-env.d.ts +7 -7
  69. package/dist/node/dot-env.js +7 -7
  70. package/dist/node/dot-env.js.map +1 -1
  71. package/dist/node/framework.d.ts +2 -2
  72. package/dist/node/framework.js +2 -2
  73. package/dist/node/framework.js.map +1 -1
  74. package/dist/node/hooks/prerun.js +6 -6
  75. package/dist/node/hooks/prerun.js.map +1 -1
  76. package/dist/node/node-package-manager.d.ts +32 -28
  77. package/dist/node/node-package-manager.js +29 -29
  78. package/dist/node/node-package-manager.js.map +1 -1
  79. package/dist/node/ruby.d.ts +4 -4
  80. package/dist/node/ruby.js +5 -5
  81. package/dist/node/ruby.js.map +1 -1
  82. package/dist/os.d.ts +1 -1
  83. package/dist/os.js +1 -1
  84. package/dist/os.js.map +1 -1
  85. package/dist/output.d.ts +18 -20
  86. package/dist/output.js +23 -25
  87. package/dist/output.js.map +1 -1
  88. package/dist/path.d.ts +4 -4
  89. package/dist/path.js +4 -4
  90. package/dist/path.js.map +1 -1
  91. package/dist/plugins.d.ts +4 -4
  92. package/dist/plugins.js +4 -4
  93. package/dist/plugins.js.map +1 -1
  94. package/dist/port.d.ts +1 -1
  95. package/dist/port.js +1 -1
  96. package/dist/port.js.map +1 -1
  97. package/dist/public/common/array.d.ts +4 -4
  98. package/dist/public/common/array.js +4 -4
  99. package/dist/public/common/array.js.map +1 -1
  100. package/dist/secure-store.d.ts +4 -4
  101. package/dist/secure-store.js +4 -4
  102. package/dist/secure-store.js.map +1 -1
  103. package/dist/session/device-authorization.d.ts +5 -5
  104. package/dist/session/device-authorization.js +5 -5
  105. package/dist/session/device-authorization.js.map +1 -1
  106. package/dist/session/exchange.d.ts +10 -16
  107. package/dist/session/exchange.js +10 -16
  108. package/dist/session/exchange.js.map +1 -1
  109. package/dist/session/post-auth.js +2 -2
  110. package/dist/session/post-auth.js.map +1 -1
  111. package/dist/session/redirect-listener.js +1 -1
  112. package/dist/session/redirect-listener.js.map +1 -1
  113. package/dist/session/schema.d.ts +3 -2
  114. package/dist/session/schema.js +3 -2
  115. package/dist/session/schema.js.map +1 -1
  116. package/dist/session/scopes.d.ts +3 -3
  117. package/dist/session/scopes.js +3 -3
  118. package/dist/session/scopes.js.map +1 -1
  119. package/dist/session/store.d.ts +2 -2
  120. package/dist/session/store.js +2 -2
  121. package/dist/session/store.js.map +1 -1
  122. package/dist/session/token.d.ts +1 -1
  123. package/dist/session/token.js +1 -1
  124. package/dist/session/token.js.map +1 -1
  125. package/dist/session/validate.d.ts +4 -4
  126. package/dist/session/validate.js +4 -7
  127. package/dist/session/validate.js.map +1 -1
  128. package/dist/session.d.ts +10 -10
  129. package/dist/session.js +10 -10
  130. package/dist/session.js.map +1 -1
  131. package/dist/string.d.ts +2 -2
  132. package/dist/string.js +2 -2
  133. package/dist/string.js.map +1 -1
  134. package/dist/system.d.ts +4 -4
  135. package/dist/system.js +4 -4
  136. package/dist/system.js.map +1 -1
  137. package/dist/template.d.ts +3 -3
  138. package/dist/template.js +3 -3
  139. package/dist/template.js.map +1 -1
  140. package/dist/testing/store.d.ts +2 -2
  141. package/dist/testing/store.js +2 -2
  142. package/dist/testing/store.js.map +1 -1
  143. package/dist/tsconfig.tsbuildinfo +1 -1
  144. package/dist/ui.d.ts +1 -1
  145. package/dist/ui.js +17 -8
  146. package/dist/ui.js.map +1 -1
  147. package/dist/version.d.ts +3 -3
  148. package/dist/version.js +3 -3
  149. package/dist/version.js.map +1 -1
  150. package/package.json +1 -1
  151. package/dist/api/graphql/functions/compile_module.d.ts +0 -15
  152. package/dist/api/graphql/functions/compile_module.js +0 -13
  153. package/dist/api/graphql/functions/compile_module.js.map +0 -1
  154. package/dist/api/graphql/functions/module_compilation_status.d.ts +0 -15
  155. package/dist/api/graphql/functions/module_compilation_status.js +0 -13
  156. package/dist/api/graphql/functions/module_compilation_status.js.map +0 -1
package/dist/plugins.js CHANGED
@@ -13,7 +13,7 @@ export async function fanoutHooks(config, event, options, timeout) {
13
13
  * Execute the 'tunnel_provider' hook, and return the list of available tunnel providers.
14
14
  * Fail if there are multiple plugins for the same provider
15
15
  *
16
- * @param config oclif config used to execute hooks
16
+ * @param config - oclif config used to execute hooks
17
17
  * @returns list of available tunnel plugins
18
18
  */
19
19
  export async function getListOfTunnelPlugins(config) {
@@ -27,9 +27,9 @@ export async function getListOfTunnelPlugins(config) {
27
27
  * Execute the 'tunnel_start' hook for the given provider.
28
28
  * Fails if there aren't plugins for that provider or if there are more than one.
29
29
  *
30
- * @param config oclif config used to execute hooks
31
- * @param port port where the tunnel will be started
32
- * @param provider selected provider, must be unique
30
+ * @param config - oclif config used to execute hooks
31
+ * @param port - port where the tunnel will be started
32
+ * @param provider - selected provider, must be unique
33
33
  * @returns tunnel URL from the selected provider
34
34
  */
35
35
  export async function runTunnelPlugin(config, port, provider) {
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,0BAA0B,EAAE,0BAA0B,EAAC,MAAM,0BAA0B,CAAA;AAG/F;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAyB,EACzB,KAAa,EACb,OAA4C,EAC5C,OAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACzD,8DAA8D;IAC9D,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAQ,CAAA;AAClG,CAAC;AA4CD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAc;IACzD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAA;IAC9D,MAAM,KAAK,GAAG,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;IACtF,IAAI,0BAA0B,CAAC,KAAK,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAC,CAAA;IACtG,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,CAAA;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,IAAY,EACZ,QAAgB;IAEhB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAA;IACzE,MAAM,IAAI,GAAG,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IACpF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAC,KAAK,EAAE,eAAe,EAAC,CAAA;IACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAC,KAAK,EAAE,SAAS,EAAC,CAAA;IAChD,OAAO,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAC,CAAA;AACvB,CAAC","sourcesContent":["import {JsonMap} from './json.js'\nimport {PickByPrefix} from './typing/pick-by-prefix.js'\nimport {MonorailEventPublic, MonorailEventSensitive} from './monorail.js'\nimport {HookReturnPerTunnelPlugin} from './plugins/tunnel.js'\nimport {getArrayContainsDuplicates, getArrayRejectingUndefined} from './public/common/array.js'\nimport {Config, Interfaces} from '@oclif/core'\n\n/**\n * Convenience function to trigger a hook, and gather any successful responses. Failures are ignored.\n *\n * Responses are organised into a dictionary, keyed by plug-in name. Only plug-ins that have hooks registered for the given event, and the hooks were run successfully, are included.\n */\nexport async function fanoutHooks<TPluginMap extends HookReturnsPerPlugin, TEvent extends string & keyof TPluginMap>(\n config: Interfaces.Config,\n event: TEvent,\n options: TPluginMap[typeof event]['options'],\n timeout?: number,\n): Promise<Partial<TPluginMap[typeof event]['pluginReturns']>> {\n const res = await config.runHook(event, options, timeout)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return Object.fromEntries(res.successes.map(({result, plugin}) => [plugin.name, result])) as any\n}\n\ntype AppSpecificMonorailFields = PickByPrefix<MonorailEventPublic, 'app_', 'project_type' | 'api_key' | 'partner_id'> &\n PickByPrefix<MonorailEventPublic, 'cmd_extensions_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_scaffold_'>\n\ntype AppSpecificSensitiveMonorailFields = PickByPrefix<MonorailEventSensitive, 'app_'>\n\ninterface HookReturnsPerPlugin extends HookReturnPerTunnelPlugin {\n public_command_metadata: {\n options: {[key: string]: never}\n pluginReturns: {\n '@shopify/app': Partial<AppSpecificMonorailFields>\n [pluginName: string]: JsonMap\n }\n }\n sensitive_command_metadata: {\n options: {[key: string]: never}\n pluginReturns: {\n '@shopify/app': Partial<AppSpecificSensitiveMonorailFields>\n [pluginName: string]: JsonMap\n }\n }\n [hookName: string]: {\n options: {[key: string]: unknown}\n pluginReturns: {[key: string]: JsonMap}\n }\n}\n\nexport type PluginReturnsForHook<\n TEvent extends keyof TPluginMap,\n TPluginName extends keyof TPluginMap[TEvent]['pluginReturns'],\n TPluginMap extends HookReturnsPerPlugin = HookReturnsPerPlugin,\n> = TPluginMap[TEvent]['pluginReturns'][TPluginName]\n\nexport type FanoutHookFunction<\n TEvent extends keyof TPluginMap = string,\n TPluginName extends keyof TPluginMap[TEvent]['pluginReturns'] = string,\n TPluginMap extends HookReturnsPerPlugin = HookReturnsPerPlugin,\n> = (\n this: Interfaces.Hook.Context,\n options: TPluginMap[TEvent]['options'] & {config: Interfaces.Config},\n) => Promise<PluginReturnsForHook<TEvent, TPluginName, TPluginMap>>\n\n/**\n * Execute the 'tunnel_provider' hook, and return the list of available tunnel providers.\n * Fail if there are multiple plugins for the same provider\n *\n * @param config oclif config used to execute hooks\n * @returns list of available tunnel plugins\n */\nexport async function getListOfTunnelPlugins(config: Config): Promise<{plugins: string[]; error?: string}> {\n const hooks = await fanoutHooks(config, 'tunnel_provider', {})\n const names = getArrayRejectingUndefined(Object.values(hooks).map((key) => key?.name))\n if (getArrayContainsDuplicates(names)) return {plugins: names, error: 'multiple-plugins-for-provider'}\n return {plugins: names}\n}\n\n/**\n * Execute the 'tunnel_start' hook for the given provider.\n * Fails if there aren't plugins for that provider or if there are more than one.\n *\n * @param config oclif config used to execute hooks\n * @param port port where the tunnel will be started\n * @param provider selected provider, must be unique\n * @returns tunnel URL from the selected provider\n */\nexport async function runTunnelPlugin(\n config: Config,\n port: number,\n provider: string,\n): Promise<{url?: string; error?: string}> {\n const hooks = await fanoutHooks(config, 'tunnel_start', {port, provider})\n const urls = getArrayRejectingUndefined(Object.values(hooks).map((key) => key?.url))\n if (urls.length > 1) return {error: 'multiple-urls'}\n if (urls.length === 0) return {error: 'no-urls'}\n return {url: urls[0]}\n}\n"]}
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,0BAA0B,EAAE,0BAA0B,EAAC,MAAM,0BAA0B,CAAA;AAG/F;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAyB,EACzB,KAAa,EACb,OAA4C,EAC5C,OAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACzD,8DAA8D;IAC9D,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAQ,CAAA;AAClG,CAAC;AA4CD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAc;IACzD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAA;IAC9D,MAAM,KAAK,GAAG,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;IACtF,IAAI,0BAA0B,CAAC,KAAK,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAC,CAAA;IACtG,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,CAAA;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,IAAY,EACZ,QAAgB;IAEhB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAA;IACzE,MAAM,IAAI,GAAG,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IACpF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAC,KAAK,EAAE,eAAe,EAAC,CAAA;IACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAC,KAAK,EAAE,SAAS,EAAC,CAAA;IAChD,OAAO,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAC,CAAA;AACvB,CAAC","sourcesContent":["import {JsonMap} from './json.js'\nimport {PickByPrefix} from './typing/pick-by-prefix.js'\nimport {MonorailEventPublic, MonorailEventSensitive} from './monorail.js'\nimport {HookReturnPerTunnelPlugin} from './plugins/tunnel.js'\nimport {getArrayContainsDuplicates, getArrayRejectingUndefined} from './public/common/array.js'\nimport {Config, Interfaces} from '@oclif/core'\n\n/**\n * Convenience function to trigger a hook, and gather any successful responses. Failures are ignored.\n *\n * Responses are organised into a dictionary, keyed by plug-in name. Only plug-ins that have hooks registered for the given event, and the hooks were run successfully, are included.\n */\nexport async function fanoutHooks<TPluginMap extends HookReturnsPerPlugin, TEvent extends string & keyof TPluginMap>(\n config: Interfaces.Config,\n event: TEvent,\n options: TPluginMap[typeof event]['options'],\n timeout?: number,\n): Promise<Partial<TPluginMap[typeof event]['pluginReturns']>> {\n const res = await config.runHook(event, options, timeout)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return Object.fromEntries(res.successes.map(({result, plugin}) => [plugin.name, result])) as any\n}\n\ntype AppSpecificMonorailFields = PickByPrefix<MonorailEventPublic, 'app_', 'project_type' | 'api_key' | 'partner_id'> &\n PickByPrefix<MonorailEventPublic, 'cmd_extensions_'> &\n PickByPrefix<MonorailEventPublic, 'cmd_scaffold_'>\n\ntype AppSpecificSensitiveMonorailFields = PickByPrefix<MonorailEventSensitive, 'app_'>\n\ninterface HookReturnsPerPlugin extends HookReturnPerTunnelPlugin {\n public_command_metadata: {\n options: {[key: string]: never}\n pluginReturns: {\n '@shopify/app': Partial<AppSpecificMonorailFields>\n [pluginName: string]: JsonMap\n }\n }\n sensitive_command_metadata: {\n options: {[key: string]: never}\n pluginReturns: {\n '@shopify/app': Partial<AppSpecificSensitiveMonorailFields>\n [pluginName: string]: JsonMap\n }\n }\n [hookName: string]: {\n options: {[key: string]: unknown}\n pluginReturns: {[key: string]: JsonMap}\n }\n}\n\nexport type PluginReturnsForHook<\n TEvent extends keyof TPluginMap,\n TPluginName extends keyof TPluginMap[TEvent]['pluginReturns'],\n TPluginMap extends HookReturnsPerPlugin = HookReturnsPerPlugin,\n> = TPluginMap[TEvent]['pluginReturns'][TPluginName]\n\nexport type FanoutHookFunction<\n TEvent extends keyof TPluginMap = string,\n TPluginName extends keyof TPluginMap[TEvent]['pluginReturns'] = string,\n TPluginMap extends HookReturnsPerPlugin = HookReturnsPerPlugin,\n> = (\n this: Interfaces.Hook.Context,\n options: TPluginMap[TEvent]['options'] & {config: Interfaces.Config},\n) => Promise<PluginReturnsForHook<TEvent, TPluginName, TPluginMap>>\n\n/**\n * Execute the 'tunnel_provider' hook, and return the list of available tunnel providers.\n * Fail if there are multiple plugins for the same provider\n *\n * @param config - oclif config used to execute hooks\n * @returns list of available tunnel plugins\n */\nexport async function getListOfTunnelPlugins(config: Config): Promise<{plugins: string[]; error?: string}> {\n const hooks = await fanoutHooks(config, 'tunnel_provider', {})\n const names = getArrayRejectingUndefined(Object.values(hooks).map((key) => key?.name))\n if (getArrayContainsDuplicates(names)) return {plugins: names, error: 'multiple-plugins-for-provider'}\n return {plugins: names}\n}\n\n/**\n * Execute the 'tunnel_start' hook for the given provider.\n * Fails if there aren't plugins for that provider or if there are more than one.\n *\n * @param config - oclif config used to execute hooks\n * @param port - port where the tunnel will be started\n * @param provider - selected provider, must be unique\n * @returns tunnel URL from the selected provider\n */\nexport async function runTunnelPlugin(\n config: Config,\n port: number,\n provider: string,\n): Promise<{url?: string; error?: string}> {\n const hooks = await fanoutHooks(config, 'tunnel_start', {port, provider})\n const urls = getArrayRejectingUndefined(Object.values(hooks).map((key) => key?.url))\n if (urls.length > 1) return {error: 'multiple-urls'}\n if (urls.length === 0) return {error: 'no-urls'}\n return {url: urls[0]}\n}\n"]}
package/dist/port.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Returns an available port in the current environment.
3
- * @returns {Promise<number>} A promise that resolves with an availabe port.
3
+ * @returns A promise that resolves with an availabe port.
4
4
  */
5
5
  export declare function getRandomPort(): Promise<number>;
package/dist/port.js CHANGED
@@ -4,7 +4,7 @@ import { sleep } from './system.js';
4
4
  import * as port from 'get-port-please';
5
5
  /**
6
6
  * Returns an available port in the current environment.
7
- * @returns {Promise<number>} A promise that resolves with an availabe port.
7
+ * @returns A promise that resolves with an availabe port.
8
8
  */
9
9
  export async function getRandomPort() {
10
10
  debug(content `Getting a random port...`);
package/dist/port.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"port.js","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AACjD,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAChC,OAAO,EAAC,KAAK,EAAC,MAAM,aAAa,CAAA;AACjC,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,KAAK,CAAC,OAAO,CAAA,0BAA0B,CAAC,CAAA;IACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;IACjE,KAAK,CAAC,OAAO,CAAA,yBAAyB,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,CAAA;IACnE,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,KAAK,UAAU,YAAY,CAAI,OAAgB,EAAE,QAAQ,GAAG,CAAC,EAAE,iBAAiB,GAAG,CAAC;IAClF,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,OAAO,IAAI,EAAE;QACX,IAAI;YACF,4CAA4C;YAC5C,OAAO,MAAM,OAAO,EAAE,CAAA;YACtB,8DAA8D;SAC/D;QAAC,OAAO,KAAU,EAAE;YACnB,IAAI,UAAU,EAAE,GAAG,QAAQ,EAAE;gBAC3B,KAAK,CAAC,OAAO,CAAA,0CAA0C,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;gBACvE,4CAA4C;gBAC5C,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAA;aAC/B;iBAAM;gBACL,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;aAC/B;SACF;KACF;AACH,CAAC","sourcesContent":["import {debug, content, token} from './output.js'\nimport {Abort} from './error.js'\nimport {sleep} from './system.js'\nimport * as port from 'get-port-please'\n\n/**\n * Returns an available port in the current environment.\n * @returns {Promise<number>} A promise that resolves with an availabe port.\n */\nexport async function getRandomPort(): Promise<number> {\n debug(content`Getting a random port...`)\n const randomPort = await retryOnError(() => port.getRandomPort())\n debug(content`Random port obtained: ${token.raw(`${randomPort}`)}`)\n return randomPort\n}\n\nasync function retryOnError<T>(execute: () => T, maxTries = 5, waitTimeInSeconds = 1) {\n let retryCount = 1\n while (true) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await execute()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (retryCount++ < maxTries) {\n debug(content`Unknown problem getting a random port: ${error.message}`)\n // eslint-disable-next-line no-await-in-loop\n await sleep(waitTimeInSeconds)\n } else {\n throw new Abort(error.message)\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AACjD,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAChC,OAAO,EAAC,KAAK,EAAC,MAAM,aAAa,CAAA;AACjC,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,KAAK,CAAC,OAAO,CAAA,0BAA0B,CAAC,CAAA;IACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;IACjE,KAAK,CAAC,OAAO,CAAA,yBAAyB,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,CAAA;IACnE,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,KAAK,UAAU,YAAY,CAAI,OAAgB,EAAE,QAAQ,GAAG,CAAC,EAAE,iBAAiB,GAAG,CAAC;IAClF,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,OAAO,IAAI,EAAE;QACX,IAAI;YACF,4CAA4C;YAC5C,OAAO,MAAM,OAAO,EAAE,CAAA;YACtB,8DAA8D;SAC/D;QAAC,OAAO,KAAU,EAAE;YACnB,IAAI,UAAU,EAAE,GAAG,QAAQ,EAAE;gBAC3B,KAAK,CAAC,OAAO,CAAA,0CAA0C,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;gBACvE,4CAA4C;gBAC5C,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAA;aAC/B;iBAAM;gBACL,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;aAC/B;SACF;KACF;AACH,CAAC","sourcesContent":["import {debug, content, token} from './output.js'\nimport {Abort} from './error.js'\nimport {sleep} from './system.js'\nimport * as port from 'get-port-please'\n\n/**\n * Returns an available port in the current environment.\n * @returns A promise that resolves with an availabe port.\n */\nexport async function getRandomPort(): Promise<number> {\n debug(content`Getting a random port...`)\n const randomPort = await retryOnError(() => port.getRandomPort())\n debug(content`Random port obtained: ${token.raw(`${randomPort}`)}`)\n return randomPort\n}\n\nasync function retryOnError<T>(execute: () => T, maxTries = 5, waitTimeInSeconds = 1) {\n let retryCount = 1\n while (true) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await execute()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (retryCount++ < maxTries) {\n debug(content`Unknown problem getting a random port: ${error.message}`)\n // eslint-disable-next-line no-await-in-loop\n await sleep(waitTimeInSeconds)\n } else {\n throw new Abort(error.message)\n }\n }\n }\n}\n"]}
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Takes a random value from an array.
3
- * @param array {T[]} Array from which we'll select a random item.
3
+ * @param array - Array from which we'll select a random item.
4
4
  * @returns A random element from the array.
5
5
  */
6
6
  export declare function takeRandomFromArray<T>(array: T[]): T | undefined;
7
7
  /**
8
8
  * Returns a copy of the array deleting the elemements that are undefined.
9
- * @param array {T[]} The array whose undefined will be deleted.
10
- * @returns {T[]} A copy of the array with the undefined elements deleted.
9
+ * @param array - The array whose undefined will be deleted.
10
+ * @returns A copy of the array with the undefined elements deleted.
11
11
  */
12
12
  export declare function getArrayRejectingUndefined<T>(array: (T | undefined)[]): T[];
13
13
  /**
14
14
  * Returns true if an array contains duplicates.
15
- * @returns {boolean} True if the array contains duplicates.
15
+ * @returns True if the array contains duplicates.
16
16
  */
17
17
  export declare function getArrayContainsDuplicates<T>(array: T[]): boolean;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Takes a random value from an array.
3
- * @param array {T[]} Array from which we'll select a random item.
3
+ * @param array - Array from which we'll select a random item.
4
4
  * @returns A random element from the array.
5
5
  */
6
6
  export function takeRandomFromArray(array) {
@@ -8,15 +8,15 @@ export function takeRandomFromArray(array) {
8
8
  }
9
9
  /**
10
10
  * Returns a copy of the array deleting the elemements that are undefined.
11
- * @param array {T[]} The array whose undefined will be deleted.
12
- * @returns {T[]} A copy of the array with the undefined elements deleted.
11
+ * @param array - The array whose undefined will be deleted.
12
+ * @returns A copy of the array with the undefined elements deleted.
13
13
  */
14
14
  export function getArrayRejectingUndefined(array) {
15
15
  return array.filter((item) => item !== undefined);
16
16
  }
17
17
  /**
18
18
  * Returns true if an array contains duplicates.
19
- * @returns {boolean} True if the array contains duplicates.
19
+ * @returns True if the array contains duplicates.
20
20
  */
21
21
  export function getArrayContainsDuplicates(array) {
22
22
  return array.length !== new Set(array).size;
@@ -1 +1 @@
1
- {"version":3,"file":"array.js","sourceRoot":"","sources":["../../../src/public/common/array.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAI,KAAU;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAwB;IACpE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAmC,CAAA;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAU;IACtD,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAA;AAC7C,CAAC","sourcesContent":["/**\n * Takes a random value from an array.\n * @param array {T[]} Array from which we'll select a random item.\n * @returns A random element from the array.\n */\nexport function takeRandomFromArray<T>(array: T[]) {\n return array[Math.floor(Math.random() * array.length)]\n}\n\n/**\n * Returns a copy of the array deleting the elemements that are undefined.\n * @param array {T[]} The array whose undefined will be deleted.\n * @returns {T[]} A copy of the array with the undefined elements deleted.\n */\nexport function getArrayRejectingUndefined<T>(array: (T | undefined)[]): T[] {\n return array.filter((item) => item !== undefined) as Exclude<T, null | undefined>[]\n}\n\n/**\n * Returns true if an array contains duplicates.\n * @returns {boolean} True if the array contains duplicates.\n */\nexport function getArrayContainsDuplicates<T>(array: T[]) {\n return array.length !== new Set(array).size\n}\n"]}
1
+ {"version":3,"file":"array.js","sourceRoot":"","sources":["../../../src/public/common/array.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAI,KAAU;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAwB;IACpE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAmC,CAAA;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAU;IACtD,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAA;AAC7C,CAAC","sourcesContent":["/**\n * Takes a random value from an array.\n * @param array - Array from which we'll select a random item.\n * @returns A random element from the array.\n */\nexport function takeRandomFromArray<T>(array: T[]) {\n return array[Math.floor(Math.random() * array.length)]\n}\n\n/**\n * Returns a copy of the array deleting the elemements that are undefined.\n * @param array - The array whose undefined will be deleted.\n * @returns A copy of the array with the undefined elements deleted.\n */\nexport function getArrayRejectingUndefined<T>(array: (T | undefined)[]): T[] {\n return array.filter((item) => item !== undefined) as Exclude<T, null | undefined>[]\n}\n\n/**\n * Returns true if an array contains duplicates.\n * @returns True if the array contains duplicates.\n */\nexport function getArrayContainsDuplicates<T>(array: T[]) {\n return array.length !== new Set(array).size\n}\n"]}
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * Fetches secured content from the system's keychain.
3
- * @param identifier {string} Identifier to identify the content.
3
+ * @param identifier - Identifier to identify the content.
4
4
  * @returns A promise that resolves with the content or null if it doesn't exist.
5
5
  */
6
6
  export declare function fetch(identifier: string): Promise<string | null>;
7
7
  /**
8
8
  * Securely stores the content under the given key.
9
- * @param identifier {string} Identifier to identify the content.
10
- * @param content {string} The content to be stored.
9
+ * @param identifier - Identifier to identify the content.
10
+ * @param content - The content to be stored.
11
11
  * @returns A promise that resolves when the storing completes.
12
12
  */
13
13
  export declare function store(identifier: string, content: string): Promise<void>;
14
14
  /**
15
15
  * Removes the content with the given identifier.
16
- * @param identifier {string} Identifier to identify the content.
16
+ * @param identifier - Identifier to identify the content.
17
17
  * @returns A promise that resolves with true if the content was deleted.
18
18
  */
19
19
  export declare function remove(identifier: string): Promise<boolean>;
@@ -3,7 +3,7 @@ import { content as outputContent, debug } from './output.js';
3
3
  import { Abort } from './error.js';
4
4
  /**
5
5
  * Fetches secured content from the system's keychain.
6
- * @param identifier {string} Identifier to identify the content.
6
+ * @param identifier - Identifier to identify the content.
7
7
  * @returns A promise that resolves with the content or null if it doesn't exist.
8
8
  */
9
9
  export async function fetch(identifier) {
@@ -19,8 +19,8 @@ export async function fetch(identifier) {
19
19
  }
20
20
  /**
21
21
  * Securely stores the content under the given key.
22
- * @param identifier {string} Identifier to identify the content.
23
- * @param content {string} The content to be stored.
22
+ * @param identifier - Identifier to identify the content.
23
+ * @param content - The content to be stored.
24
24
  * @returns A promise that resolves when the storing completes.
25
25
  */
26
26
  export async function store(identifier, content) {
@@ -35,7 +35,7 @@ export async function store(identifier, content) {
35
35
  }
36
36
  /**
37
37
  * Removes the content with the given identifier.
38
- * @param identifier {string} Identifier to identify the content.
38
+ * @param identifier - Identifier to identify the content.
39
39
  * @returns A promise that resolves with true if the content was deleted.
40
40
  */
41
41
  export async function remove(identifier) {
@@ -1 +1 @@
1
- {"version":3,"file":"secure-store.js","sourceRoot":"","sources":["../src/secure-store.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAC,OAAO,IAAI,aAAa,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAEhC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,UAAkB;IAC5C,KAAK,CAAC,aAAa,CAAA,WAAW,UAAU,2BAA2B,CAAC,CAAA;IACpE,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAChF,OAAO,OAAO,CAAA;KACf;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,sCAAsC,CAAC,CAAA;KACjE;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,UAAkB,EAAE,OAAe;IAC7D,KAAK,CAAC,aAAa,CAAA,YAAY,UAAU,0CAA0C,CAAC,CAAA;IACpF,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;KAClF;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,mCAAmC,CAAC,CAAA;KAC9D;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAkB;IAC7C,KAAK,CAAC,aAAa,CAAA,YAAY,UAAU,2BAA2B,CAAC,CAAA;IACrE,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC1F,OAAO,MAAM,CAAA;KACd;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,wCAAwC,CAAC,CAAA;KACnE;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,OAAe;IAClD,IAAI,UAAU,GAAG,OAAO,CAAA;IACxB,IAAI,KAAK,GAAuB,EAAE,CAAA;IAClC,IAAI,KAAK,YAAY,KAAK,EAAE;QAC1B,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACjD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;KACpB;IACD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;IACnB,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import constants from './constants.js'\nimport {content as outputContent, debug} from './output.js'\nimport {Abort} from './error.js'\n\n/**\n * Fetches secured content from the system's keychain.\n * @param identifier {string} Identifier to identify the content.\n * @returns A promise that resolves with the content or null if it doesn't exist.\n */\nexport async function fetch(identifier: string): Promise<string | null> {\n debug(outputContent`Reading ${identifier} from the secure store...`)\n try {\n const keytar = await import('keytar')\n const content = await keytar.getPassword(constants.keychain.service, identifier)\n return content\n } catch (error) {\n throw createAbort(error, 'Unable to read from the secure store')\n }\n}\n\n/**\n * Securely stores the content under the given key.\n * @param identifier {string} Identifier to identify the content.\n * @param content {string} The content to be stored.\n * @returns A promise that resolves when the storing completes.\n */\nexport async function store(identifier: string, content: string): Promise<void> {\n debug(outputContent`Updating ${identifier} in the secure store with new content...`)\n try {\n const keytar = await import('keytar')\n await keytar.default.setPassword(constants.keychain.service, identifier, content)\n } catch (error) {\n throw createAbort(error, 'Unable to update the secure store')\n }\n}\n\n/**\n * Removes the content with the given identifier.\n * @param identifier {string} Identifier to identify the content.\n * @returns A promise that resolves with true if the content was deleted.\n */\nexport async function remove(identifier: string): Promise<boolean> {\n debug(outputContent`Removing ${identifier} from the secure store...`)\n try {\n const keytar = await import('keytar')\n const result = await keytar.default.deletePassword(constants.keychain.service, identifier)\n return result\n } catch (error) {\n throw createAbort(error, 'Unable to remove from the secure store')\n }\n}\n\nfunction createAbort(error: unknown, message: string) {\n let newMessage = message\n let stack: string | undefined = ''\n if (error instanceof Error) {\n newMessage = message.concat(`: ${error.message}`)\n stack = error.stack\n }\n const abort = new Abort(newMessage)\n abort.stack = stack\n return abort\n}\n"]}
1
+ {"version":3,"file":"secure-store.js","sourceRoot":"","sources":["../src/secure-store.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAC,OAAO,IAAI,aAAa,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAEhC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,UAAkB;IAC5C,KAAK,CAAC,aAAa,CAAA,WAAW,UAAU,2BAA2B,CAAC,CAAA;IACpE,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAChF,OAAO,OAAO,CAAA;KACf;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,sCAAsC,CAAC,CAAA;KACjE;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,UAAkB,EAAE,OAAe;IAC7D,KAAK,CAAC,aAAa,CAAA,YAAY,UAAU,0CAA0C,CAAC,CAAA;IACpF,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;KAClF;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,mCAAmC,CAAC,CAAA;KAC9D;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAkB;IAC7C,KAAK,CAAC,aAAa,CAAA,YAAY,UAAU,2BAA2B,CAAC,CAAA;IACrE,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC1F,OAAO,MAAM,CAAA;KACd;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,WAAW,CAAC,KAAK,EAAE,wCAAwC,CAAC,CAAA;KACnE;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,OAAe;IAClD,IAAI,UAAU,GAAG,OAAO,CAAA;IACxB,IAAI,KAAK,GAAuB,EAAE,CAAA;IAClC,IAAI,KAAK,YAAY,KAAK,EAAE;QAC1B,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACjD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;KACpB;IACD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;IACnB,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import constants from './constants.js'\nimport {content as outputContent, debug} from './output.js'\nimport {Abort} from './error.js'\n\n/**\n * Fetches secured content from the system's keychain.\n * @param identifier - Identifier to identify the content.\n * @returns A promise that resolves with the content or null if it doesn't exist.\n */\nexport async function fetch(identifier: string): Promise<string | null> {\n debug(outputContent`Reading ${identifier} from the secure store...`)\n try {\n const keytar = await import('keytar')\n const content = await keytar.getPassword(constants.keychain.service, identifier)\n return content\n } catch (error) {\n throw createAbort(error, 'Unable to read from the secure store')\n }\n}\n\n/**\n * Securely stores the content under the given key.\n * @param identifier - Identifier to identify the content.\n * @param content - The content to be stored.\n * @returns A promise that resolves when the storing completes.\n */\nexport async function store(identifier: string, content: string): Promise<void> {\n debug(outputContent`Updating ${identifier} in the secure store with new content...`)\n try {\n const keytar = await import('keytar')\n await keytar.default.setPassword(constants.keychain.service, identifier, content)\n } catch (error) {\n throw createAbort(error, 'Unable to update the secure store')\n }\n}\n\n/**\n * Removes the content with the given identifier.\n * @param identifier - Identifier to identify the content.\n * @returns A promise that resolves with true if the content was deleted.\n */\nexport async function remove(identifier: string): Promise<boolean> {\n debug(outputContent`Removing ${identifier} from the secure store...`)\n try {\n const keytar = await import('keytar')\n const result = await keytar.default.deletePassword(constants.keychain.service, identifier)\n return result\n } catch (error) {\n throw createAbort(error, 'Unable to remove from the secure store')\n }\n}\n\nfunction createAbort(error: unknown, message: string) {\n let newMessage = message\n let stack: string | undefined = ''\n if (error instanceof Error) {\n newMessage = message.concat(`: ${error.message}`)\n stack = error.stack\n }\n const abort = new Abort(newMessage)\n abort.stack = stack\n return abort\n}\n"]}
@@ -14,8 +14,8 @@ export interface DeviceAuthorizationResponse {
14
14
  *
15
15
  * Also returns a `deviceCode` used for polling the token endpoint in the next step.
16
16
  *
17
- * @param scopes The scopes to request
18
- * @returns {Promise<DeviceAuthorizationResponse>} An object with the device authorization response.
17
+ * @param scopes - The scopes to request
18
+ * @returns An object with the device authorization response.
19
19
  */
20
20
  export declare function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse>;
21
21
  /**
@@ -25,8 +25,8 @@ export declare function requestDeviceAuthorization(scopes: string[]): Promise<De
25
25
  *
26
26
  * Timeout for the polling is defined by the server and is around 600 seconds.
27
27
  *
28
- * @param code The device code obtained after starting a device identity flow
29
- * @param interval The interval to poll the token endpoint
30
- * @returns {Promise<IdentityToken>} The identity token
28
+ * @param code - The device code obtained after starting a device identity flow
29
+ * @param interval - The interval to poll the token endpoint
30
+ * @returns The identity token
31
31
  */
32
32
  export declare function pollForDeviceAuthorization(code: string, interval?: number): Promise<IdentityToken>;
@@ -14,8 +14,8 @@ const DeviceAuthError = () => {
14
14
  *
15
15
  * Also returns a `deviceCode` used for polling the token endpoint in the next step.
16
16
  *
17
- * @param scopes The scopes to request
18
- * @returns {Promise<DeviceAuthorizationResponse>} An object with the device authorization response.
17
+ * @param scopes - The scopes to request
18
+ * @returns An object with the device authorization response.
19
19
  */
20
20
  export async function requestDeviceAuthorization(scopes) {
21
21
  const fqdn = await identityFqdn();
@@ -51,9 +51,9 @@ export async function requestDeviceAuthorization(scopes) {
51
51
  *
52
52
  * Timeout for the polling is defined by the server and is around 600 seconds.
53
53
  *
54
- * @param code The device code obtained after starting a device identity flow
55
- * @param interval The interval to poll the token endpoint
56
- * @returns {Promise<IdentityToken>} The identity token
54
+ * @param code - The device code obtained after starting a device identity flow
55
+ * @param interval - The interval to poll the token endpoint
56
+ * @returns The identity token
57
57
  */
58
58
  export async function pollForDeviceAuthorization(code, interval = 5) {
59
59
  let currentIntervalInSeconds = interval;
@@ -1 +1 @@
1
- {"version":3,"file":"device-authorization.js","sourceRoot":"","sources":["../../src/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 {identity as identityFqdn} from '../environment/fqdn.js'\nimport {shopifyFetch} from '../http.js'\nimport {content, debug, info, token} from '../output.js'\nimport {Bug} from '../error.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\nconst DeviceAuthError = () => {\n return new Bug('Failed to start authorization process')\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 {Promise<DeviceAuthorizationResponse>} An object with the device authorization response.\n */\nexport async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {\n const fqdn = await identityFqdn()\n const identityClientId = await 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 debug(content`Received device authorization code: ${token.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) throw DeviceAuthError()\n\n info('\\nTo run this command, log in to Shopify Partners.')\n info(content`User verification code: ${jsonResult.user_code}`)\n info(content`👉 Open this link to start the auth process: ${token.green(jsonResult.verification_uri_complete)}`)\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 {Promise<IdentityToken>} 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()) return resolve(result.value)\n\n const error = result.error ?? 'unknown_failure'\n\n debug(content`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending':\n return startPolling()\n case 'slow_down':\n currentIntervalInSeconds += 5\n return startPolling()\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure':\n return reject(result)\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/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 {identity as identityFqdn} from '../environment/fqdn.js'\nimport {shopifyFetch} from '../http.js'\nimport {content, debug, info, token} from '../output.js'\nimport {Bug} from '../error.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\nconst DeviceAuthError = () => {\n return new Bug('Failed to start authorization process')\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 = await 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 debug(content`Received device authorization code: ${token.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) throw DeviceAuthError()\n\n info('\\nTo run this command, log in to Shopify Partners.')\n info(content`User verification code: ${jsonResult.user_code}`)\n info(content`👉 Open this link to start the auth process: ${token.green(jsonResult.verification_uri_complete)}`)\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()) return resolve(result.value)\n\n const error = result.error ?? 'unknown_failure'\n\n debug(content`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending':\n return startPolling()\n case 'slow_down':\n currentIntervalInSeconds += 5\n return startPolling()\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure':\n return reject(result)\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"]}
@@ -11,41 +11,35 @@ export interface ExchangeScopes {
11
11
  /**
12
12
  * Given a valid authorization code, request an identity access token.
13
13
  * This token can then be used to get API specific tokens.
14
- * @param codeData code and codeVerifier from the authorize endpoint
15
- * @param clientId
16
- * @param identityFqdn
17
- * @returns {Promise<IdentityToken>} An instance with the identity access tokens.
14
+ * @param codeData - code and codeVerifier from the authorize endpoint
15
+ * @returns An instance with the identity access tokens.
18
16
  */
19
17
  export declare function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken>;
20
18
  /**
21
19
  * Given an identity token, request an application token.
22
- * @param token access token obtained in a previous step
23
- * @param store the store to use, only needed for admin API
24
- * @param clientId
25
- * @param identityFqdn
26
- * @returns {Promise<ApplicationSchema>} An array with the application access tokens.
20
+ * @param identityToken - access token obtained in a previous step
21
+ * @param store - the store to use, only needed for admin API
22
+ * @returns An array with the application access tokens.
27
23
  */
28
24
  export declare function exchangeAccessForApplicationTokens(identityToken: IdentityToken, scopes: ExchangeScopes, store?: string): Promise<{
29
25
  [x: string]: ApplicationToken;
30
26
  }>;
31
27
  /**
32
28
  * Given an expired access token, refresh it to get a new one.
33
- * @param currentToken
34
- * @returns
35
29
  */
36
30
  export declare function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken>;
37
31
  /**
38
32
  * Given a custom CLI token passed as ENV variable, request a valid partners API token
39
33
  * This token does not accept extra scopes, just the cli one.
40
- * @param token {string} The CLI token passed as ENV variable
41
- * @returns {Promise<ApplicationToken>} An instance with the application access tokens.
34
+ * @param token - The CLI token passed as ENV variable
35
+ * @returns An instance with the application access tokens.
42
36
  */
43
37
  export declare function exchangeCustomPartnerToken(token: string): Promise<ApplicationToken>;
44
38
  export declare type IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure';
45
39
  /**
46
40
  * Given a deviceCode obtained after starting a device identity flow, request an identity token.
47
- * @param deviceCode The device code obtained after starting a device identity flow
48
- * @param scopes The scopes to request
49
- * @returns {Promise<IdentityToken>} An instance with the identity access tokens.
41
+ * @param deviceCode - The device code obtained after starting a device identity flow
42
+ * @param scopes - The scopes to request
43
+ * @returns An instance with the identity access tokens.
50
44
  */
51
45
  export declare function exchangeDeviceCodeForAccessToken(deviceCode: string): Promise<Result<IdentityToken, IdentityDeviceError>>;
@@ -10,10 +10,8 @@ const InvalidIdentityError = () => new Abort('\nError validating auth session',
10
10
  /**
11
11
  * Given a valid authorization code, request an identity access token.
12
12
  * This token can then be used to get API specific tokens.
13
- * @param codeData code and codeVerifier from the authorize endpoint
14
- * @param clientId
15
- * @param identityFqdn
16
- * @returns {Promise<IdentityToken>} An instance with the identity access tokens.
13
+ * @param codeData - code and codeVerifier from the authorize endpoint
14
+ * @returns An instance with the identity access tokens.
17
15
  */
18
16
  export async function exchangeCodeForAccessToken(codeData) {
19
17
  const clientId = await getIdentityClientId();
@@ -30,11 +28,9 @@ export async function exchangeCodeForAccessToken(codeData) {
30
28
  }
31
29
  /**
32
30
  * Given an identity token, request an application token.
33
- * @param token access token obtained in a previous step
34
- * @param store the store to use, only needed for admin API
35
- * @param clientId
36
- * @param identityFqdn
37
- * @returns {Promise<ApplicationSchema>} An array with the application access tokens.
31
+ * @param identityToken - access token obtained in a previous step
32
+ * @param store - the store to use, only needed for admin API
33
+ * @returns An array with the application access tokens.
38
34
  */
39
35
  export async function exchangeAccessForApplicationTokens(identityToken, scopes, store) {
40
36
  const token = identityToken.accessToken;
@@ -52,8 +48,6 @@ export async function exchangeAccessForApplicationTokens(identityToken, scopes,
52
48
  }
53
49
  /**
54
50
  * Given an expired access token, refresh it to get a new one.
55
- * @param currentToken
56
- * @returns
57
51
  */
58
52
  export async function refreshAccessToken(currentToken) {
59
53
  const clientId = await getIdentityClientId();
@@ -70,8 +64,8 @@ export async function refreshAccessToken(currentToken) {
70
64
  /**
71
65
  * Given a custom CLI token passed as ENV variable, request a valid partners API token
72
66
  * This token does not accept extra scopes, just the cli one.
73
- * @param token {string} The CLI token passed as ENV variable
74
- * @returns {Promise<ApplicationToken>} An instance with the application access tokens.
67
+ * @param token - The CLI token passed as ENV variable
68
+ * @returns An instance with the application access tokens.
75
69
  */
76
70
  export async function exchangeCustomPartnerToken(token) {
77
71
  const appId = applicationId('partners');
@@ -80,9 +74,9 @@ export async function exchangeCustomPartnerToken(token) {
80
74
  }
81
75
  /**
82
76
  * Given a deviceCode obtained after starting a device identity flow, request an identity token.
83
- * @param deviceCode The device code obtained after starting a device identity flow
84
- * @param scopes The scopes to request
85
- * @returns {Promise<IdentityToken>} An instance with the identity access tokens.
77
+ * @param deviceCode - The device code obtained after starting a device identity flow
78
+ * @param scopes - The scopes to request
79
+ * @returns An instance with the identity access tokens.
86
80
  */
87
81
  export async function exchangeDeviceCodeForAccessToken(deviceCode) {
88
82
  const clientId = await getIdentityClientId();
@@ -1 +1 @@
1
- {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../src/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 {CodeAuthResult} from './authorize.js'\nimport * as secureStore from './store.js'\nimport {Abort} from '../error.js'\nimport {API} from '../network/api.js'\nimport {identity as identityFqdn} from '../environment/fqdn.js'\nimport {shopifyFetch} from '../http.js'\nimport {err, ok, Result} from '../common/result.js'\n\nexport class InvalidGrantError extends Error {}\n\nconst InvalidIdentityError = () =>\n new Abort('\\nError validating auth session', \"We've cleared the current session, please try again\")\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n}\n/**\n * Given a valid authorization code, request an identity access token.\n * This token can then be used to get API specific tokens.\n * @param codeData code and codeVerifier from the authorize endpoint\n * @param clientId\n * @param identityFqdn\n * @returns {Promise<IdentityToken>} An instance with the identity access tokens.\n */\nexport async function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n const params = {\n grant_type: 'authorization_code',\n code: codeData.code,\n redirect_uri: 'http://127.0.0.1:3456',\n client_id: clientId,\n code_verifier: codeData.codeVerifier,\n }\n\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrThrow()\n return buildIdentityToken(value)\n}\n\n/**\n * Given an identity token, request an application token.\n * @param token access token obtained in a previous step\n * @param store the store to use, only needed for admin API\n * @param clientId\n * @param identityFqdn\n * @returns {Promise<ApplicationSchema>} 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 = await requestAppToken('partners', token, scopes.partners)\n const storefront = await requestAppToken('storefront-renderer', token, scopes.storefront)\n\n const result = {\n ...partners,\n ...storefront,\n }\n\n if (store) {\n const admin = await requestAppToken('admin', token, scopes.admin, store)\n Object.assign(result, admin)\n }\n return result\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n * @param currentToken\n * @returns\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = await 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).valueOrThrow()\n return buildIdentityToken(value)\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 {string} The CLI token passed as ENV variable\n * @returns {Promise<ApplicationToken>} An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<ApplicationToken> {\n const appId = applicationId('partners')\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n}\n\nexport type IdentityDeviceError =\n | 'authorization_pending'\n | 'access_denied'\n | 'expired_token'\n | 'slow_down'\n | '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 {Promise<IdentityToken>} 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).valueOrThrow()\n const appToken = await 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}\n\nasync function tokenRequestErrorHandler(error: string) {\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 await secureStore.remove()\n return InvalidIdentityError()\n }\n return new Abort(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): IdentityToken {\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 }\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/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 {CodeAuthResult} from './authorize.js'\nimport * as secureStore from './store.js'\nimport {Abort} from '../error.js'\nimport {API} from '../network/api.js'\nimport {identity as identityFqdn} from '../environment/fqdn.js'\nimport {shopifyFetch} from '../http.js'\nimport {err, ok, Result} from '../common/result.js'\n\nexport class InvalidGrantError extends Error {}\n\nconst InvalidIdentityError = () =>\n new Abort('\\nError validating auth session', \"We've cleared the current session, please try again\")\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n}\n/**\n * Given a valid authorization code, request an identity access token.\n * This token can then be used to get API specific tokens.\n * @param codeData - code and codeVerifier from the authorize endpoint\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n const params = {\n grant_type: 'authorization_code',\n code: codeData.code,\n redirect_uri: 'http://127.0.0.1:3456',\n client_id: clientId,\n code_verifier: codeData.codeVerifier,\n }\n\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrThrow()\n return buildIdentityToken(value)\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 = await requestAppToken('partners', token, scopes.partners)\n const storefront = await requestAppToken('storefront-renderer', token, scopes.storefront)\n\n const result = {\n ...partners,\n ...storefront,\n }\n\n if (store) {\n const admin = await requestAppToken('admin', token, scopes.admin, store)\n Object.assign(result, admin)\n }\n return result\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 = await 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).valueOrThrow()\n return buildIdentityToken(value)\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<ApplicationToken> {\n const appId = applicationId('partners')\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n}\n\nexport type IdentityDeviceError =\n | 'authorization_pending'\n | 'access_denied'\n | 'expired_token'\n | 'slow_down'\n | '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).valueOrThrow()\n const appToken = await 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}\n\nasync function tokenRequestErrorHandler(error: string) {\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 await secureStore.remove()\n return InvalidIdentityError()\n }\n return new Abort(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): IdentityToken {\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 }\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"]}
@@ -13,8 +13,8 @@ const FaviconFileName = 'favicon.svg';
13
13
  /**
14
14
  * Finds the full path of the given file-name from the assets folder.
15
15
  *
16
- * @param {string} fileName The name of the file to look for.
17
- * @returns {string | null} The full path of the file, or null if not found.
16
+ * @param fileName - The name of the file to look for.
17
+ * @returns The full path of the file, or null if not found.
18
18
  */
19
19
  const getFilePath = async (fileName) => {
20
20
  const filePath = await findUp(`assets/${fileName}`, {
@@ -1 +1 @@
1
- {"version":3,"file":"post-auth.js","sourceRoot":"","sources":["../../src/session/post-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,eAAe,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAE/B,MAAM,aAAa,GAAG;IACpB,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,oBAAoB;IACpB,cAAc;CACN,CAAA;AACV,MAAM,kBAAkB,GAAG,WAAW,CAAA;AACtC,MAAM,eAAe,GAAG,aAAa,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,QAAQ,EAAE,EAAE;QAClD,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACtC,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,8BAA8B,EAAE,CAAA;KACvC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,IAAqB,EAAE;IACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAqB,EAAE;IAC1D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,IAAqB,EAAE;IAC5D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,IAAqB,EAAE;IAC7D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IACxD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAqB,EAAE;IACvD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,kBAAkB,CAAC,CAAA;IACtD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAqB,EAAE;IACpD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,CAAA;IACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,+DAA+D,CAAA;AAE7F,MAAM,CAAC,MAAM,eAAe,GAAG,kDAAkD,CAAA;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,kFAAkF,CAAA;AAEnH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mFAAmF,CAAA;AAErH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,+BAA+B,CAAC,CAAA","sourcesContent":["import {findUp, moduleDirectory} from '../path.js'\nimport {read} from '../file.js'\nimport {Bug} from '../error.js'\n\nconst HTMLFileNames = [\n 'empty-url.html',\n 'auth-error.html',\n 'missing-code.html',\n 'missing-state.html',\n 'success.html',\n] as const\nconst StylesheetFilename = 'style.css'\nconst FaviconFileName = 'favicon.svg'\n\n/**\n * Finds the full path of the given file-name from the assets folder.\n *\n * @param {string} fileName The name of the file to look for.\n * @returns {string | null} The full path of the file, or null if not found.\n */\nconst getFilePath = async (fileName: string): Promise<string> => {\n const filePath = await findUp(`assets/${fileName}`, {\n type: 'file',\n cwd: moduleDirectory(import.meta.url),\n })\n if (!filePath) {\n throw RedirectPageAssetNotFoundError()\n }\n return filePath\n}\n\nexport const getEmptyUrlHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[0])\n return read(filePath)\n}\n\nexport const getAuthErrorHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[1])\n return read(filePath)\n}\n\nexport const getMissingCodeHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[2])\n return read(filePath)\n}\n\nexport const getMissingStateHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[3])\n return read(filePath)\n}\n\nexport const getSuccessHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[4])\n return read(filePath)\n}\n\nexport const getStylesheet = async (): Promise<string> => {\n const filePath = await getFilePath(StylesheetFilename)\n return read(filePath)\n}\n\nexport const getFavicon = async (): Promise<string> => {\n const filePath = await getFilePath(FaviconFileName)\n return read(filePath)\n}\n\nexport const EmptyUrlString = 'We received the authentication redirect but the URL is empty.'\n\nexport const AuthErrorString = 'There was an issue while trying to authenticate.'\n\nexport const MissingCodeString = \"The authentication can't continue because the redirect doesn't include the code.\"\n\nexport const MissingStateString = \"The authentication can't continue because the redirect doesn't include the state.\"\n\nexport const RedirectPageAssetNotFoundError = () => new Bug(`Redirect page asset not found`)\n"]}
1
+ {"version":3,"file":"post-auth.js","sourceRoot":"","sources":["../../src/session/post-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,eAAe,EAAC,MAAM,YAAY,CAAA;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA;AAE/B,MAAM,aAAa,GAAG;IACpB,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,oBAAoB;IACpB,cAAc;CACN,CAAA;AACV,MAAM,kBAAkB,GAAG,WAAW,CAAA;AACtC,MAAM,eAAe,GAAG,aAAa,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,GAAG,KAAK,EAAE,QAAgB,EAAmB,EAAE;IAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,QAAQ,EAAE,EAAE;QAClD,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACtC,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,8BAA8B,EAAE,CAAA;KACvC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,IAAqB,EAAE;IACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAqB,EAAE;IAC1D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,IAAqB,EAAE;IAC5D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,IAAqB,EAAE;IAC7D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IACxD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAqB,EAAE;IACvD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,kBAAkB,CAAC,CAAA;IACtD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAqB,EAAE;IACpD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,CAAA;IACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAA;AACvB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,+DAA+D,CAAA;AAE7F,MAAM,CAAC,MAAM,eAAe,GAAG,kDAAkD,CAAA;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,kFAAkF,CAAA;AAEnH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mFAAmF,CAAA;AAErH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,+BAA+B,CAAC,CAAA","sourcesContent":["import {findUp, moduleDirectory} from '../path.js'\nimport {read} from '../file.js'\nimport {Bug} from '../error.js'\n\nconst HTMLFileNames = [\n 'empty-url.html',\n 'auth-error.html',\n 'missing-code.html',\n 'missing-state.html',\n 'success.html',\n] as const\nconst StylesheetFilename = 'style.css'\nconst FaviconFileName = 'favicon.svg'\n\n/**\n * Finds the full path of the given file-name from the assets folder.\n *\n * @param fileName - The name of the file to look for.\n * @returns The full path of the file, or null if not found.\n */\nconst getFilePath = async (fileName: string): Promise<string> => {\n const filePath = await findUp(`assets/${fileName}`, {\n type: 'file',\n cwd: moduleDirectory(import.meta.url),\n })\n if (!filePath) {\n throw RedirectPageAssetNotFoundError()\n }\n return filePath\n}\n\nexport const getEmptyUrlHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[0])\n return read(filePath)\n}\n\nexport const getAuthErrorHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[1])\n return read(filePath)\n}\n\nexport const getMissingCodeHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[2])\n return read(filePath)\n}\n\nexport const getMissingStateHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[3])\n return read(filePath)\n}\n\nexport const getSuccessHTML = async (): Promise<string> => {\n const filePath = await getFilePath(HTMLFileNames[4])\n return read(filePath)\n}\n\nexport const getStylesheet = async (): Promise<string> => {\n const filePath = await getFilePath(StylesheetFilename)\n return read(filePath)\n}\n\nexport const getFavicon = async (): Promise<string> => {\n const filePath = await getFilePath(FaviconFileName)\n return read(filePath)\n}\n\nexport const EmptyUrlString = 'We received the authentication redirect but the URL is empty.'\n\nexport const AuthErrorString = 'There was an issue while trying to authenticate.'\n\nexport const MissingCodeString = \"The authentication can't continue because the redirect doesn't include the code.\"\n\nexport const MissingStateString = \"The authentication can't continue because the redirect doesn't include the state.\"\n\nexport const RedirectPageAssetNotFoundError = () => new Bug(`Redirect page asset not found`)\n"]}
@@ -22,7 +22,7 @@ export class RedirectListener {
22
22
  static createServer(callback) {
23
23
  const app = createApp().use('*', async (request, response) => {
24
24
  const requestUrl = request.url;
25
- if (requestUrl === '/favicon.svg') {
25
+ if (requestUrl?.includes('favicon')) {
26
26
  const faviconFile = await getFavicon();
27
27
  response.setHeader('Content-Type', 'image/svg+xml').write(faviconFile);
28
28
  response.end();
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-listener.js","sourceRoot":"","sources":["../../src/session/redirect-listener.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getFavicon,\n getStylesheet,\n getEmptyUrlHTML,\n getAuthErrorHTML,\n getMissingCodeHTML,\n getMissingStateHTML,\n getSuccessHTML,\n EmptyUrlString,\n MissingCodeString,\n MissingStateString,\n} from './post-auth.js'\nimport {Abort, Bug} from '../error.js'\nimport {content, info, token} from '../output.js'\nimport {createApp, IncomingMessage, ServerResponse} from 'h3'\nimport url from 'url'\nimport {createServer, Server} from 'http'\n\nconst ResponseTimeoutSeconds = 10\nconst ServerStopDelaySeconds = 0.5\n\n/**\n * It represents the result of a redirect.\n */\ntype RedirectCallback = (error: Error | undefined, state: string | undefined, code: string | undefined) => void\n\n/**\n * Defines the interface of the options that\n * are used to instantiate a redirect listener.\n */\ninterface RedirectListenerOptions {\n host: string\n port: number\n callback: RedirectCallback\n}\n/**\n * When the authentication completes, Identity redirects\n * the user to a URL. In the case of the CLI, the redirect\n * is to localhost passing some parameters that are necessary\n * to continue the authentication. Because of that, we need\n * an HTTP server that runs and listens to the request.\n */\nexport class RedirectListener {\n private static createServer(callback: RedirectCallback): Server {\n const app = createApp().use('*', async (request: IncomingMessage, response: ServerResponse) => {\n const requestUrl = request.url\n if (requestUrl === '/favicon.svg') {\n const faviconFile = await getFavicon()\n response.setHeader('Content-Type', 'image/svg+xml').write(faviconFile)\n response.end()\n return {}\n } else if (requestUrl === '/style.css') {\n const stylesheetFile = await getStylesheet()\n response.setHeader('Content-Type', 'text/css').write(stylesheetFile)\n response.end()\n return {}\n }\n\n const respond = async (contents: string, error?: Error, state?: string, code?: string) => {\n response.setHeader('Content-Type', 'text/html').write(contents)\n response.end()\n callback(error, state, code)\n return {}\n }\n\n // If there was an empty/malformed URL sent back.\n if (!requestUrl) {\n const file = await getEmptyUrlHTML()\n const err = new Bug(EmptyUrlString)\n return respond(file, err, undefined, undefined)\n }\n\n // If an error was returned by the Identity server.\n const queryObject = url.parse(requestUrl, true).query\n if (queryObject.error && queryObject.error_description) {\n const file = await getAuthErrorHTML()\n const err = new Abort(`${queryObject.error_description}`)\n return respond(file, err, undefined, undefined)\n }\n\n // If the code isn't present in the URL.\n if (!queryObject.code) {\n const file = await getMissingCodeHTML()\n const err = new Bug(MissingCodeString)\n return respond(file, err, undefined, undefined)\n }\n\n // If the state isn't present in the URL.\n if (!queryObject.state) {\n const file = await getMissingStateHTML()\n const err = new Bug(MissingStateString)\n return respond(file, err, undefined, undefined)\n }\n\n const file = await getSuccessHTML()\n return respond(file, undefined, `${queryObject.code}`, `${queryObject.state}`)\n })\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return createServer(app)\n }\n\n port: number\n host: string\n server: ReturnType<typeof RedirectListener.createServer>\n\n constructor(options: RedirectListenerOptions) {\n this.port = options.port\n this.host = options.host\n this.server = RedirectListener.createServer(options.callback)\n }\n\n start(): void {\n this.server.listen({port: this.port, host: this.host}, () => {})\n }\n\n async stop(): Promise<void> {\n await this.server.close()\n }\n}\n\nexport async function listenRedirect(host: string, port: number, url: string): Promise<{code: string; state: string}> {\n const result = await new Promise<{code: string; state: string}>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const message = '\\nAuto-open timed out. Open the login page: '\n info(content`${message}${token.link('Log in to Shopify Partners', url)}\\n`)\n }, ResponseTimeoutSeconds * 1000)\n\n const callback: RedirectCallback = (error, code, state) => {\n clearTimeout(timeout)\n setTimeout(() => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n redirectListener.stop()\n if (error) reject(error)\n else resolve({code: code as string, state: state as string})\n }, ServerStopDelaySeconds * 1000)\n }\n\n const redirectListener = new RedirectListener({host, port, callback})\n redirectListener.start()\n })\n return result\n}\n"]}
1
+ {"version":3,"file":"redirect-listener.js","sourceRoot":"","sources":["../../src/session/redirect-listener.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getFavicon,\n getStylesheet,\n getEmptyUrlHTML,\n getAuthErrorHTML,\n getMissingCodeHTML,\n getMissingStateHTML,\n getSuccessHTML,\n EmptyUrlString,\n MissingCodeString,\n MissingStateString,\n} from './post-auth.js'\nimport {Abort, Bug} from '../error.js'\nimport {content, info, token} from '../output.js'\nimport {createApp, IncomingMessage, ServerResponse} from 'h3'\nimport url from 'url'\nimport {createServer, Server} from 'http'\n\nconst ResponseTimeoutSeconds = 10\nconst ServerStopDelaySeconds = 0.5\n\n/**\n * It represents the result of a redirect.\n */\ntype RedirectCallback = (error: Error | undefined, state: string | undefined, code: string | undefined) => void\n\n/**\n * Defines the interface of the options that\n * are used to instantiate a redirect listener.\n */\ninterface RedirectListenerOptions {\n host: string\n port: number\n callback: RedirectCallback\n}\n/**\n * When the authentication completes, Identity redirects\n * the user to a URL. In the case of the CLI, the redirect\n * is to localhost passing some parameters that are necessary\n * to continue the authentication. Because of that, we need\n * an HTTP server that runs and listens to the request.\n */\nexport class RedirectListener {\n private static createServer(callback: RedirectCallback): Server {\n const app = createApp().use('*', async (request: IncomingMessage, response: ServerResponse) => {\n const requestUrl = request.url\n if (requestUrl?.includes('favicon')) {\n const faviconFile = await getFavicon()\n response.setHeader('Content-Type', 'image/svg+xml').write(faviconFile)\n response.end()\n return {}\n } else if (requestUrl === '/style.css') {\n const stylesheetFile = await getStylesheet()\n response.setHeader('Content-Type', 'text/css').write(stylesheetFile)\n response.end()\n return {}\n }\n\n const respond = async (contents: string, error?: Error, state?: string, code?: string) => {\n response.setHeader('Content-Type', 'text/html').write(contents)\n response.end()\n callback(error, state, code)\n return {}\n }\n\n // If there was an empty/malformed URL sent back.\n if (!requestUrl) {\n const file = await getEmptyUrlHTML()\n const err = new Bug(EmptyUrlString)\n return respond(file, err, undefined, undefined)\n }\n\n // If an error was returned by the Identity server.\n const queryObject = url.parse(requestUrl, true).query\n if (queryObject.error && queryObject.error_description) {\n const file = await getAuthErrorHTML()\n const err = new Abort(`${queryObject.error_description}`)\n return respond(file, err, undefined, undefined)\n }\n\n // If the code isn't present in the URL.\n if (!queryObject.code) {\n const file = await getMissingCodeHTML()\n const err = new Bug(MissingCodeString)\n return respond(file, err, undefined, undefined)\n }\n\n // If the state isn't present in the URL.\n if (!queryObject.state) {\n const file = await getMissingStateHTML()\n const err = new Bug(MissingStateString)\n return respond(file, err, undefined, undefined)\n }\n\n const file = await getSuccessHTML()\n return respond(file, undefined, `${queryObject.code}`, `${queryObject.state}`)\n })\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return createServer(app)\n }\n\n port: number\n host: string\n server: ReturnType<typeof RedirectListener.createServer>\n\n constructor(options: RedirectListenerOptions) {\n this.port = options.port\n this.host = options.host\n this.server = RedirectListener.createServer(options.callback)\n }\n\n start(): void {\n this.server.listen({port: this.port, host: this.host}, () => {})\n }\n\n async stop(): Promise<void> {\n await this.server.close()\n }\n}\n\nexport async function listenRedirect(host: string, port: number, url: string): Promise<{code: string; state: string}> {\n const result = await new Promise<{code: string; state: string}>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const message = '\\nAuto-open timed out. Open the login page: '\n info(content`${message}${token.link('Log in to Shopify Partners', url)}\\n`)\n }, ResponseTimeoutSeconds * 1000)\n\n const callback: RedirectCallback = (error, code, state) => {\n clearTimeout(timeout)\n setTimeout(() => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n redirectListener.stop()\n if (error) reject(error)\n else resolve({code: code as string, state: state as string})\n }, ServerStopDelaySeconds * 1000)\n }\n\n const redirectListener = new RedirectListener({host, port, callback})\n redirectListener.start()\n })\n return result\n}\n"]}
@@ -40,6 +40,7 @@ declare const ApplicationTokenSchema: define.ZodObject<{
40
40
  * token exchanges.
41
41
  *
42
42
  * @example
43
+ * ```
43
44
  * {
44
45
  * "accounts.shopify.com": {
45
46
  * "identity": {...} // IdentityTokenSchema
@@ -53,8 +54,8 @@ declare const ApplicationTokenSchema: define.ZodObject<{
53
54
  * }
54
55
  * },
55
56
  * "identity.spin.com": {...}
56
- *}
57
- *
57
+ * }
58
+ * ```
58
59
  */
59
60
  export declare const SessionSchema: define.ZodObject<{}, "strip", define.ZodObject<{
60
61
  /**