@shopify/cli-kit 3.60.1 → 3.61.1

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 (71) hide show
  1. package/assets/cli-ruby/lib/project_types/extension/messages/messages.rb +1 -1
  2. package/assets/cli-ruby/lib/project_types/extension/models/specifications.rb +3 -1
  3. package/assets/cli-ruby/lib/shopify_cli/constants.rb +1 -1
  4. package/assets/cli-ruby/lib/shopify_cli/exception_reporter.rb +1 -0
  5. package/dist/private/node/api.d.ts +1 -1
  6. package/dist/private/node/api.js +1 -1
  7. package/dist/private/node/api.js.map +1 -1
  8. package/dist/private/node/constants.d.ts +1 -0
  9. package/dist/private/node/constants.js +3 -0
  10. package/dist/private/node/constants.js.map +1 -1
  11. package/dist/private/node/session/exchange.d.ts +1 -0
  12. package/dist/private/node/session/exchange.js +6 -2
  13. package/dist/private/node/session/exchange.js.map +1 -1
  14. package/dist/private/node/session/identity-token-validation.js +4 -0
  15. package/dist/private/node/session/identity-token-validation.js.map +1 -1
  16. package/dist/private/node/session/identity.js +9 -0
  17. package/dist/private/node/session/identity.js.map +1 -1
  18. package/dist/private/node/session/scopes.d.ts +3 -2
  19. package/dist/private/node/session/scopes.js +10 -5
  20. package/dist/private/node/session/scopes.js.map +1 -1
  21. package/dist/private/node/session/validate.js +5 -0
  22. package/dist/private/node/session/validate.js.map +1 -1
  23. package/dist/private/node/session.d.ts +10 -0
  24. package/dist/private/node/session.js +11 -3
  25. package/dist/private/node/session.js.map +1 -1
  26. package/dist/private/node/ui/components/ConcurrentOutput.d.ts +6 -1
  27. package/dist/private/node/ui/components/ConcurrentOutput.js +46 -16
  28. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  29. package/dist/private/node/ui/components/ConcurrentOutput.test.js +124 -15
  30. package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
  31. package/dist/private/node/ui/components/TextPrompt.d.ts +1 -0
  32. package/dist/private/node/ui/components/TextPrompt.js +2 -2
  33. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  34. package/dist/private/node/ui/utilities.js +3 -1
  35. package/dist/private/node/ui/utilities.js.map +1 -1
  36. package/dist/public/common/version.d.ts +1 -1
  37. package/dist/public/common/version.js +1 -1
  38. package/dist/public/common/version.js.map +1 -1
  39. package/dist/public/node/api/{shopify-developers.d.ts → app-management.d.ts} +2 -2
  40. package/dist/public/node/api/{shopify-developers.js → app-management.js} +6 -6
  41. package/dist/public/node/api/app-management.js.map +1 -0
  42. package/dist/public/node/context/fqdn.d.ts +3 -3
  43. package/dist/public/node/context/fqdn.js +3 -3
  44. package/dist/public/node/context/fqdn.js.map +1 -1
  45. package/dist/public/node/custom-oclif-loader.d.ts +6 -0
  46. package/dist/public/node/custom-oclif-loader.js +6 -3
  47. package/dist/public/node/custom-oclif-loader.js.map +1 -1
  48. package/dist/public/node/fs.d.ts +1 -1
  49. package/dist/public/node/fs.js +3 -2
  50. package/dist/public/node/fs.js.map +1 -1
  51. package/dist/public/node/http.d.ts +1 -1
  52. package/dist/public/node/http.js +1 -1
  53. package/dist/public/node/http.js.map +1 -1
  54. package/dist/public/node/logs.d.ts +3 -0
  55. package/dist/public/node/logs.js +11 -0
  56. package/dist/public/node/logs.js.map +1 -0
  57. package/dist/public/node/schema.d.ts +2 -2
  58. package/dist/public/node/schema.js.map +1 -1
  59. package/dist/public/node/session.d.ts +9 -0
  60. package/dist/public/node/session.js +18 -0
  61. package/dist/public/node/session.js.map +1 -1
  62. package/dist/public/node/themes/types.d.ts +21 -0
  63. package/dist/public/node/themes/types.js.map +1 -1
  64. package/dist/public/node/toml.d.ts +1 -1
  65. package/dist/public/node/toml.js.map +1 -1
  66. package/dist/public/node/ui/components.d.ts +1 -1
  67. package/dist/public/node/ui/components.js +1 -1
  68. package/dist/public/node/ui/components.js.map +1 -1
  69. package/dist/tsconfig.tsbuildinfo +1 -1
  70. package/package.json +2 -2
  71. package/dist/public/node/api/shopify-developers.js.map +0 -1
@@ -245,7 +245,7 @@ module Extension
245
245
  The extension development server binary could not be found!
246
246
 
247
247
  If you're running a development version of the CLI, please run `rake extensions:install` to install it.
248
- Otherwise, please file a bug report via https://github.com/Shopify/shopify-cli/issues/new.
248
+ Otherwise, please file a bug report via https://github.com/Shopify/cli/issues/new.
249
249
  ERROR
250
250
  },
251
251
  outdated_extensions: {
@@ -82,7 +82,9 @@ module Extension
82
82
  end
83
83
 
84
84
  def select_cli_extensions(specification_attribute_sets)
85
- specification_attribute_sets.select { |attributes| attributes.dig(:options, :management_experience) == "cli" }
85
+ specification_attribute_sets.select do |attributes|
86
+ attributes.dig(:options, :management_experience) == "cli" && attributes[:identifier] != "data"
87
+ end
86
88
  end
87
89
  end
88
90
  end
@@ -91,7 +91,7 @@ module ShopifyCLI
91
91
  end
92
92
 
93
93
  module Links
94
- NEW_ISSUE = "https://github.com/Shopify/shopify-cli/issues/new"
94
+ NEW_ISSUE = "https://github.com/Shopify/cli/issues/new"
95
95
  end
96
96
 
97
97
  module Extension
@@ -64,6 +64,7 @@ module ShopifyCLI
64
64
 
65
65
  def self.report_error?(context:)
66
66
  return false if Environment.development?
67
+ return false unless Environment.interactive?
67
68
 
68
69
  CLI::UI::Prompt.ask(context.message("core.error_reporting.report_error.question")) do |handler|
69
70
  handler.option(context.message("core.error_reporting.report_error.yes")) { |_| true }
@@ -1,5 +1,5 @@
1
1
  import { Headers } from 'form-data';
2
- export type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform';
2
+ export type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management';
3
3
  export declare const allAPIs: API[];
4
4
  interface RequestOptions<T> {
5
5
  request: Promise<T>;
@@ -3,7 +3,7 @@ import { sanitizeURL } from './api/urls.js';
3
3
  import { outputDebug } from '@shopify/cli-kit/node/output';
4
4
  import { ClientError } from 'graphql-request';
5
5
  import { performance } from 'perf_hooks';
6
- export const allAPIs = ['admin', 'storefront-renderer', 'partners', 'business-platform'];
6
+ export const allAPIs = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management'];
7
7
  const interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id']);
8
8
  export async function debugLogResponseInfo({ request, url }, errorHandler) {
9
9
  const t0 = performance.now();
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAExD,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAA;AAO/F,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAC,OAAO,EAAE,GAAG,EAAoB,EACjC,YAAiF;IAEjF,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,eAAe,GAA4B,EAAE,CAAA;IACnD,IAAI,QAAQ,GAAM,EAAO,CAAA;IACzB,IAAI;QACF,QAAQ,GAAG,MAAM,OAAO,CAAA;QACxB,8DAA8D;QAC9D,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,GAAQ,EAAE,EAAE;YAChD,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACvE,CAAC,CAAC,CAAA;KACH;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,GAAG,YAAY,WAAW,EAAE;YAC9B,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE;gBACzB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAqC,EAAE;oBAC9E,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;wBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;iBACtE;aACF;SACF;QACD,IAAI,YAAY,EAAE;YAChB,MAAM,YAAY,CAAC,GAAG,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC,CAAA;SACzD;aAAM;YACL,MAAM,GAAG,CAAA;SACV;KACF;YAAS;QACR,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC5B,WAAW,CAAC,cAAc,WAAW,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;;EAEhF,sBAAsB,CAAC,eAAe,CAAC;KACpC,CAAC,CAAA;KACH;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {sanitizeURL} from './api/urls.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform']\n\ninterface RequestOptions<T> {\n request: Promise<T>\n url: string\n}\n\nconst interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id'])\n\nexport async function debugLogResponseInfo<T extends {headers: Headers; status: number}>(\n {request, url}: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => Error | unknown,\n): Promise<T> {\n const t0 = performance.now()\n const responseHeaders: {[key: string]: string} = {}\n let response: T = {} as T\n try {\n response = await request\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n response.headers.forEach((value: any, key: any) => {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n })\n } catch (err) {\n if (err instanceof ClientError) {\n if (err.response?.headers) {\n for (const [key, value] of err.response?.headers as Iterable<[string, string]>) {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n }\n }\n }\n if (errorHandler) {\n throw errorHandler(err, responseHeaders['x-request-id'])\n } else {\n throw err\n }\n } finally {\n const t1 = performance.now()\n outputDebug(`Request to ${sanitizeURL(url)} completed in ${Math.round(t1 - t0)} ms\nWith response headers:\n${sanitizedHeadersOutput(responseHeaders)}\n `)\n }\n return response\n}\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAExD,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,CAAA;AAOjH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAC,OAAO,EAAE,GAAG,EAAoB,EACjC,YAAiF;IAEjF,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,eAAe,GAA4B,EAAE,CAAA;IACnD,IAAI,QAAQ,GAAM,EAAO,CAAA;IACzB,IAAI;QACF,QAAQ,GAAG,MAAM,OAAO,CAAA;QACxB,8DAA8D;QAC9D,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,GAAQ,EAAE,EAAE;YAChD,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACvE,CAAC,CAAC,CAAA;KACH;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,GAAG,YAAY,WAAW,EAAE;YAC9B,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE;gBACzB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAqC,EAAE;oBAC9E,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;wBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;iBACtE;aACF;SACF;QACD,IAAI,YAAY,EAAE;YAChB,MAAM,YAAY,CAAC,GAAG,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC,CAAA;SACzD;aAAM;YACL,MAAM,GAAG,CAAA;SACV;KACF;YAAS;QACR,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC5B,WAAW,CAAC,cAAc,WAAW,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;;EAEhF,sBAAsB,CAAC,eAAe,CAAC;KACpC,CAAC,CAAA;KACH;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {sanitizeURL} from './api/urls.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management']\n\ninterface RequestOptions<T> {\n request: Promise<T>\n url: string\n}\n\nconst interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id'])\n\nexport async function debugLogResponseInfo<T extends {headers: Headers; status: number}>(\n {request, url}: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => Error | unknown,\n): Promise<T> {\n const t0 = performance.now()\n const responseHeaders: {[key: string]: string} = {}\n let response: T = {} as T\n try {\n response = await request\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n response.headers.forEach((value: any, key: any) => {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n })\n } catch (err) {\n if (err instanceof ClientError) {\n if (err.response?.headers) {\n for (const [key, value] of err.response?.headers as Iterable<[string, string]>) {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n }\n }\n }\n if (errorHandler) {\n throw errorHandler(err, responseHeaders['x-request-id'])\n } else {\n throw err\n }\n } finally {\n const t1 = performance.now()\n outputDebug(`Request to ${sanitizeURL(url)} completed in ${Math.round(t1 - t0)} ms\nWith response headers:\n${sanitizedHeadersOutput(responseHeaders)}\n `)\n }\n return response\n}\n"]}
@@ -1,3 +1,4 @@
1
+ export declare const logsFolder: () => string;
1
2
  export declare const environmentVariables: {
2
3
  alwaysLogAnalytics: string;
3
4
  alwaysLogMetrics: string;
@@ -6,6 +6,9 @@ const cacheFolder = () => {
6
6
  return process.env.XDG_CACHE_HOME;
7
7
  return envPaths(identifier).cache;
8
8
  };
9
+ export const logsFolder = () => {
10
+ return envPaths(identifier).log;
11
+ };
9
12
  export const environmentVariables = {
10
13
  alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',
11
14
  alwaysLogMetrics: 'SHOPIFY_CLI_ALWAYS_LOG_METRICS',
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,gBAAgB,EAAE,gCAAgC;IAClD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,eAAe,EAAE,+BAA+B;IAChD,eAAe,EAAE,+BAA+B;IAChD,mEAAmE;IACnE,UAAU,EAAE,YAAY;IACxB,aAAa,EAAE,gBAAgB;IAC/B,6BAA6B,EAAE,0CAA0C;IACzE,MAAM,EAAE,sBAAsB;IAC9B,UAAU,EAAE,aAAa;IACzB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,0BAA0B;IACxC,aAAa,EAAE,4BAA4B;IAC3C,YAAY,EAAE,2BAA2B;IACzC,OAAO,EAAE,yCAAyC;IAClD,oBAAoB,EAAE,qCAAqC;CAC5D,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,kCAAkC,CAAA;AAE7E,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE;QACX,GAAG,EAAE,kBAAkB;KACxB;IACD,WAAW,EAAE;QACX,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,OAAO,WAAW,EAAE,CAAA;YACtB,CAAC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,GAAG,EAAE;oBACT,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;gBAC1C,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACtD,CAAC;aACF;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6BAA6B,EAAE,CAAC;CACjC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,kCAAkC,CAAA","sourcesContent":["import {joinPath} from '../../public/node/path.js'\nimport envPaths from 'env-paths'\n\nconst identifier = 'shopify-cli'\n\nconst cacheFolder = () => {\n if (process.env.XDG_CACHE_HOME) return process.env.XDG_CACHE_HOME\n return envPaths(identifier).cache\n}\n\nexport const environmentVariables = {\n alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',\n alwaysLogMetrics: 'SHOPIFY_CLI_ALWAYS_LOG_METRICS',\n deviceAuth: 'SHOPIFY_CLI_DEVICE_AUTH',\n enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT',\n env: 'SHOPIFY_CLI_ENV',\n firstPartyDev: 'SHOPIFY_CLI_1P_DEV',\n noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS',\n partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',\n runAsUser: 'SHOPIFY_RUN_AS_USER',\n serviceEnv: 'SHOPIFY_SERVICE_ENV',\n skipCliRedirect: 'SHOPIFY_CLI_SKIP_CLI_REDIRECT',\n spinInstance: 'SPIN_INSTANCE',\n themeToken: 'SHOPIFY_CLI_THEME_TOKEN',\n unitTest: 'SHOPIFY_UNIT_TEST',\n verbose: 'SHOPIFY_FLAG_VERBOSE',\n noThemeBundling: 'SHOPIFY_CLI_NO_THEME_BUNDLING',\n bundledThemeCLI: 'SHOPIFY_CLI_BUNDLED_THEME_CLI',\n // Variables to detect if the CLI is running in a cloud environment\n codespaces: 'CODESPACES',\n codespaceName: 'CODESPACE_NAME',\n codespacePortForwardingDomain: 'GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN',\n gitpod: 'GITPOD_WORKSPACE_URL',\n cloudShell: 'CLOUD_SHELL',\n spin: 'SPIN',\n spinAppPort: 'SERVER_PORT',\n spinAppHost: 'SPIN_APP_HOST',\n organization: 'SHOPIFY_CLI_ORGANIZATION',\n identityToken: 'SHOPIFY_CLI_IDENTITY_TOKEN',\n refreshToken: 'SHOPIFY_CLI_REFRESH_TOKEN',\n otelURL: 'SHOPIFY_CLI_OTEL_EXPORTER_OTLP_ENDPOINT',\n themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',\n}\n\nexport const defaultThemeKitAccessDomain = 'theme-kit-access.shopifyapps.com'\n\nexport const systemEnvironmentVariables = {\n backendPort: 'BACKEND_PORT',\n}\n\nexport const pathConstants = {\n executables: {\n dev: '/opt/dev/bin/dev',\n },\n directories: {\n cache: {\n path: () => {\n return cacheFolder()\n },\n vendor: {\n path: () => {\n return joinPath(cacheFolder(), 'vendor')\n },\n binaries: () => {\n return joinPath(cacheFolder(), 'vendor', 'binaries')\n },\n },\n },\n },\n}\n\nexport const sessionConstants = {\n expirationTimeMarginInMinutes: 4,\n}\n\nexport const bugsnagApiKey = '9e1e6889176fd0c795d5c659225e0fae'\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,gBAAgB,EAAE,gCAAgC;IAClD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,eAAe,EAAE,+BAA+B;IAChD,eAAe,EAAE,+BAA+B;IAChD,mEAAmE;IACnE,UAAU,EAAE,YAAY;IACxB,aAAa,EAAE,gBAAgB;IAC/B,6BAA6B,EAAE,0CAA0C;IACzE,MAAM,EAAE,sBAAsB;IAC9B,UAAU,EAAE,aAAa;IACzB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,0BAA0B;IACxC,aAAa,EAAE,4BAA4B;IAC3C,YAAY,EAAE,2BAA2B;IACzC,OAAO,EAAE,yCAAyC;IAClD,oBAAoB,EAAE,qCAAqC;CAC5D,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,kCAAkC,CAAA;AAE7E,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE;QACX,GAAG,EAAE,kBAAkB;KACxB;IACD,WAAW,EAAE;QACX,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,OAAO,WAAW,EAAE,CAAA;YACtB,CAAC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,GAAG,EAAE;oBACT,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;gBAC1C,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACtD,CAAC;aACF;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6BAA6B,EAAE,CAAC;CACjC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,kCAAkC,CAAA","sourcesContent":["import {joinPath} from '../../public/node/path.js'\nimport envPaths from 'env-paths'\n\nconst identifier = 'shopify-cli'\n\nconst cacheFolder = () => {\n if (process.env.XDG_CACHE_HOME) return process.env.XDG_CACHE_HOME\n return envPaths(identifier).cache\n}\n\nexport const logsFolder = () => {\n return envPaths(identifier).log\n}\n\nexport const environmentVariables = {\n alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',\n alwaysLogMetrics: 'SHOPIFY_CLI_ALWAYS_LOG_METRICS',\n deviceAuth: 'SHOPIFY_CLI_DEVICE_AUTH',\n enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT',\n env: 'SHOPIFY_CLI_ENV',\n firstPartyDev: 'SHOPIFY_CLI_1P_DEV',\n noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS',\n partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',\n runAsUser: 'SHOPIFY_RUN_AS_USER',\n serviceEnv: 'SHOPIFY_SERVICE_ENV',\n skipCliRedirect: 'SHOPIFY_CLI_SKIP_CLI_REDIRECT',\n spinInstance: 'SPIN_INSTANCE',\n themeToken: 'SHOPIFY_CLI_THEME_TOKEN',\n unitTest: 'SHOPIFY_UNIT_TEST',\n verbose: 'SHOPIFY_FLAG_VERBOSE',\n noThemeBundling: 'SHOPIFY_CLI_NO_THEME_BUNDLING',\n bundledThemeCLI: 'SHOPIFY_CLI_BUNDLED_THEME_CLI',\n // Variables to detect if the CLI is running in a cloud environment\n codespaces: 'CODESPACES',\n codespaceName: 'CODESPACE_NAME',\n codespacePortForwardingDomain: 'GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN',\n gitpod: 'GITPOD_WORKSPACE_URL',\n cloudShell: 'CLOUD_SHELL',\n spin: 'SPIN',\n spinAppPort: 'SERVER_PORT',\n spinAppHost: 'SPIN_APP_HOST',\n organization: 'SHOPIFY_CLI_ORGANIZATION',\n identityToken: 'SHOPIFY_CLI_IDENTITY_TOKEN',\n refreshToken: 'SHOPIFY_CLI_REFRESH_TOKEN',\n otelURL: 'SHOPIFY_CLI_OTEL_EXPORTER_OTLP_ENDPOINT',\n themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',\n}\n\nexport const defaultThemeKitAccessDomain = 'theme-kit-access.shopifyapps.com'\n\nexport const systemEnvironmentVariables = {\n backendPort: 'BACKEND_PORT',\n}\n\nexport const pathConstants = {\n executables: {\n dev: '/opt/dev/bin/dev',\n },\n directories: {\n cache: {\n path: () => {\n return cacheFolder()\n },\n vendor: {\n path: () => {\n return joinPath(cacheFolder(), 'vendor')\n },\n binaries: () => {\n return joinPath(cacheFolder(), 'vendor', 'binaries')\n },\n },\n },\n },\n}\n\nexport const sessionConstants = {\n expirationTimeMarginInMinutes: 4,\n}\n\nexport const bugsnagApiKey = '9e1e6889176fd0c795d5c659225e0fae'\n"]}
@@ -11,6 +11,7 @@ export interface ExchangeScopes {
11
11
  partners: string[];
12
12
  storefront: string[];
13
13
  businessPlatform: string[];
14
+ appManagement: string[];
14
15
  }
15
16
  /**
16
17
  * Given a valid authorization code, request an identity access token.
@@ -3,6 +3,7 @@ import { identityFqdn } from '../../../public/node/context/fqdn.js';
3
3
  import { shopifyFetch } from '../../../public/node/http.js';
4
4
  import { err, ok } from '../../../public/node/result.js';
5
5
  import { AbortError, ExtendableError } from '../../../public/node/error.js';
6
+ import { isTruthy } from '@shopify/cli-kit/node/context/utilities';
6
7
  export class InvalidGrantError extends ExtendableError {
7
8
  }
8
9
  export class InvalidRequestError extends ExtendableError {
@@ -34,17 +35,20 @@ export async function exchangeCodeForAccessToken(codeData) {
34
35
  */
35
36
  export async function exchangeAccessForApplicationTokens(identityToken, scopes, store) {
36
37
  const token = identityToken.accessToken;
37
- const [partners, storefront, businessPlatform, admin] = await Promise.all([
38
+ const appManagementEnabled = isTruthy(process.env.USE_APP_MANAGEMENT_API);
39
+ const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([
38
40
  requestAppToken('partners', token, scopes.partners),
39
41
  requestAppToken('storefront-renderer', token, scopes.storefront),
40
42
  requestAppToken('business-platform', token, scopes.businessPlatform),
41
43
  store ? requestAppToken('admin', token, scopes.admin, store) : {},
44
+ appManagementEnabled ? requestAppToken('app-management', token, scopes.appManagement) : {},
42
45
  ]);
43
46
  return {
44
47
  ...partners,
45
48
  ...storefront,
46
49
  ...businessPlatform,
47
50
  ...admin,
51
+ ...appManagement,
48
52
  };
49
53
  }
50
54
  /**
@@ -117,7 +121,7 @@ async function requestAppToken(api, token, scopes = [], store) {
117
121
  }
118
122
  const tokenResult = await tokenRequest(params);
119
123
  const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug();
120
- const appToken = await buildApplicationToken(value);
124
+ const appToken = buildApplicationToken(value);
121
125
  return { [identifier]: appToken };
122
126
  }
123
127
  function tokenRequestErrorHandler(error) {
@@ -1 +1 @@
1
- {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {CodeAuthResult} from './authorize.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, ExtendableError} from '../../../public/node/error.js'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: 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).valueOrBug()\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, storefront, businessPlatform, admin] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\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 try {\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n } catch (error) {\n throw new AbortError('The custom token provided is invalid.', 'Ensure the token is correct and not expired.')\n }\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = 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\nfunction 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 return new InvalidRequestError()\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult): 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/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {CodeAuthResult} from './authorize.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, ExtendableError} from '../../../public/node/error.js'\nimport {isTruthy} from '@shopify/cli-kit/node/context/utilities'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n appManagement: 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).valueOrBug()\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 const appManagementEnabled = isTruthy(process.env.USE_APP_MANAGEMENT_API)\n\n const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n appManagementEnabled ? requestAppToken('app-management', token, scopes.appManagement) : {},\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n ...appManagement,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\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 try {\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n } catch (error) {\n throw new AbortError('The custom token provided is invalid.', 'Ensure the token is correct and not expired.')\n }\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n}\n\nfunction 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 return new InvalidRequestError()\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult): 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"]}
@@ -4,7 +4,11 @@ import { shopifyFetch } from '../../../public/node/http.js';
4
4
  import { cacheRetrieveOrRepopulate } from '../conf-store.js';
5
5
  import { err, ok } from '../../../public/node/result.js';
6
6
  import { AbortError } from '../../../public/node/error.js';
7
+ import { firstPartyDev } from '@shopify/cli-kit/node/context/local';
8
+ import { isSpin } from '@shopify/cli-kit/node/context/spin';
7
9
  export async function validateIdentityToken(token) {
10
+ if (isSpin() && firstPartyDev())
11
+ return true;
8
12
  try {
9
13
  return withIntrospectionURL(async (introspectionURL) => {
10
14
  const options = {
@@ -1 +1 @@
1
- {"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {cacheRetrieveOrRepopulate, IntrospectionUrlKey} from '../conf-store.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError} from '../../../public/node/error.js'\n\nexport async function validateIdentityToken(token: string): Promise<boolean> {\n try {\n return withIntrospectionURL<boolean>(async (introspectionURL: string) => {\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`)\n\n const response = await shopifyFetch(introspectionURL, options)\n\n if (response.ok && response.headers.get('content-type')?.includes('json')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n outputDebug(`The identity token is valid: ${json.valid}`)\n return ok(json.valid)\n } else if (response.status === 404 || response.status > 500) {\n // If the status is 404 or 5xx, most likely the introspection endpoint\n // has changed. We should invalidate the cache and try again.\n return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`))\n } else {\n const text = await response.text()\n outputDebug(`The Introspection request failed with:\n - status: ${response.status}\n - www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}\n - body: ${JSON.stringify(text)}`)\n return ok(false)\n }\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function withIntrospectionURL<T>(fn: (introspectionUrl: string) => Promise<Result<T, AbortError>>): Promise<T> {\n const week = 7 * 24 * 60 * 60 * 1000\n const cacheKey: IntrospectionUrlKey = `identity-introspection-url-${await identityFqdn()}`\n let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week)\n let result: Result<T, AbortError> = await fn(introspectionURL)\n if (result.isErr()) {\n introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0)\n result = await fn(introspectionURL)\n }\n if (result.isErr()) {\n throw result.error\n } else {\n return result.value\n }\n}\n\nasync function getIntrospectionURL(): Promise<string> {\n const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n return json.introspection_endpoint\n}\n"]}
1
+ {"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {cacheRetrieveOrRepopulate, IntrospectionUrlKey} from '../conf-store.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {firstPartyDev} from '@shopify/cli-kit/node/context/local'\nimport {isSpin} from '@shopify/cli-kit/node/context/spin'\n\nexport async function validateIdentityToken(token: string): Promise<boolean> {\n if (isSpin() && firstPartyDev()) return true\n\n try {\n return withIntrospectionURL<boolean>(async (introspectionURL: string) => {\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`)\n\n const response = await shopifyFetch(introspectionURL, options)\n\n if (response.ok && response.headers.get('content-type')?.includes('json')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n outputDebug(`The identity token is valid: ${json.valid}`)\n return ok(json.valid)\n } else if (response.status === 404 || response.status > 500) {\n // If the status is 404 or 5xx, most likely the introspection endpoint\n // has changed. We should invalidate the cache and try again.\n return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`))\n } else {\n const text = await response.text()\n outputDebug(`The Introspection request failed with:\n - status: ${response.status}\n - www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}\n - body: ${JSON.stringify(text)}`)\n return ok(false)\n }\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function withIntrospectionURL<T>(fn: (introspectionUrl: string) => Promise<Result<T, AbortError>>): Promise<T> {\n const week = 7 * 24 * 60 * 60 * 1000\n const cacheKey: IntrospectionUrlKey = `identity-introspection-url-${await identityFqdn()}`\n let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week)\n let result: Result<T, AbortError> = await fn(introspectionURL)\n if (result.isErr()) {\n introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0)\n result = await fn(introspectionURL)\n }\n if (result.isErr()) {\n throw result.error\n } else {\n return result.value\n }\n}\n\nasync function getIntrospectionURL(): Promise<string> {\n const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n return json.introspection_endpoint\n}\n"]}
@@ -62,6 +62,15 @@ export function applicationId(api) {
62
62
  return 'ace6dc89-b526-456d-a942-4b8ef6acda4b';
63
63
  }
64
64
  }
65
+ case 'app-management': {
66
+ const environment = serviceEnvironment();
67
+ if (environment === Environment.Production) {
68
+ return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c';
69
+ }
70
+ else {
71
+ return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52';
72
+ }
73
+ }
65
74
  default:
66
75
  throw new BugError(`Application id for API of type: ${api}`);
67
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,uBAAuB,CAAA;AAErE,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;IACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;QACrC,OAAO,sCAAsC,CAAA;KAC9C;SAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;QACjD,OAAO,sCAAsC,CAAA;KAC9C;SAAM;QACL,OAAO,sCAAsC,CAAA;KAC9C;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO,CAAC,CAAC;YACZ,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,UAAU,CAAC,CAAC;YACf,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,qBAAqB,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD,KAAK,mBAAmB,CAAC,CAAC;YACxB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD;YACE,MAAM,IAAI,QAAQ,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAA;KAC/D;AACH,CAAC","sourcesContent":["import {API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {Environment, serviceEnvironment} from '../context/service.js'\n\nexport function clientId(): string {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n } else if (environment === Environment.Production) {\n return 'fbdb2649-e327-4907-8f67-908d24cfd7e3'\n } else {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n }\n}\n\nexport function applicationId(api: API): string {\n switch (api) {\n case 'admin': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n } else if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n case 'partners': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n } else if (environment === Environment.Production) {\n return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6'\n } else {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n }\n }\n case 'storefront-renderer': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return '46f603de-894f-488d-9471-5b721280ff49'\n } else if (environment === Environment.Production) {\n return 'ee139b3d-5861-4d45-b387-1bc3ada7811c'\n } else {\n return '46f603de-894f-488d-9471-5b721280ff49'\n }\n }\n case 'business-platform': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n } else if (environment === Environment.Production) {\n return '32ff8ee5-82b8-4d93-9f8a-c6997cefb7dc'\n } else {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n }\n }\n default:\n throw new BugError(`Application id for API of type: ${api}`)\n }\n}\n"]}
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,uBAAuB,CAAA;AAErE,MAAM,UAAU,QAAQ;IACtB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;IACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;QACrC,OAAO,sCAAsC,CAAA;KAC9C;SAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;QACjD,OAAO,sCAAsC,CAAA;KAC9C;SAAM;QACL,OAAO,sCAAsC,CAAA;KAC9C;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAQ;IACpC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO,CAAC,CAAC;YACZ,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,UAAU,CAAC,CAAC;YACf,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,kEAAkE,CAAA;aAC1E;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD,KAAK,qBAAqB,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD,KAAK,mBAAmB,CAAC,CAAC;YACxB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,KAAK,EAAE;gBACrC,OAAO,sCAAsC,CAAA;aAC9C;iBAAM,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBACjD,OAAO,sCAAsC,CAAA;aAC9C;iBAAM;gBACL,OAAO,sCAAsC,CAAA;aAC9C;SACF;QACD,KAAK,gBAAgB,CAAC,CAAC;YACrB,MAAM,WAAW,GAAG,kBAAkB,EAAE,CAAA;YACxC,IAAI,WAAW,KAAK,WAAW,CAAC,UAAU,EAAE;gBAC1C,OAAO,kEAAkE,CAAA;aAC1E;iBAAM;gBACL,OAAO,kEAAkE,CAAA;aAC1E;SACF;QACD;YACE,MAAM,IAAI,QAAQ,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAA;KAC/D;AACH,CAAC","sourcesContent":["import {API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {Environment, serviceEnvironment} from '../context/service.js'\n\nexport function clientId(): string {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n } else if (environment === Environment.Production) {\n return 'fbdb2649-e327-4907-8f67-908d24cfd7e3'\n } else {\n return 'e5380e02-312a-7408-5718-e07017e9cf52'\n }\n}\n\nexport function applicationId(api: API): string {\n switch (api) {\n case 'admin': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n } else if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n case 'partners': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n } else if (environment === Environment.Production) {\n return '271e16d403dfa18082ffb3d197bd2b5f4479c3fc32736d69296829cbb28d41a6'\n } else {\n return 'df89d73339ac3c6c5f0a98d9ca93260763e384d51d6038da129889c308973978'\n }\n }\n case 'storefront-renderer': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return '46f603de-894f-488d-9471-5b721280ff49'\n } else if (environment === Environment.Production) {\n return 'ee139b3d-5861-4d45-b387-1bc3ada7811c'\n } else {\n return '46f603de-894f-488d-9471-5b721280ff49'\n }\n }\n case 'business-platform': {\n const environment = serviceEnvironment()\n if (environment === Environment.Local) {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n } else if (environment === Environment.Production) {\n return '32ff8ee5-82b8-4d93-9f8a-c6997cefb7dc'\n } else {\n return 'ace6dc89-b526-456d-a942-4b8ef6acda4b'\n }\n }\n case 'app-management': {\n const environment = serviceEnvironment()\n if (environment === Environment.Production) {\n return '7ee65a63608843c577db8b23c4d7316ea0a01bd2f7594f8a9c06ea668c1b775c'\n } else {\n return 'e92482cebb9bfb9fb5a0199cc770fde3de6c8d16b798ee73e36c9d815e070e52'\n }\n }\n default:\n throw new BugError(`Application id for API of type: ${api}`)\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" resolution-mode="require"/>
1
2
  import { API } from '../api.js';
2
3
  /**
3
4
  * Generate a flat array with all the default scopes for all the APIs plus
@@ -5,7 +6,7 @@ import { API } from '../api.js';
5
6
  * @param extraScopes - custom user-defined scopes
6
7
  * @returns Array of scopes
7
8
  */
8
- export declare function allDefaultScopes(extraScopes?: string[]): string[];
9
+ export declare function allDefaultScopes(extraScopes?: string[], systemEnvironment?: NodeJS.ProcessEnv): string[];
9
10
  /**
10
11
  * Generate a flat array with the default scopes for the given API plus
11
12
  * any custom scope defined by the user
@@ -13,4 +14,4 @@ export declare function allDefaultScopes(extraScopes?: string[]): string[];
13
14
  * @param extraScopes - custom user-defined scopes
14
15
  * @returns Array of scopes
15
16
  */
16
- export declare function apiScopes(api: API, extraScopes?: string[]): string[];
17
+ export declare function apiScopes(api: API, extraScopes?: string[], systemEnvironment?: NodeJS.ProcessEnv): string[];
@@ -1,13 +1,14 @@
1
1
  import { allAPIs } from '../api.js';
2
2
  import { BugError } from '../../../public/node/error.js';
3
+ import { isTruthy } from '@shopify/cli-kit/node/context/utilities';
3
4
  /**
4
5
  * Generate a flat array with all the default scopes for all the APIs plus
5
6
  * any custom scope defined by the user.
6
7
  * @param extraScopes - custom user-defined scopes
7
8
  * @returns Array of scopes
8
9
  */
9
- export function allDefaultScopes(extraScopes = []) {
10
- let scopes = allAPIs.map(defaultApiScopes).flat();
10
+ export function allDefaultScopes(extraScopes = [], systemEnvironment = process.env) {
11
+ let scopes = allAPIs.map((api) => defaultApiScopes(api, systemEnvironment)).flat();
11
12
  scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform);
12
13
  return Array.from(new Set(scopes));
13
14
  }
@@ -18,11 +19,11 @@ export function allDefaultScopes(extraScopes = []) {
18
19
  * @param extraScopes - custom user-defined scopes
19
20
  * @returns Array of scopes
20
21
  */
21
- export function apiScopes(api, extraScopes = []) {
22
- const scopes = [...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform);
22
+ export function apiScopes(api, extraScopes = [], systemEnvironment = process.env) {
23
+ const scopes = [...defaultApiScopes(api, systemEnvironment), ...extraScopes.map(scopeTransform)].map(scopeTransform);
23
24
  return Array.from(new Set(scopes));
24
25
  }
25
- function defaultApiScopes(api) {
26
+ function defaultApiScopes(api, systemEnvironment = process.env) {
26
27
  switch (api) {
27
28
  case 'admin':
28
29
  return ['graphql', 'themes', 'collaborator'];
@@ -32,6 +33,8 @@ function defaultApiScopes(api) {
32
33
  return ['cli'];
33
34
  case 'business-platform':
34
35
  return ['destinations'];
36
+ case 'app-management':
37
+ return isTruthy(systemEnvironment.USE_APP_MANAGEMENT_API) ? ['app-management'] : [];
35
38
  default:
36
39
  throw new BugError(`Unknown API: ${api}`);
37
40
  }
@@ -50,6 +53,8 @@ function scopeTransform(scope) {
50
53
  return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools';
51
54
  case 'destinations':
52
55
  return 'https://api.shopify.com/auth/destinations.readonly';
56
+ case 'app-management':
57
+ return 'https://api.shopify.com/auth/organization.apps.manage';
53
58
  default:
54
59
  return scope;
55
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../../src/private/node/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAM,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwB,EAAE;IACzD,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,CAAA;IACjD,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,cAAwB,EAAE;IAC5D,MAAM,MAAM,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IACjG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ;IAChC,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO;YACV,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QAC9C,KAAK,qBAAqB;YACxB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,KAAK,UAAU;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,KAAK,mBAAmB;YACtB,OAAO,CAAC,cAAc,CAAC,CAAA;QACzB;YACE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;KAC5C;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,QAAQ,KAAK,EAAE;QACb,KAAK,SAAS;YACZ,OAAO,iDAAiD,CAAA;QAC1D,KAAK,QAAQ;YACX,OAAO,gDAAgD,CAAA;QACzD,KAAK,cAAc;YACjB,OAAO,2EAA2E,CAAA;QACpF,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAA;QAC/D,KAAK,UAAU;YACb,OAAO,gEAAgE,CAAA;QACzE,KAAK,cAAc;YACjB,OAAO,oDAAoD,CAAA;QAC7D;YACE,OAAO,KAAK,CAAA;KACf;AACH,CAAC","sourcesContent":["import {allAPIs, API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\n\n/**\n * Generate a flat array with all the default scopes for all the APIs plus\n * any custom scope defined by the user.\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function allDefaultScopes(extraScopes: string[] = []): string[] {\n let scopes = allAPIs.map(defaultApiScopes).flat()\n scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\n/**\n * Generate a flat array with the default scopes for the given API plus\n * any custom scope defined by the user\n * @param api - API to get the scopes for\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function apiScopes(api: API, extraScopes: string[] = []): string[] {\n const scopes = [...defaultApiScopes(api), ...extraScopes.map(scopeTransform)].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\nfunction defaultApiScopes(api: API): string[] {\n switch (api) {\n case 'admin':\n return ['graphql', 'themes', 'collaborator']\n case 'storefront-renderer':\n return ['devtools']\n case 'partners':\n return ['cli']\n case 'business-platform':\n return ['destinations']\n default:\n throw new BugError(`Unknown API: ${api}`)\n }\n}\n\nfunction scopeTransform(scope: string): string {\n switch (scope) {\n case 'graphql':\n return 'https://api.shopify.com/auth/shop.admin.graphql'\n case 'themes':\n return 'https://api.shopify.com/auth/shop.admin.themes'\n case 'collaborator':\n return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly'\n case 'cli':\n return 'https://api.shopify.com/auth/partners.app.cli.access'\n case 'devtools':\n return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools'\n case 'destinations':\n return 'https://api.shopify.com/auth/destinations.readonly'\n default:\n return scope\n }\n}\n"]}
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../../src/private/node/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAM,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAC,QAAQ,EAAC,MAAM,yCAAyC,CAAA;AAEhE;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwB,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IAC1F,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAClF,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAClE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,cAAwB,EAAE,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IAC7F,MAAM,MAAM,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IACpH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG;IACjE,QAAQ,GAAG,EAAE;QACX,KAAK,OAAO;YACV,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAA;QAC9C,KAAK,qBAAqB;YACxB,OAAO,CAAC,UAAU,CAAC,CAAA;QACrB,KAAK,UAAU;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,KAAK,mBAAmB;YACtB,OAAO,CAAC,cAAc,CAAC,CAAA;QACzB,KAAK,gBAAgB;YACnB,OAAO,QAAQ,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACrF;YACE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;KAC5C;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,QAAQ,KAAK,EAAE;QACb,KAAK,SAAS;YACZ,OAAO,iDAAiD,CAAA;QAC1D,KAAK,QAAQ;YACX,OAAO,gDAAgD,CAAA;QACzD,KAAK,cAAc;YACjB,OAAO,2EAA2E,CAAA;QACpF,KAAK,KAAK;YACR,OAAO,sDAAsD,CAAA;QAC/D,KAAK,UAAU;YACb,OAAO,gEAAgE,CAAA;QACzE,KAAK,cAAc;YACjB,OAAO,oDAAoD,CAAA;QAC7D,KAAK,gBAAgB;YACnB,OAAO,uDAAuD,CAAA;QAChE;YACE,OAAO,KAAK,CAAA;KACf;AACH,CAAC","sourcesContent":["import {allAPIs, API} from '../api.js'\nimport {BugError} from '../../../public/node/error.js'\nimport {isTruthy} from '@shopify/cli-kit/node/context/utilities'\n\n/**\n * Generate a flat array with all the default scopes for all the APIs plus\n * any custom scope defined by the user.\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function allDefaultScopes(extraScopes: string[] = [], systemEnvironment = process.env): string[] {\n let scopes = allAPIs.map((api) => defaultApiScopes(api, systemEnvironment)).flat()\n scopes = ['openid', ...scopes, ...extraScopes].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\n/**\n * Generate a flat array with the default scopes for the given API plus\n * any custom scope defined by the user\n * @param api - API to get the scopes for\n * @param extraScopes - custom user-defined scopes\n * @returns Array of scopes\n */\nexport function apiScopes(api: API, extraScopes: string[] = [], systemEnvironment = process.env): string[] {\n const scopes = [...defaultApiScopes(api, systemEnvironment), ...extraScopes.map(scopeTransform)].map(scopeTransform)\n return Array.from(new Set(scopes))\n}\n\nfunction defaultApiScopes(api: API, systemEnvironment = process.env): string[] {\n switch (api) {\n case 'admin':\n return ['graphql', 'themes', 'collaborator']\n case 'storefront-renderer':\n return ['devtools']\n case 'partners':\n return ['cli']\n case 'business-platform':\n return ['destinations']\n case 'app-management':\n return isTruthy(systemEnvironment.USE_APP_MANAGEMENT_API) ? ['app-management'] : []\n default:\n throw new BugError(`Unknown API: ${api}`)\n }\n}\n\nfunction scopeTransform(scope: string): string {\n switch (scope) {\n case 'graphql':\n return 'https://api.shopify.com/auth/shop.admin.graphql'\n case 'themes':\n return 'https://api.shopify.com/auth/shop.admin.themes'\n case 'collaborator':\n return 'https://api.shopify.com/auth/partners.collaborator-relationships.readonly'\n case 'cli':\n return 'https://api.shopify.com/auth/partners.app.cli.access'\n case 'devtools':\n return 'https://api.shopify.com/auth/shop.storefront-renderer.devtools'\n case 'destinations':\n return 'https://api.shopify.com/auth/destinations.readonly'\n case 'app-management':\n return 'https://api.shopify.com/auth/organization.apps.manage'\n default:\n return scope\n }\n}\n"]}
@@ -32,6 +32,11 @@ export async function validateSession(scopes, applications, session) {
32
32
  const token = session.applications[appId];
33
33
  tokensAreExpired = tokensAreExpired || isTokenExpired(token);
34
34
  }
35
+ if (applications.appManagementApi) {
36
+ const appId = applicationId('app-management');
37
+ const token = session.applications[appId];
38
+ tokensAreExpired = tokensAreExpired || isTokenExpired(token);
39
+ }
35
40
  if (applications.storefrontRendererApi) {
36
41
  const appId = applicationId('storefront-renderer');
37
42
  const token = session.applications[appId];
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAC,qBAAqB,EAAC,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAC,aAAa,EAAC,MAAM,uCAAuC,CAAA;AAKnE;;GAEG;AACH,SAAS,cAAc,CAAC,eAAyB,EAAE,QAAuB;IACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAA;IACrC,IAAI,aAAa,EAAE,KAAK,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAA;IACxE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAgB,EAChB,YAA+B,EAC/B,OAGC;IAED,IAAI,CAAC,OAAO;QAAE,OAAO,iBAAiB,CAAA;IACtC,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC/D,MAAM,eAAe,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACjF,IAAI,CAAC,cAAc;QAAE,OAAO,iBAAiB,CAAA;IAC7C,IAAI,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAEvD,IAAI,YAAY,CAAC,WAAW,EAAE;QAC5B,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAE,CAAA;QAC1C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,IAAI,YAAY,CAAC,qBAAqB,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAA;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAE,CAAA;QAC1C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,IAAI,YAAY,CAAC,QAAQ,EAAE;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,CAAA;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,SAAS,CAAE,CAAA;QAC9C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,WAAW,CAAC;;kBAEI,gBAAgB;8BACJ,CAAC,eAAe;GAC3C,CAAC,CAAA;IAEF,IAAI,gBAAgB;QAAE,OAAO,eAAe,CAAA;IAC5C,IAAI,CAAC,eAAe;QAAE,OAAO,iBAAiB,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,cAAc,CAAC,KAAuB;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,KAAK,CAAC,SAAS,GAAG,eAAe,EAAE,CAAA;AAC5C,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC,6BAA6B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;AAC1F,CAAC","sourcesContent":["import {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate\n * @param scopes - requested scopes to validate\n * @param applications - requested applications\n * @param session - current session with identity and application tokens\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(\n scopes: string[],\n applications: OAuthApplications,\n session: {\n identity: IdentityToken\n applications: {[x: string]: ApplicationToken}\n },\n): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n if (!scopesAreValid) return 'needs_full_auth'\n let tokensAreExpired = isTokenExpired(session.identity)\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.applications[realAppId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n outputDebug(`\nThe validation of the token for application/identity completed with the following results:\n- It's expired: ${tokensAreExpired}\n- It's invalid in identity: ${!identityIsValid}\n `)\n\n if (tokensAreExpired) return 'needs_refresh'\n if (!identityIsValid) return 'needs_full_auth'\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate\n * @param scopes - requested scopes to validate\n * @param applications - requested applications\n * @param session - current session with identity and application tokens\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(\n scopes: string[],\n applications: OAuthApplications,\n session: {\n identity: IdentityToken\n applications: {[x: string]: ApplicationToken}\n },\n): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n if (!scopesAreValid) return 'needs_full_auth'\n let tokensAreExpired = isTokenExpired(session.identity)\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.appManagementApi) {\n const appId = applicationId('app-management')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.applications[realAppId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n outputDebug(`\nThe validation of the token for application/identity completed with the following results:\n- It's expired: ${tokensAreExpired}\n- It's invalid in identity: ${!identityIsValid}\n `)\n\n if (tokensAreExpired) return 'needs_refresh'\n if (!identityIsValid) return 'needs_full_auth'\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
@@ -21,6 +21,14 @@ interface PartnersAPIOAuthOptions {
21
21
  /** List of scopes to request permissions for. */
22
22
  scopes: PartnersAPIScope[];
23
23
  }
24
+ /**
25
+ * A scope supported by the Developer Platform API.
26
+ */
27
+ type AppManagementAPIScope = 'https://api.shopify.com/auth/organization.apps.manage' | string;
28
+ interface AppManagementAPIOauthOptions {
29
+ /** List of scopes to request permissions for. */
30
+ scopes: AppManagementAPIScope[];
31
+ }
24
32
  /**
25
33
  * A scope supported by the Storefront Renderer API.
26
34
  */
@@ -44,12 +52,14 @@ export interface OAuthApplications {
44
52
  storefrontRendererApi?: StorefrontRendererAPIOAuthOptions;
45
53
  partnersApi?: PartnersAPIOAuthOptions;
46
54
  businessPlatformApi?: BusinessPlatformAPIOAuthOptions;
55
+ appManagementApi?: AppManagementAPIOauthOptions;
47
56
  }
48
57
  export interface OAuthSession {
49
58
  admin?: AdminSession;
50
59
  partners?: string;
51
60
  storefront?: string;
52
61
  businessPlatform?: string;
62
+ appManagement?: string;
53
63
  }
54
64
  /**
55
65
  * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
@@ -17,6 +17,7 @@ import { getIdentityTokenInformation, getPartnersToken } from '../../public/node
17
17
  import { gql } from 'graphql-request';
18
18
  import { outputCompleted, outputInfo, outputWarn } from '@shopify/cli-kit/node/output';
19
19
  import { isTruthy } from '@shopify/cli-kit/node/context/utilities';
20
+ import { isSpin } from '@shopify/cli-kit/node/context/spin';
20
21
  /**
21
22
  * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
22
23
  *
@@ -45,7 +46,7 @@ ${outputToken.json(applications)}
45
46
  const validationResult = await validateSession(scopes, applications, fqdnSession);
46
47
  let newSession = {};
47
48
  function throwOnNoPrompt() {
48
- if (!noPrompt)
49
+ if (!noPrompt || (isSpin() && firstPartyDev()))
49
50
  return;
50
51
  throw new AbortError(`The currently available CLI credentials are invalid.
51
52
 
@@ -145,7 +146,7 @@ async function executeCompleteFlow(applications, identityFqdn) {
145
146
  * @param partnersToken - Partners token.
146
147
  */
147
148
  async function ensureUserHasPartnerAccount(partnersToken) {
148
- if (isTruthy(process.env.USE_SHOPIFY_DEVELOPERS_CLIENT))
149
+ if (isTruthy(process.env.USE_APP_MANAGEMENT_API))
149
150
  return;
150
151
  outputDebug(outputContent `Verifying that the user has a Partner organization`);
151
152
  if (!(await hasPartnerAccount(partnersToken))) {
@@ -244,6 +245,10 @@ async function tokensFor(applications, session, fqdn) {
244
245
  const appId = applicationId('business-platform');
245
246
  tokens.businessPlatform = fqdnSession.applications[appId]?.accessToken;
246
247
  }
248
+ if (applications.appManagementApi) {
249
+ const appId = applicationId('app-management');
250
+ tokens.appManagement = fqdnSession.applications[appId]?.accessToken;
251
+ }
247
252
  return tokens;
248
253
  }
249
254
  // Scope Helpers
@@ -258,7 +263,8 @@ function getFlattenScopes(apps) {
258
263
  const partner = apps.partnersApi?.scopes || [];
259
264
  const storefront = apps.storefrontRendererApi?.scopes || [];
260
265
  const businessPlatform = apps.businessPlatformApi?.scopes || [];
261
- const requestedScopes = [...admin, ...partner, ...storefront, ...businessPlatform];
266
+ const appManagement = apps.appManagementApi?.scopes || [];
267
+ const requestedScopes = [...admin, ...partner, ...storefront, ...businessPlatform, ...appManagement];
262
268
  return allDefaultScopes(requestedScopes);
263
269
  }
264
270
  /**
@@ -272,11 +278,13 @@ function getExchangeScopes(apps) {
272
278
  const partnerScope = apps.partnersApi?.scopes || [];
273
279
  const storefrontScopes = apps.storefrontRendererApi?.scopes || [];
274
280
  const businessPlatformScopes = apps.businessPlatformApi?.scopes || [];
281
+ const appManagementScopes = apps.appManagementApi?.scopes || [];
275
282
  return {
276
283
  admin: apiScopes('admin', adminScope),
277
284
  partners: apiScopes('partners', partnerScope),
278
285
  storefront: apiScopes('storefront-renderer', storefrontScopes),
279
286
  businessPlatform: apiScopes('business-platform', businessPlatformScopes),
287
+ appManagement: apiScopes('app-management', appManagementScopes),
280
288
  };
281
289
  }
282
290
  function buildIdentityTokenFromEnv(scopes, identityTokenInformation) {