@shopify/cli-kit 3.75.4 → 3.76.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 (54) hide show
  1. package/dist/cli/api/graphql/admin/generated/theme_create.d.ts +21 -0
  2. package/dist/cli/api/graphql/admin/generated/theme_create.js +85 -0
  3. package/dist/cli/api/graphql/admin/generated/theme_create.js.map +1 -0
  4. package/dist/private/node/api/graphql.d.ts +1 -0
  5. package/dist/private/node/api/graphql.js +34 -4
  6. package/dist/private/node/api/graphql.js.map +1 -1
  7. package/dist/private/node/conf-store.d.ts +6 -5
  8. package/dist/private/node/conf-store.js +1 -1
  9. package/dist/private/node/conf-store.js.map +1 -1
  10. package/dist/private/node/session/device-authorization.js +11 -3
  11. package/dist/private/node/session/device-authorization.js.map +1 -1
  12. package/dist/private/node/session/validate.js +0 -5
  13. package/dist/private/node/session/validate.js.map +1 -1
  14. package/dist/public/common/version.d.ts +1 -1
  15. package/dist/public/common/version.js +1 -1
  16. package/dist/public/common/version.js.map +1 -1
  17. package/dist/public/node/api/admin.js +3 -3
  18. package/dist/public/node/api/admin.js.map +1 -1
  19. package/dist/public/node/api/app-management.d.ts +3 -2
  20. package/dist/public/node/api/app-management.js +6 -1
  21. package/dist/public/node/api/app-management.js.map +1 -1
  22. package/dist/public/node/api/business-platform.d.ts +5 -3
  23. package/dist/public/node/api/business-platform.js +6 -2
  24. package/dist/public/node/api/business-platform.js.map +1 -1
  25. package/dist/public/node/api/graphql.d.ts +8 -0
  26. package/dist/public/node/api/graphql.js +19 -2
  27. package/dist/public/node/api/graphql.js.map +1 -1
  28. package/dist/public/node/api/partners.d.ts +3 -2
  29. package/dist/public/node/api/partners.js +3 -1
  30. package/dist/public/node/api/partners.js.map +1 -1
  31. package/dist/public/node/base-command.js +8 -5
  32. package/dist/public/node/base-command.js.map +1 -1
  33. package/dist/public/node/cli.js +5 -4
  34. package/dist/public/node/cli.js.map +1 -1
  35. package/dist/public/node/hooks/postrun.js +2 -1
  36. package/dist/public/node/hooks/postrun.js.map +1 -1
  37. package/dist/public/node/hooks/prerun.js +3 -0
  38. package/dist/public/node/hooks/prerun.js.map +1 -1
  39. package/dist/public/node/notifications-system.d.ts +15 -1
  40. package/dist/public/node/notifications-system.js +55 -11
  41. package/dist/public/node/notifications-system.js.map +1 -1
  42. package/dist/public/node/system.d.ts +3 -1
  43. package/dist/public/node/system.js +22 -3
  44. package/dist/public/node/system.js.map +1 -1
  45. package/dist/public/node/themes/api.d.ts +16 -1
  46. package/dist/public/node/themes/api.js +34 -114
  47. package/dist/public/node/themes/api.js.map +1 -1
  48. package/dist/public/node/themes/theme-manager.js +4 -4
  49. package/dist/public/node/themes/theme-manager.js.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +1 -2
  52. package/dist/private/node/session/identity-token-validation.d.ts +0 -1
  53. package/dist/private/node/session/identity-token-validation.js +0 -70
  54. package/dist/private/node/session/identity-token-validation.js.map +0 -1
@@ -0,0 +1,21 @@
1
+ import * as Types from './types.js';
2
+ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
3
+ export type ThemeCreateMutationVariables = Types.Exact<{
4
+ name: Types.Scalars['String']['input'];
5
+ source: Types.Scalars['URL']['input'];
6
+ role: Types.ThemeRole;
7
+ }>;
8
+ export type ThemeCreateMutation = {
9
+ themeCreate?: {
10
+ theme?: {
11
+ id: string;
12
+ name: string;
13
+ role: Types.ThemeRole;
14
+ } | null;
15
+ userErrors: {
16
+ field?: string[] | null;
17
+ message: string;
18
+ }[];
19
+ } | null;
20
+ };
21
+ export declare const ThemeCreate: DocumentNode<ThemeCreateMutation, ThemeCreateMutationVariables>;
@@ -0,0 +1,85 @@
1
+ export const ThemeCreate = {
2
+ kind: 'Document',
3
+ definitions: [
4
+ {
5
+ kind: 'OperationDefinition',
6
+ operation: 'mutation',
7
+ name: { kind: 'Name', value: 'themeCreate' },
8
+ variableDefinitions: [
9
+ {
10
+ kind: 'VariableDefinition',
11
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'name' } },
12
+ type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } },
13
+ },
14
+ {
15
+ kind: 'VariableDefinition',
16
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'source' } },
17
+ type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'URL' } } },
18
+ },
19
+ {
20
+ kind: 'VariableDefinition',
21
+ variable: { kind: 'Variable', name: { kind: 'Name', value: 'role' } },
22
+ type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'ThemeRole' } } },
23
+ },
24
+ ],
25
+ selectionSet: {
26
+ kind: 'SelectionSet',
27
+ selections: [
28
+ {
29
+ kind: 'Field',
30
+ name: { kind: 'Name', value: 'themeCreate' },
31
+ arguments: [
32
+ {
33
+ kind: 'Argument',
34
+ name: { kind: 'Name', value: 'name' },
35
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'name' } },
36
+ },
37
+ {
38
+ kind: 'Argument',
39
+ name: { kind: 'Name', value: 'source' },
40
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'source' } },
41
+ },
42
+ {
43
+ kind: 'Argument',
44
+ name: { kind: 'Name', value: 'role' },
45
+ value: { kind: 'Variable', name: { kind: 'Name', value: 'role' } },
46
+ },
47
+ ],
48
+ selectionSet: {
49
+ kind: 'SelectionSet',
50
+ selections: [
51
+ {
52
+ kind: 'Field',
53
+ name: { kind: 'Name', value: 'theme' },
54
+ selectionSet: {
55
+ kind: 'SelectionSet',
56
+ selections: [
57
+ { kind: 'Field', name: { kind: 'Name', value: 'id' } },
58
+ { kind: 'Field', name: { kind: 'Name', value: 'name' } },
59
+ { kind: 'Field', name: { kind: 'Name', value: 'role' } },
60
+ { kind: 'Field', name: { kind: 'Name', value: '__typename' } },
61
+ ],
62
+ },
63
+ },
64
+ {
65
+ kind: 'Field',
66
+ name: { kind: 'Name', value: 'userErrors' },
67
+ selectionSet: {
68
+ kind: 'SelectionSet',
69
+ selections: [
70
+ { kind: 'Field', name: { kind: 'Name', value: 'field' } },
71
+ { kind: 'Field', name: { kind: 'Name', value: 'message' } },
72
+ { kind: 'Field', name: { kind: 'Name', value: '__typename' } },
73
+ ],
74
+ },
75
+ },
76
+ { kind: 'Field', name: { kind: 'Name', value: '__typename' } },
77
+ ],
78
+ },
79
+ },
80
+ ],
81
+ },
82
+ },
83
+ ],
84
+ };
85
+ //# sourceMappingURL=theme_create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme_create.js","sourceRoot":"","sources":["../../../../../../src/cli/api/graphql/admin/generated/theme_create.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-definitions */\nimport * as Types from './types.js'\n\nimport {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core'\n\nexport type ThemeCreateMutationVariables = Types.Exact<{\n name: Types.Scalars['String']['input']\n source: Types.Scalars['URL']['input']\n role: Types.ThemeRole\n}>\n\nexport type ThemeCreateMutation = {\n themeCreate?: {\n theme?: {id: string; name: string; role: Types.ThemeRole} | null\n userErrors: {field?: string[] | null; message: string}[]\n } | null\n}\n\nexport const ThemeCreate = {\n kind: 'Document',\n definitions: [\n {\n kind: 'OperationDefinition',\n operation: 'mutation',\n name: {kind: 'Name', value: 'themeCreate'},\n variableDefinitions: [\n {\n kind: 'VariableDefinition',\n variable: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},\n type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},\n },\n {\n kind: 'VariableDefinition',\n variable: {kind: 'Variable', name: {kind: 'Name', value: 'source'}},\n type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'URL'}}},\n },\n {\n kind: 'VariableDefinition',\n variable: {kind: 'Variable', name: {kind: 'Name', value: 'role'}},\n type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'ThemeRole'}}},\n },\n ],\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'themeCreate'},\n arguments: [\n {\n kind: 'Argument',\n name: {kind: 'Name', value: 'name'},\n value: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},\n },\n {\n kind: 'Argument',\n name: {kind: 'Name', value: 'source'},\n value: {kind: 'Variable', name: {kind: 'Name', value: 'source'}},\n },\n {\n kind: 'Argument',\n name: {kind: 'Name', value: 'role'},\n value: {kind: 'Variable', name: {kind: 'Name', value: 'role'}},\n },\n ],\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'theme'},\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {kind: 'Field', name: {kind: 'Name', value: 'id'}},\n {kind: 'Field', name: {kind: 'Name', value: 'name'}},\n {kind: 'Field', name: {kind: 'Name', value: 'role'}},\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'userErrors'},\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {kind: 'Field', name: {kind: 'Name', value: 'field'}},\n {kind: 'Field', name: {kind: 'Name', value: 'message'}},\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n ],\n },\n },\n ],\n} as unknown as DocumentNode<ThemeCreateMutation, ThemeCreateMutationVariables>\n"]}
@@ -2,4 +2,5 @@ import { Variables } from 'graphql-request';
2
2
  export declare function debugLogRequestInfo(api: string, query: string, url: string, variables?: Variables, headers?: {
3
3
  [key: string]: string;
4
4
  }): void;
5
+ export declare function sanitizeVariables(variables: Variables): string;
5
6
  export declare function errorHandler(api: string): (error: unknown, requestId?: string) => unknown;
@@ -11,12 +11,42 @@ With request headers:
11
11
  ${sanitizedHeadersOutput(headers)}\n
12
12
  to ${sanitizeURL(url)}`);
13
13
  }
14
- function sanitizeVariables(variables) {
14
+ export function sanitizeVariables(variables) {
15
15
  const result = { ...variables };
16
- if ('apiKey' in result) {
17
- result.apiKey = '*****';
16
+ const sensitiveKeys = ['apiKey', 'serialized_script'];
17
+ const sanitizedResult = sanitizeDeepVariables(result, sensitiveKeys);
18
+ return JSON.stringify(sanitizedResult, null, 2);
19
+ }
20
+ function sanitizeDeepVariables(value, sensitiveKeys) {
21
+ // Checking for JSON
22
+ if (typeof value === 'string') {
23
+ try {
24
+ const parsed = JSON.parse(value);
25
+ if (typeof parsed === 'object' && parsed !== null) {
26
+ const sanitized = sanitizeDeepVariables(parsed, sensitiveKeys);
27
+ return JSON.stringify(sanitized, null);
28
+ }
29
+ // eslint-disable-next-line no-catch-all/no-catch-all
30
+ }
31
+ catch (error) {
32
+ return value;
33
+ }
34
+ }
35
+ if (typeof value !== 'object' || value === null) {
36
+ return value;
37
+ }
38
+ if (Array.isArray(value)) {
39
+ return value.map((item) => sanitizeDeepVariables(item, sensitiveKeys));
40
+ }
41
+ const result = {};
42
+ for (const [key, val] of Object.entries(value)) {
43
+ if (sensitiveKeys.includes(key) && typeof val === 'string') {
44
+ result[key] = '*****';
45
+ continue;
46
+ }
47
+ result[key] = sanitizeDeepVariables(val, sensitiveKeys);
18
48
  }
19
- return JSON.stringify(result, null, 2);
49
+ return result;
20
50
  }
21
51
  export function errorHandler(api) {
22
52
  return (error, requestId) => {
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACvE,OAAO,EAAC,WAAW,EAAC,MAAM,WAAW,CAAA;AACrC,OAAO,EAAC,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AACxG,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,EAAC,WAAW,EAAY,MAAM,iBAAiB,CAAA;AAEtD,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,KAAa,EACb,GAAW,EACX,SAAqB,EACrB,UAAmC,EAAE;IAErC,WAAW,CAAC,aAAa,CAAA,WAAW,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;IACvD,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;EAC1C,SAAS,CAAC,CAAC,CAAC,sBAAsB,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;;EAEvE,sBAAsB,CAAC,OAAO,CAAC;KAC5B,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAoB;IAC7C,MAAM,MAAM,GAAc,EAAC,GAAG,SAAS,EAAC,CAAA;IACxC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAA;IACzB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,CAAC,KAAc,EAAE,SAAkB,EAAE,EAAE;QAC5C,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,EAAC,MAAM,EAAC,GAAG,KAAK,CAAC,QAAQ,CAAA;YAC/B,IAAI,YAAY,GAAG,gBAAgB,CAAC,aAAa,CAAA;MACjD,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,6CAClB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,MAAM,MAClD;;EAEJ,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;OAClC,CAAC,CAAA;YACF,IAAI,SAAS,EAAE,CAAC;gBACd,YAAY,IAAI;cACV,SAAS;CACtB,CAAA;YACK,CAAC;YACD,IAAI,WAAkB,CAAA;YACtB,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;gBACjB,WAAW,GAAG,IAAI,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;YACnF,CAAC;iBAAM,CAAC;gBACN,WAAW,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAA;YAC5C,CAAC;YACD,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;YAC/B,OAAO,WAAW,CAAA;QACpB,CAAC;aAAM,CAAC;YACN,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {GraphQLClientError, sanitizedHeadersOutput} from './headers.js'\nimport {sanitizeURL} from './urls.js'\nimport {stringifyMessage, outputContent, outputToken, outputDebug} from '../../../public/node/output.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {ClientError, Variables} from 'graphql-request'\n\nexport function debugLogRequestInfo(\n api: string,\n query: string,\n url: string,\n variables?: Variables,\n headers: {[key: string]: string} = {},\n) {\n outputDebug(outputContent`Sending ${outputToken.json(api)} GraphQL request:\n ${outputToken.raw(query.toString().trim())}\n${variables ? `\\nWith variables:\\n${sanitizeVariables(variables)}\\n` : ''}\nWith request headers:\n${sanitizedHeadersOutput(headers)}\\n\nto ${sanitizeURL(url)}`)\n}\n\nfunction sanitizeVariables(variables: Variables): string {\n const result: Variables = {...variables}\n if ('apiKey' in result) {\n result.apiKey = '*****'\n }\n return JSON.stringify(result, null, 2)\n}\n\nexport function errorHandler(api: string): (error: unknown, requestId?: string) => unknown {\n return (error: unknown, requestId?: string) => {\n if (error instanceof ClientError) {\n const {status} = error.response\n let errorMessage = stringifyMessage(outputContent`\nThe ${outputToken.raw(api)} GraphQL API responded unsuccessfully with${\n status === 200 ? '' : ` the HTTP status ${status} and`\n } errors:\n\n${outputToken.json(error.response.errors)}\n `)\n if (requestId) {\n errorMessage += `\nRequest ID: ${requestId}\n`\n }\n let mappedError: Error\n if (status < 500) {\n mappedError = new GraphQLClientError(errorMessage, status, error.response.errors)\n } else {\n mappedError = new AbortError(errorMessage)\n }\n mappedError.stack = error.stack\n return mappedError\n } else {\n return error\n }\n }\n}\n"]}
1
+ {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"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","sourcesContent":["import {GraphQLClientError, sanitizedHeadersOutput} from './headers.js'\nimport {sanitizeURL} from './urls.js'\nimport {stringifyMessage, outputContent, outputToken, outputDebug} from '../../../public/node/output.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {ClientError, Variables} from 'graphql-request'\n\nexport function debugLogRequestInfo(\n api: string,\n query: string,\n url: string,\n variables?: Variables,\n headers: {[key: string]: string} = {},\n) {\n outputDebug(outputContent`Sending ${outputToken.json(api)} GraphQL request:\n ${outputToken.raw(query.toString().trim())}\n${variables ? `\\nWith variables:\\n${sanitizeVariables(variables)}\\n` : ''}\nWith request headers:\n${sanitizedHeadersOutput(headers)}\\n\nto ${sanitizeURL(url)}`)\n}\n\nexport function sanitizeVariables(variables: Variables): string {\n const result: Variables = {...variables}\n const sensitiveKeys = ['apiKey', 'serialized_script']\n\n const sanitizedResult = sanitizeDeepVariables(result, sensitiveKeys)\n\n return JSON.stringify(sanitizedResult, null, 2)\n}\n\nfunction sanitizeDeepVariables(value: unknown, sensitiveKeys: string[]): unknown {\n // Checking for JSON\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value)\n if (typeof parsed === 'object' && parsed !== null) {\n const sanitized = sanitizeDeepVariables(parsed, sensitiveKeys)\n return JSON.stringify(sanitized, null)\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n return value\n }\n }\n\n if (typeof value !== 'object' || value === null) {\n return value\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeDeepVariables(item, sensitiveKeys))\n }\n\n const result: Variables = {}\n\n for (const [key, val] of Object.entries(value)) {\n if (sensitiveKeys.includes(key) && typeof val === 'string') {\n result[key] = '*****'\n continue\n }\n\n result[key] = sanitizeDeepVariables(val, sensitiveKeys)\n }\n\n return result\n}\n\nexport function errorHandler(api: string): (error: unknown, requestId?: string) => unknown {\n return (error: unknown, requestId?: string) => {\n if (error instanceof ClientError) {\n const {status} = error.response\n let errorMessage = stringifyMessage(outputContent`\nThe ${outputToken.raw(api)} GraphQL API responded unsuccessfully with${\n status === 200 ? '' : ` the HTTP status ${status} and`\n } errors:\n\n${outputToken.json(error.response.errors)}\n `)\n if (requestId) {\n errorMessage += `\nRequest ID: ${requestId}\n`\n }\n let mappedError: Error\n if (status < 500) {\n mappedError = new GraphQLClientError(errorMessage, status, error.response.errors)\n } else {\n mappedError = new AbortError(errorMessage)\n }\n mappedError.stack = error.stack\n return mappedError\n } else {\n return error\n }\n }\n}\n"]}
@@ -3,19 +3,19 @@ interface CacheValue<T> {
3
3
  value: T;
4
4
  timestamp: number;
5
5
  }
6
- export type IntrospectionUrlKey = `identity-introspection-url-${string}`;
7
6
  export type PackageVersionKey = `npm-package-${string}`;
8
7
  export type NotificationsKey = `notifications-${string}`;
9
8
  export type NotificationKey = `notification-${string}`;
9
+ export type GraphQLRequestKey = `q-${string}-${string}-${string}`;
10
10
  type MostRecentOccurrenceKey = `most-recent-occurrence-${string}`;
11
11
  type RateLimitKey = `rate-limited-occurrences-${string}`;
12
- type ExportedKey = IntrospectionUrlKey | PackageVersionKey | NotificationsKey | NotificationKey;
12
+ type ExportedKey = PackageVersionKey | NotificationsKey | NotificationKey | GraphQLRequestKey;
13
13
  interface Cache {
14
- [introspectionUrlKey: IntrospectionUrlKey]: CacheValue<string>;
15
14
  [packageVersionKey: PackageVersionKey]: CacheValue<string>;
16
15
  [notifications: NotificationsKey]: CacheValue<string>;
17
16
  [notification: NotificationKey]: CacheValue<string>;
18
- [MostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
17
+ [graphQLRequestKey: GraphQLRequestKey]: CacheValue<string>;
18
+ [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
19
19
  [rateLimitKey: RateLimitKey]: CacheValue<number[]>;
20
20
  }
21
21
  export interface ConfSchema {
@@ -57,12 +57,13 @@ export declare function cacheStore(key: ExportedKey, value: string, config?: Loc
57
57
  */
58
58
  export declare function cacheRetrieve(key: ExportedKey, config?: LocalStorage<ConfSchema>): CacheValue<string> | undefined;
59
59
  export declare function cacheClear(config?: LocalStorage<ConfSchema>): void;
60
- interface TimeInterval {
60
+ export interface TimeInterval {
61
61
  days?: number;
62
62
  hours?: number;
63
63
  minutes?: number;
64
64
  seconds?: number;
65
65
  }
66
+ export declare function timeIntervalToMilliseconds({ days, hours, minutes, seconds }: TimeInterval): number;
66
67
  /**
67
68
  * Execute a task only if the most recent occurrence of the task is older than the specified timeout.
68
69
  * @param key - The key to use for the cache.
@@ -73,7 +73,7 @@ export function cacheRetrieve(key, config = cliKitStore()) {
73
73
  export function cacheClear(config = cliKitStore()) {
74
74
  config.delete('cache');
75
75
  }
76
- function timeIntervalToMilliseconds({ days = 0, hours = 0, minutes = 0, seconds = 0 }) {
76
+ export function timeIntervalToMilliseconds({ days = 0, hours = 0, minutes = 0, seconds = 0 }) {
77
77
  return (days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds) * 1000;
78
78
  }
79
79
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '@shopify/cli-kit/node/output'\n\ninterface CacheValue<T> {\n value: T\n timestamp: number\n}\n\nexport type IntrospectionUrlKey = `identity-introspection-url-${string}`\nexport type PackageVersionKey = `npm-package-${string}`\nexport type NotificationsKey = `notifications-${string}`\nexport type NotificationKey = `notification-${string}`\ntype MostRecentOccurrenceKey = `most-recent-occurrence-${string}`\ntype RateLimitKey = `rate-limited-occurrences-${string}`\n\ntype ExportedKey = IntrospectionUrlKey | PackageVersionKey | NotificationsKey | NotificationKey\n\ninterface Cache {\n [introspectionUrlKey: IntrospectionUrlKey]: CacheValue<string>\n [packageVersionKey: PackageVersionKey]: CacheValue<string>\n [notifications: NotificationsKey]: CacheValue<string>\n [notification: NotificationKey]: CacheValue<string>\n [MostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>\n [rateLimitKey: RateLimitKey]: CacheValue<number[]>\n}\n\nexport interface ConfSchema {\n sessionStore: string\n cache?: Cache\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n if (!_instance) {\n _instance = new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n }\n return _instance\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSession(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get('sessionStore')\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSession(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set('sessionStore', session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSession(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete('sessionStore')\n}\n\ntype CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value']\n\n/**\n * Fetch from cache, or run the provided function to get the value, and cache it\n * before returning it.\n * @param key - The key to use for the cache.\n * @param fn - The function to run to get the value to cache, if a cache miss occurs.\n * @param timeout - The maximum valid age of a cached value, in milliseconds.\n * If the cached value is older than this, it will be refreshed.\n * @returns The value from the cache or the result of the function.\n */\nexport async function cacheRetrieveOrRepopulate(\n key: ExportedKey,\n fn: () => Promise<CacheValueForKey<typeof key>>,\n timeout?: number,\n config = cliKitStore(),\n): Promise<CacheValueForKey<typeof key>> {\n const cached = cacheRetrieve(key, config)\n\n if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {\n return cached.value\n }\n\n const value = await fn()\n cacheStore(key, value, config)\n return value\n}\n\nexport function cacheStore(key: ExportedKey, value: string, config = cliKitStore()): void {\n const cache: Cache = config.get('cache') || {}\n cache[key] = {value, timestamp: Date.now()}\n config.set('cache', cache)\n}\n\n/**\n * Fetch from cache if already populated, otherwise return undefined.\n * @param key - The key to use for the cache.\n * @returns The chache element.\n */\nexport function cacheRetrieve(key: ExportedKey, config = cliKitStore()): CacheValue<string> | undefined {\n const cache: Cache = config.get('cache') || {}\n return cache[key]\n}\n\nexport function cacheClear(config = cliKitStore()): void {\n config.delete('cache')\n}\n\ninterface TimeInterval {\n days?: number\n hours?: number\n minutes?: number\n seconds?: number\n}\n\nfunction timeIntervalToMilliseconds({days = 0, hours = 0, minutes = 0, seconds = 0}: TimeInterval): number {\n return (days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds) * 1000\n}\n\n/**\n * Execute a task only if the most recent occurrence of the task is older than the specified timeout.\n * @param key - The key to use for the cache.\n * @param timeout - The maximum valid age of the most recent occurrence, expressed as an object with\n * days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n * @param task - The task to run if the most recent occurrence is older than the timeout.\n * @returns true if the task was run, or false if the task was not run.\n */\nexport async function runAtMinimumInterval(\n key: string,\n timeout: TimeInterval,\n task: () => Promise<void>,\n config = cliKitStore(),\n): Promise<boolean> {\n const cache: Cache = config.get('cache') || {}\n const cacheKey: MostRecentOccurrenceKey = `most-recent-occurrence-${key}`\n const cached = cache[cacheKey]\n\n if (cached?.value !== undefined && Date.now() - cached.timestamp < timeIntervalToMilliseconds(timeout)) {\n return false\n }\n\n await task()\n cache[cacheKey] = {value: true, timestamp: Date.now()}\n config.set('cache', cache)\n return true\n}\n\ninterface RunWithRateLimitOptions {\n /**\n * The key to use for the cache.\n */\n key: string\n\n /**\n * The number of times the task can be run within the limit\n */\n limit: number\n\n /**\n * The window of time after which the rate limit is refreshed,\n * expressed as an object with days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n */\n timeout: TimeInterval\n\n /**\n * The task to run if the most recent occurrence is older than the timeout.\n */\n task: () => Promise<void>\n}\n\n/**\n * Execute a task with a time-based rate limit. The rate limit is enforced by\n * checking how many times that task has been executed in a window of time ending\n * at the current time. If the task has been executed more than the allowed number\n * of times in that window, the task will not be executed.\n *\n * Note that this function has side effects, as it will also remove events prior\n * to the window of time that is being checked.\n * @param options - The options for the rate limiting.\n * @returns true, or undefined if the task was not run.\n */\nexport async function runWithRateLimit(options: RunWithRateLimitOptions, config = cliKitStore()): Promise<boolean> {\n const {key, limit, timeout, task} = options\n const cache: Cache = config.get('cache') || {}\n const cacheKey: RateLimitKey = `rate-limited-occurrences-${key}`\n const cached = cache[cacheKey]\n const now = Date.now()\n\n if (cached?.value) {\n // First sweep through the cache and eliminate old events\n const windowStart = now - timeIntervalToMilliseconds(timeout)\n const occurrences = cached.value.filter((occurrence) => occurrence >= windowStart)\n\n // Now check that the number of occurrences within the interval is below the limit\n if (occurrences.length >= limit) {\n // First remove the old occurrences from the cache\n cache[cacheKey] = {value: occurrences, timestamp: Date.now()}\n config.set('cache', cache)\n\n return false\n }\n\n await task()\n cache[cacheKey] = {value: [...occurrences, now], timestamp: now}\n } else {\n await task()\n cache[cacheKey] = {value: [now], timestamp: now}\n }\n config.set('cache', cache)\n\n return true\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<{[partnerToken: string]: {status: true; checkedAt: string}}>({\n projectName: 'shopify-cli-kit-partner-status',\n })\n}\n\nexport function getCachedPartnerAccountStatus(partnersToken: string): true | null {\n if (!partnersToken) return null\n const store = getConfigStoreForPartnerStatus()\n\n const hasPartnerAccount = store.get(partnersToken)\n if (hasPartnerAccount) {\n // this never needs to expire\n return true\n }\n return null\n}\n\nexport function setCachedPartnerAccountStatus(partnersToken: string) {\n const store = getConfigStoreForPartnerStatus()\n\n store.set(partnersToken, {status: true, checkedAt: new Date().toISOString()})\n}\n"]}
1
+ {"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '@shopify/cli-kit/node/output'\n\ninterface CacheValue<T> {\n value: T\n timestamp: number\n}\n\nexport type PackageVersionKey = `npm-package-${string}`\nexport type NotificationsKey = `notifications-${string}`\nexport type NotificationKey = `notification-${string}`\nexport type GraphQLRequestKey = `q-${string}-${string}-${string}`\ntype MostRecentOccurrenceKey = `most-recent-occurrence-${string}`\ntype RateLimitKey = `rate-limited-occurrences-${string}`\n\ntype ExportedKey = PackageVersionKey | NotificationsKey | NotificationKey | GraphQLRequestKey\n\ninterface Cache {\n [packageVersionKey: PackageVersionKey]: CacheValue<string>\n [notifications: NotificationsKey]: CacheValue<string>\n [notification: NotificationKey]: CacheValue<string>\n [graphQLRequestKey: GraphQLRequestKey]: CacheValue<string>\n [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>\n [rateLimitKey: RateLimitKey]: CacheValue<number[]>\n}\n\nexport interface ConfSchema {\n sessionStore: string\n cache?: Cache\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n if (!_instance) {\n _instance = new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n }\n return _instance\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSession(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get('sessionStore')\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSession(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set('sessionStore', session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSession(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete('sessionStore')\n}\n\ntype CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value']\n\n/**\n * Fetch from cache, or run the provided function to get the value, and cache it\n * before returning it.\n * @param key - The key to use for the cache.\n * @param fn - The function to run to get the value to cache, if a cache miss occurs.\n * @param timeout - The maximum valid age of a cached value, in milliseconds.\n * If the cached value is older than this, it will be refreshed.\n * @returns The value from the cache or the result of the function.\n */\nexport async function cacheRetrieveOrRepopulate(\n key: ExportedKey,\n fn: () => Promise<CacheValueForKey<typeof key>>,\n timeout?: number,\n config = cliKitStore(),\n): Promise<CacheValueForKey<typeof key>> {\n const cached = cacheRetrieve(key, config)\n\n if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {\n return cached.value\n }\n\n const value = await fn()\n cacheStore(key, value, config)\n return value\n}\n\nexport function cacheStore(key: ExportedKey, value: string, config = cliKitStore()): void {\n const cache: Cache = config.get('cache') || {}\n cache[key] = {value, timestamp: Date.now()}\n config.set('cache', cache)\n}\n\n/**\n * Fetch from cache if already populated, otherwise return undefined.\n * @param key - The key to use for the cache.\n * @returns The chache element.\n */\nexport function cacheRetrieve(key: ExportedKey, config = cliKitStore()): CacheValue<string> | undefined {\n const cache: Cache = config.get('cache') || {}\n return cache[key]\n}\n\nexport function cacheClear(config = cliKitStore()): void {\n config.delete('cache')\n}\n\nexport interface TimeInterval {\n days?: number\n hours?: number\n minutes?: number\n seconds?: number\n}\n\nexport function timeIntervalToMilliseconds({days = 0, hours = 0, minutes = 0, seconds = 0}: TimeInterval): number {\n return (days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds) * 1000\n}\n\n/**\n * Execute a task only if the most recent occurrence of the task is older than the specified timeout.\n * @param key - The key to use for the cache.\n * @param timeout - The maximum valid age of the most recent occurrence, expressed as an object with\n * days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n * @param task - The task to run if the most recent occurrence is older than the timeout.\n * @returns true if the task was run, or false if the task was not run.\n */\nexport async function runAtMinimumInterval(\n key: string,\n timeout: TimeInterval,\n task: () => Promise<void>,\n config = cliKitStore(),\n): Promise<boolean> {\n const cache: Cache = config.get('cache') || {}\n const cacheKey: MostRecentOccurrenceKey = `most-recent-occurrence-${key}`\n const cached = cache[cacheKey]\n\n if (cached?.value !== undefined && Date.now() - cached.timestamp < timeIntervalToMilliseconds(timeout)) {\n return false\n }\n\n await task()\n cache[cacheKey] = {value: true, timestamp: Date.now()}\n config.set('cache', cache)\n return true\n}\n\ninterface RunWithRateLimitOptions {\n /**\n * The key to use for the cache.\n */\n key: string\n\n /**\n * The number of times the task can be run within the limit\n */\n limit: number\n\n /**\n * The window of time after which the rate limit is refreshed,\n * expressed as an object with days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n */\n timeout: TimeInterval\n\n /**\n * The task to run if the most recent occurrence is older than the timeout.\n */\n task: () => Promise<void>\n}\n\n/**\n * Execute a task with a time-based rate limit. The rate limit is enforced by\n * checking how many times that task has been executed in a window of time ending\n * at the current time. If the task has been executed more than the allowed number\n * of times in that window, the task will not be executed.\n *\n * Note that this function has side effects, as it will also remove events prior\n * to the window of time that is being checked.\n * @param options - The options for the rate limiting.\n * @returns true, or undefined if the task was not run.\n */\nexport async function runWithRateLimit(options: RunWithRateLimitOptions, config = cliKitStore()): Promise<boolean> {\n const {key, limit, timeout, task} = options\n const cache: Cache = config.get('cache') || {}\n const cacheKey: RateLimitKey = `rate-limited-occurrences-${key}`\n const cached = cache[cacheKey]\n const now = Date.now()\n\n if (cached?.value) {\n // First sweep through the cache and eliminate old events\n const windowStart = now - timeIntervalToMilliseconds(timeout)\n const occurrences = cached.value.filter((occurrence) => occurrence >= windowStart)\n\n // Now check that the number of occurrences within the interval is below the limit\n if (occurrences.length >= limit) {\n // First remove the old occurrences from the cache\n cache[cacheKey] = {value: occurrences, timestamp: Date.now()}\n config.set('cache', cache)\n\n return false\n }\n\n await task()\n cache[cacheKey] = {value: [...occurrences, now], timestamp: now}\n } else {\n await task()\n cache[cacheKey] = {value: [now], timestamp: now}\n }\n config.set('cache', cache)\n\n return true\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<{[partnerToken: string]: {status: true; checkedAt: string}}>({\n projectName: 'shopify-cli-kit-partner-status',\n })\n}\n\nexport function getCachedPartnerAccountStatus(partnersToken: string): true | null {\n if (!partnersToken) return null\n const store = getConfigStoreForPartnerStatus()\n\n const hasPartnerAccount = store.get(partnersToken)\n if (hasPartnerAccount) {\n // this never needs to expire\n return true\n }\n return null\n}\n\nexport function setCachedPartnerAccountStatus(partnersToken: string) {\n const store = getConfigStoreForPartnerStatus()\n\n store.set(partnersToken, {status: true, checkedAt: new Date().toISOString()})\n}\n"]}
@@ -39,14 +39,22 @@ export async function requestDeviceAuthorization(scopes) {
39
39
  }
40
40
  outputInfo(outputContent `User verification code: ${jsonResult.user_code}`);
41
41
  const linkToken = outputToken.link(jsonResult.verification_uri_complete);
42
- if (isCloudEnvironment()) {
42
+ const cloudMessage = () => {
43
43
  outputInfo(outputContent `👉 Open this link to start the auth process: ${linkToken}`);
44
+ };
45
+ if (isCloudEnvironment()) {
46
+ cloudMessage();
44
47
  }
45
48
  else {
46
49
  outputInfo('👉 Press any key to open the login page on your browser');
47
50
  await keypress();
48
- await openURL(jsonResult.verification_uri_complete);
49
- outputInfo(outputContent `Opened link to start the auth process: ${linkToken}`);
51
+ const opened = await openURL(jsonResult.verification_uri_complete);
52
+ if (opened) {
53
+ outputInfo(outputContent `Opened link to start the auth process: ${linkToken}`);
54
+ }
55
+ else {
56
+ cloudMessage();
57
+ }
50
58
  }
51
59
  return {
52
60
  deviceCode: jsonResult.device_code,
@@ -1 +1 @@
1
- {"version":3,"file":"device-authorization.js","sourceRoot":"","sources":["../../../../src/private/node/session/device-authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import {clientId} from './identity.js'\nimport {exchangeDeviceCodeForAccessToken} from './exchange.js'\nimport {IdentityToken} from './schema.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {outputContent, outputDebug, outputInfo, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../../../public/node/error.js'\nimport {isCloudEnvironment} from '../../../public/node/context/local.js'\nimport {openURL} from '../../../public/node/system.js'\nimport {isTTY, keypress} from '../../../public/node/ui.js'\n\nexport interface DeviceAuthorizationResponse {\n deviceCode: string\n userCode: string\n verificationUri: string\n expiresIn: number\n verificationUriComplete?: string\n interval?: number\n}\n\n/**\n * Initiate a device authorization flow.\n * This will return a DeviceAuthorizationResponse containing the URL where user\n * should go to authorize the device without the need of a callback to the CLI.\n *\n * Also returns a `deviceCode` used for polling the token endpoint in the next step.\n *\n * @param scopes - The scopes to request\n * @returns An object with the device authorization response.\n */\nexport async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {\n const fqdn = await identityFqdn()\n const identityClientId = clientId()\n const queryParams = {client_id: identityClientId, scope: scopes.join(' ')}\n const url = `https://${fqdn}/oauth/device_authorization`\n\n const response = await shopifyFetch(url, {\n method: 'POST',\n headers: {'Content-type': 'application/x-www-form-urlencoded'},\n body: convertRequestToParams(queryParams),\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonResult: any = await response.json()\n\n outputDebug(outputContent`Received device authorization code: ${outputToken.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) {\n throw new BugError('Failed to start authorization process')\n }\n\n outputInfo('\\nTo run this command, log in to Shopify.')\n\n if (!isTTY()) {\n throw new AbortError(\n 'Authorization is required to continue, but the current environment does not support interactive prompts.',\n 'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.',\n )\n }\n\n outputInfo(outputContent`User verification code: ${jsonResult.user_code}`)\n const linkToken = outputToken.link(jsonResult.verification_uri_complete)\n\n if (isCloudEnvironment()) {\n outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`)\n } else {\n outputInfo('👉 Press any key to open the login page on your browser')\n await keypress()\n await openURL(jsonResult.verification_uri_complete)\n outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`)\n }\n\n return {\n deviceCode: jsonResult.device_code,\n userCode: jsonResult.user_code,\n verificationUri: jsonResult.verification_uri,\n expiresIn: jsonResult.expires_in,\n verificationUriComplete: jsonResult.verification_uri_complete,\n interval: jsonResult.interval,\n }\n}\n\n/**\n * Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.\n * The endpoint will return `authorization_pending` until the user completes the auth flow in the browser.\n * Once the user completes the auth flow, the endpoint will return the identity token.\n *\n * Timeout for the polling is defined by the server and is around 600 seconds.\n *\n * @param code - The device code obtained after starting a device identity flow\n * @param interval - The interval to poll the token endpoint\n * @returns The identity token\n */\nexport async function pollForDeviceAuthorization(code: string, interval = 5): Promise<IdentityToken> {\n let currentIntervalInSeconds = interval\n\n return new Promise<IdentityToken>((resolve, reject) => {\n const onPoll = async () => {\n const result = await exchangeDeviceCodeForAccessToken(code)\n if (!result.isErr()) {\n resolve(result.value)\n return\n }\n\n const error = result.error ?? 'unknown_failure'\n\n outputDebug(outputContent`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending': {\n startPolling()\n return\n }\n case 'slow_down':\n currentIntervalInSeconds += 5\n {\n startPolling()\n return\n }\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure': {\n reject(result)\n }\n }\n }\n\n const startPolling = () => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n setTimeout(onPoll, currentIntervalInSeconds * 1000)\n }\n\n startPolling()\n })\n}\n\nfunction convertRequestToParams(queryParams: {client_id: string; scope: string}): string {\n return Object.entries(queryParams)\n .map(([key, value]) => value && `${key}=${value}`)\n .filter((hasValue) => Boolean(hasValue))\n .join('&')\n}\n"]}
1
+ {"version":3,"file":"device-authorization.js","sourceRoot":"","sources":["../../../../src/private/node/session/device-authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AACtC,OAAO,EAAC,gCAAgC,EAAC,MAAM,eAAe,CAAA;AAE9D,OAAO,EAAC,YAAY,EAAC,MAAM,sCAAsC,CAAA;AACjE,OAAO,EAAC,YAAY,EAAC,MAAM,8BAA8B,CAAA;AACzD,OAAO,EAAC,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AAClG,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAC,MAAM,+BAA+B,CAAA;AAClE,OAAO,EAAC,kBAAkB,EAAC,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAA;AACtD,OAAO,EAAC,KAAK,EAAE,QAAQ,EAAC,MAAM,4BAA4B,CAAA;AAW1D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,MAAgB;IAC/D,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAA;IACjC,MAAM,gBAAgB,GAAG,QAAQ,EAAE,CAAA;IACnC,MAAM,WAAW,GAAG,EAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAC,CAAA;IAC1E,MAAM,GAAG,GAAG,WAAW,IAAI,6BAA6B,CAAA;IAExD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;QACvC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAC,cAAc,EAAE,mCAAmC,EAAC;QAC9D,IAAI,EAAE,sBAAsB,CAAC,WAAW,CAAC;KAC1C,CAAC,CAAA;IAEF,8DAA8D;IAC9D,MAAM,UAAU,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAE7C,WAAW,CAAC,aAAa,CAAA,uCAAuC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IAC/F,IAAI,CAAC,UAAU,CAAC,WAAW,IAAI,CAAC,UAAU,CAAC,yBAAyB,EAAE,CAAC;QACrE,MAAM,IAAI,QAAQ,CAAC,uCAAuC,CAAC,CAAA;IAC7D,CAAC;IAED,UAAU,CAAC,2CAA2C,CAAC,CAAA;IAEvD,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,UAAU,CAClB,0GAA0G,EAC1G,yIAAyI,CAC1I,CAAA;IACH,CAAC;IAED,UAAU,CAAC,aAAa,CAAA,2BAA2B,UAAU,CAAC,SAAS,EAAE,CAAC,CAAA;IAC1E,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAA;IAExE,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,UAAU,CAAC,aAAa,CAAA,gDAAgD,SAAS,EAAE,CAAC,CAAA;IACtF,CAAC,CAAA;IAED,IAAI,kBAAkB,EAAE,EAAE,CAAC;QACzB,YAAY,EAAE,CAAA;IAChB,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,yDAAyD,CAAC,CAAA;QACrE,MAAM,QAAQ,EAAE,CAAA;QAChB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAA;QAClE,IAAI,MAAM,EAAE,CAAC;YACX,UAAU,CAAC,aAAa,CAAA,0CAA0C,SAAS,EAAE,CAAC,CAAA;QAChF,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAA;QAChB,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAE,UAAU,CAAC,WAAW;QAClC,QAAQ,EAAE,UAAU,CAAC,SAAS;QAC9B,eAAe,EAAE,UAAU,CAAC,gBAAgB;QAC5C,SAAS,EAAE,UAAU,CAAC,UAAU;QAChC,uBAAuB,EAAE,UAAU,CAAC,yBAAyB;QAC7D,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAA;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,IAAY,EAAE,QAAQ,GAAG,CAAC;IACzE,IAAI,wBAAwB,GAAG,QAAQ,CAAA;IAEvC,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,MAAM,MAAM,GAAG,MAAM,gCAAgC,CAAC,IAAI,CAAC,CAAA;YAC3D,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACrB,OAAM;YACR,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,iBAAiB,CAAA;YAE/C,WAAW,CAAC,aAAa,CAAA,+CAA+C,KAAK,EAAE,CAAC,CAAA;YAChF,QAAQ,KAAK,EAAE,CAAC;gBACd,KAAK,uBAAuB,CAAC,CAAC,CAAC;oBAC7B,YAAY,EAAE,CAAA;oBACd,OAAM;gBACR,CAAC;gBACD,KAAK,WAAW;oBACd,wBAAwB,IAAI,CAAC,CAAA;oBAC7B,CAAC;wBACC,YAAY,EAAE,CAAA;wBACd,OAAM;oBACR,CAAC;gBACH,KAAK,eAAe,CAAC;gBACrB,KAAK,eAAe,CAAC;gBACrB,KAAK,iBAAiB,CAAC,CAAC,CAAC;oBACvB,MAAM,CAAC,MAAM,CAAC,CAAA;gBAChB,CAAC;YACH,CAAC;QACH,CAAC,CAAA;QAED,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,kEAAkE;YAClE,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAAC,CAAA;QACrD,CAAC,CAAA;QAED,YAAY,EAAE,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,WAA+C;IAC7E,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;SACjD,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SACvC,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC","sourcesContent":["import {clientId} from './identity.js'\nimport {exchangeDeviceCodeForAccessToken} from './exchange.js'\nimport {IdentityToken} from './schema.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {outputContent, outputDebug, outputInfo, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../../../public/node/error.js'\nimport {isCloudEnvironment} from '../../../public/node/context/local.js'\nimport {openURL} from '../../../public/node/system.js'\nimport {isTTY, keypress} from '../../../public/node/ui.js'\n\nexport interface DeviceAuthorizationResponse {\n deviceCode: string\n userCode: string\n verificationUri: string\n expiresIn: number\n verificationUriComplete?: string\n interval?: number\n}\n\n/**\n * Initiate a device authorization flow.\n * This will return a DeviceAuthorizationResponse containing the URL where user\n * should go to authorize the device without the need of a callback to the CLI.\n *\n * Also returns a `deviceCode` used for polling the token endpoint in the next step.\n *\n * @param scopes - The scopes to request\n * @returns An object with the device authorization response.\n */\nexport async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {\n const fqdn = await identityFqdn()\n const identityClientId = clientId()\n const queryParams = {client_id: identityClientId, scope: scopes.join(' ')}\n const url = `https://${fqdn}/oauth/device_authorization`\n\n const response = await shopifyFetch(url, {\n method: 'POST',\n headers: {'Content-type': 'application/x-www-form-urlencoded'},\n body: convertRequestToParams(queryParams),\n })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const jsonResult: any = await response.json()\n\n outputDebug(outputContent`Received device authorization code: ${outputToken.json(jsonResult)}`)\n if (!jsonResult.device_code || !jsonResult.verification_uri_complete) {\n throw new BugError('Failed to start authorization process')\n }\n\n outputInfo('\\nTo run this command, log in to Shopify.')\n\n if (!isTTY()) {\n throw new AbortError(\n 'Authorization is required to continue, but the current environment does not support interactive prompts.',\n 'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.',\n )\n }\n\n outputInfo(outputContent`User verification code: ${jsonResult.user_code}`)\n const linkToken = outputToken.link(jsonResult.verification_uri_complete)\n\n const cloudMessage = () => {\n outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`)\n }\n\n if (isCloudEnvironment()) {\n cloudMessage()\n } else {\n outputInfo('👉 Press any key to open the login page on your browser')\n await keypress()\n const opened = await openURL(jsonResult.verification_uri_complete)\n if (opened) {\n outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`)\n } else {\n cloudMessage()\n }\n }\n\n return {\n deviceCode: jsonResult.device_code,\n userCode: jsonResult.user_code,\n verificationUri: jsonResult.verification_uri,\n expiresIn: jsonResult.expires_in,\n verificationUriComplete: jsonResult.verification_uri_complete,\n interval: jsonResult.interval,\n }\n}\n\n/**\n * Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.\n * The endpoint will return `authorization_pending` until the user completes the auth flow in the browser.\n * Once the user completes the auth flow, the endpoint will return the identity token.\n *\n * Timeout for the polling is defined by the server and is around 600 seconds.\n *\n * @param code - The device code obtained after starting a device identity flow\n * @param interval - The interval to poll the token endpoint\n * @returns The identity token\n */\nexport async function pollForDeviceAuthorization(code: string, interval = 5): Promise<IdentityToken> {\n let currentIntervalInSeconds = interval\n\n return new Promise<IdentityToken>((resolve, reject) => {\n const onPoll = async () => {\n const result = await exchangeDeviceCodeForAccessToken(code)\n if (!result.isErr()) {\n resolve(result.value)\n return\n }\n\n const error = result.error ?? 'unknown_failure'\n\n outputDebug(outputContent`Polling for device authorization... status: ${error}`)\n switch (error) {\n case 'authorization_pending': {\n startPolling()\n return\n }\n case 'slow_down':\n currentIntervalInSeconds += 5\n {\n startPolling()\n return\n }\n case 'access_denied':\n case 'expired_token':\n case 'unknown_failure': {\n reject(result)\n }\n }\n }\n\n const startPolling = () => {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n setTimeout(onPoll, currentIntervalInSeconds * 1000)\n }\n\n startPolling()\n })\n}\n\nfunction convertRequestToParams(queryParams: {client_id: string; scope: string}): string {\n return Object.entries(queryParams)\n .map(([key, value]) => value && `${key}=${value}`)\n .filter((hasValue) => Boolean(hasValue))\n .join('&')\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
2
  import { applicationId } from './identity.js';
3
3
  import { validateCachedIdentityTokenStructure } from './schema.js';
4
- import { validateIdentityToken } from './identity-token-validation.js';
5
4
  import { sessionConstants } from '../constants.js';
6
5
  import { firstPartyDev } from '../../../public/node/context/local.js';
7
6
  import { outputDebug } from '@shopify/cli-kit/node/output';
@@ -55,10 +54,6 @@ export async function validateSession(scopes, applications, session) {
55
54
  }
56
55
  if (tokensAreExpired)
57
56
  return 'needs_refresh';
58
- const identityIsValid = await validateIdentityToken(session.identity.accessToken);
59
- outputDebug(`- Token validation -> It's invalid in identity: ${!identityIsValid}`);
60
- if (!identityIsValid)
61
- return 'needs_full_auth';
62
57
  return 'ok';
63
58
  }
64
59
  function isTokenExpired(token) {
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken, validateCachedIdentityTokenStructure} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\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 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(`- Token validation -> It's expired: ${tokensAreExpired}`)\n\n if (!validateCachedIdentityTokenStructure(session.identity)) {\n return 'needs_full_auth'\n }\n\n if (tokensAreExpired) return 'needs_refresh'\n\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n outputDebug(`- Token validation -> It's invalid in identity: ${!identityIsValid}`)\n if (!identityIsValid) return 'needs_full_auth'\n\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken, validateCachedIdentityTokenStructure} from './schema.js'\nimport {sessionConstants} from '../constants.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {OAuthApplications} from '../session.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\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 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(`- Token validation -> It's expired: ${tokensAreExpired}`)\n\n if (!validateCachedIdentityTokenStructure(session.identity)) {\n return 'needs_full_auth'\n }\n\n if (tokensAreExpired) return 'needs_refresh'\n\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 +1 @@
1
- export declare const CLI_KIT_VERSION = "3.75.4";
1
+ export declare const CLI_KIT_VERSION = "3.76.1";
@@ -1,2 +1,2 @@
1
- export const CLI_KIT_VERSION = '3.75.4';
1
+ export const CLI_KIT_VERSION = '3.76.1';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.75.4'\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.76.1'\n"]}
@@ -1,6 +1,6 @@
1
1
  import { graphqlRequest, graphqlRequestDoc } from './graphql.js';
2
2
  import { outputContent, outputToken } from '../../../public/node/output.js';
3
- import { BugError, AbortError } from '../error.js';
3
+ import { AbortError, BugError } from '../error.js';
4
4
  import { restRequestBody, restRequestHeaders, restRequestUrl, isThemeAccessSession, } from '../../../private/node/api/rest.js';
5
5
  import { fetch } from '../http.js';
6
6
  import { PublicApiVersions } from '../../../cli/api/graphql/admin/generated/public_api_versions.js';
@@ -107,8 +107,8 @@ async function fetchApiVersions(session) {
107
107
  const storeName = session.storeFqdn.replace('.myshopify.com', '');
108
108
  throw new AbortError(outputContent `Looks like you don't have access this dev store: (${outputToken.link(storeName, `https://${session.storeFqdn}`)})`, outputContent `If you're not the owner, create a dev store staff account for yourself`);
109
109
  }
110
- else if (error instanceof ClientError) {
111
- throw new BugError(`Unknown client error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`);
110
+ if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {
111
+ throw new AbortError(`Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`);
112
112
  }
113
113
  else {
114
114
  throw new BugError(`Unknown error connecting to your store ${session.storeFqdn}: ${error instanceof Error ? error.message : String(error)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../src/public/node/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {graphqlRequest, graphqlRequestDoc, GraphQLResponseOptions, GraphQLVariables} from './graphql.js'\nimport {AdminSession} from '../session.js'\nimport {outputContent, outputToken} from '../../../public/node/output.js'\nimport {BugError, AbortError} from '../error.js'\nimport {\n restRequestBody,\n restRequestHeaders,\n restRequestUrl,\n isThemeAccessSession,\n} from '../../../private/node/api/rest.js'\nimport {fetch} from '../http.js'\nimport {PublicApiVersions} from '../../../cli/api/graphql/admin/generated/public_api_versions.js'\nimport {normalizeStoreFqdn} from '../context/fqdn.js'\nimport {themeKitAccessDomain} from '../../../private/node/constants.js'\nimport {ClientError, Variables} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\n\nconst LatestApiVersionByFQDN = new Map<string, string>()\n\n/**\n * Executes a GraphQL query against the Admin API.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @returns The response of the query of generic type <T>.\n */\nexport async function adminRequest<T>(query: string, session: AdminSession, variables?: GraphQLVariables): Promise<T> {\n const api = 'Admin'\n const version = await fetchLatestSupportedApiVersion(session)\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const url = adminUrl(store, version, session)\n const addedHeaders = themeAccessHeaders(session)\n return graphqlRequest({query, api, addedHeaders, url, token: session.token, variables})\n}\n\n/**\n * Executes a GraphQL query against the Admin API. Uses typed documents.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @param version - API version.\n * @param responseOptions - Control how API responses will be handled.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function adminRequestDoc<TResult, TVariables extends Variables>(\n query: TypedDocumentNode<TResult, TVariables>,\n session: AdminSession,\n variables?: TVariables,\n version?: string,\n responseOptions?: GraphQLResponseOptions<TResult>,\n): Promise<TResult> {\n let apiVersion = version ?? LatestApiVersionByFQDN.get(session.storeFqdn)\n if (!apiVersion) {\n apiVersion = await fetchLatestSupportedApiVersion(session)\n }\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const addedHeaders = themeAccessHeaders(session)\n const opts = {\n url: adminUrl(store, apiVersion, session),\n api: 'Admin',\n token: session.token,\n addedHeaders,\n }\n let unauthorizedHandler\n if ('refresh' in session) {\n unauthorizedHandler = session.refresh as () => Promise<void>\n }\n const result = graphqlRequestDoc<TResult, TVariables>({\n ...opts,\n query,\n variables,\n responseOptions,\n unauthorizedHandler,\n })\n return result\n}\n\nfunction themeAccessHeaders(session: AdminSession): {[header: string]: string} {\n return isThemeAccessSession(session)\n ? {'X-Shopify-Shop': session.storeFqdn, 'X-Shopify-Access-Token': session.token}\n : {}\n}\n\n/**\n * GraphQL query to retrieve the latest supported API version.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - The latest supported API version.\n */\nasync function fetchLatestSupportedApiVersion(session: AdminSession): Promise<string> {\n const apiVersions = await supportedApiVersions(session)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const latest = apiVersions.reverse()[0]!\n LatestApiVersionByFQDN.set(session.storeFqdn, latest)\n return latest\n}\n\n/**\n * GraphQL query to retrieve all supported API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported API versions.\n */\nexport async function supportedApiVersions(session: AdminSession): Promise<string[]> {\n const apiVersions = await fetchApiVersions(session)\n return apiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n}\n\n/**\n * GraphQL query to retrieve all API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported and unsupported API versions.\n */\nasync function fetchApiVersions(session: AdminSession): Promise<ApiVersion[]> {\n try {\n const response = await adminRequestDoc(PublicApiVersions, session, {}, 'unstable', {handleErrors: false})\n return response.publicApiVersions\n } catch (error) {\n if (error instanceof ClientError && error.response.status === 403) {\n const storeName = session.storeFqdn.replace('.myshopify.com', '')\n throw new AbortError(\n outputContent`Looks like you don't have access this dev store: (${outputToken.link(\n storeName,\n `https://${session.storeFqdn}`,\n )})`,\n outputContent`If you're not the owner, create a dev store staff account for yourself`,\n )\n } else if (error instanceof ClientError) {\n throw new BugError(\n `Unknown client error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`,\n )\n } else {\n throw new BugError(\n `Unknown error connecting to your store ${session.storeFqdn}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n}\n\n/**\n * Returns the Admin API URL for the given store and version.\n *\n * @param store - Store FQDN.\n * @param version - API version.\n * @param session - User session.\n * @returns - Admin API URL.\n */\nexport function adminUrl(store: string, version: string | undefined, session?: AdminSession): string {\n const realVersion = version ?? 'unstable'\n\n const url =\n session && isThemeAccessSession(session)\n ? `https://${themeKitAccessDomain}/cli/admin/api/${realVersion}/graphql.json`\n : `https://${store}/admin/api/${realVersion}/graphql.json`\n return url\n}\n\ninterface ApiVersion {\n handle: string\n supported: boolean\n}\n\n/**\n * Executes a REST request against the Admin API.\n *\n * @param method - Request's HTTP method.\n * @param path - Path of the REST resource.\n * @param session - Shopify Admin session including token and Store FQDN.\n * @param requestBody - Request body of including REST resource specific parameters.\n * @param searchParams - Search params, appended to the URL.\n * @param apiVersion - Admin API version.\n * @returns - The {@link RestResponse}.\n */\nexport async function restRequest<T>(\n method: string,\n path: string,\n session: AdminSession,\n requestBody?: T,\n searchParams: {[name: string]: string} = {},\n apiVersion = 'unstable',\n): Promise<RestResponse> {\n const url = restRequestUrl(session, apiVersion, path, searchParams)\n const body = restRequestBody<T>(requestBody)\n\n const headers = restRequestHeaders(session)\n const response = await fetch(url, {\n headers,\n method,\n body,\n })\n\n const json = await response.json().catch(() => ({}))\n\n return {\n json,\n status: response.status,\n headers: response.headers.raw(),\n }\n}\n\n/**\n * Respose of a REST request.\n */\nexport interface RestResponse {\n /**\n * REST JSON respose.\n */\n // Using `any` to avoid introducing extra DTO layers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n json: any\n\n /**\n * HTTP response status.\n */\n status: number\n\n /**\n * HTTP response headers.\n */\n headers: {[key: string]: string[]}\n}\n"]}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../src/public/node/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {graphqlRequest, graphqlRequestDoc, GraphQLResponseOptions, GraphQLVariables} from './graphql.js'\nimport {AdminSession} from '../session.js'\nimport {outputContent, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../error.js'\nimport {\n restRequestBody,\n restRequestHeaders,\n restRequestUrl,\n isThemeAccessSession,\n} from '../../../private/node/api/rest.js'\nimport {fetch} from '../http.js'\nimport {PublicApiVersions} from '../../../cli/api/graphql/admin/generated/public_api_versions.js'\nimport {normalizeStoreFqdn} from '../context/fqdn.js'\nimport {themeKitAccessDomain} from '../../../private/node/constants.js'\nimport {ClientError, Variables} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\n\nconst LatestApiVersionByFQDN = new Map<string, string>()\n\n/**\n * Executes a GraphQL query against the Admin API.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @returns The response of the query of generic type <T>.\n */\nexport async function adminRequest<T>(query: string, session: AdminSession, variables?: GraphQLVariables): Promise<T> {\n const api = 'Admin'\n const version = await fetchLatestSupportedApiVersion(session)\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const url = adminUrl(store, version, session)\n const addedHeaders = themeAccessHeaders(session)\n return graphqlRequest({query, api, addedHeaders, url, token: session.token, variables})\n}\n\n/**\n * Executes a GraphQL query against the Admin API. Uses typed documents.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @param version - API version.\n * @param responseOptions - Control how API responses will be handled.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function adminRequestDoc<TResult, TVariables extends Variables>(\n query: TypedDocumentNode<TResult, TVariables>,\n session: AdminSession,\n variables?: TVariables,\n version?: string,\n responseOptions?: GraphQLResponseOptions<TResult>,\n): Promise<TResult> {\n let apiVersion = version ?? LatestApiVersionByFQDN.get(session.storeFqdn)\n if (!apiVersion) {\n apiVersion = await fetchLatestSupportedApiVersion(session)\n }\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const addedHeaders = themeAccessHeaders(session)\n const opts = {\n url: adminUrl(store, apiVersion, session),\n api: 'Admin',\n token: session.token,\n addedHeaders,\n }\n let unauthorizedHandler\n if ('refresh' in session) {\n unauthorizedHandler = session.refresh as () => Promise<void>\n }\n const result = graphqlRequestDoc<TResult, TVariables>({\n ...opts,\n query,\n variables,\n responseOptions,\n unauthorizedHandler,\n })\n return result\n}\n\nfunction themeAccessHeaders(session: AdminSession): {[header: string]: string} {\n return isThemeAccessSession(session)\n ? {'X-Shopify-Shop': session.storeFqdn, 'X-Shopify-Access-Token': session.token}\n : {}\n}\n\n/**\n * GraphQL query to retrieve the latest supported API version.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - The latest supported API version.\n */\nasync function fetchLatestSupportedApiVersion(session: AdminSession): Promise<string> {\n const apiVersions = await supportedApiVersions(session)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const latest = apiVersions.reverse()[0]!\n LatestApiVersionByFQDN.set(session.storeFqdn, latest)\n return latest\n}\n\n/**\n * GraphQL query to retrieve all supported API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported API versions.\n */\nexport async function supportedApiVersions(session: AdminSession): Promise<string[]> {\n const apiVersions = await fetchApiVersions(session)\n return apiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n}\n\n/**\n * GraphQL query to retrieve all API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported and unsupported API versions.\n */\nasync function fetchApiVersions(session: AdminSession): Promise<ApiVersion[]> {\n try {\n const response = await adminRequestDoc(PublicApiVersions, session, {}, 'unstable', {handleErrors: false})\n return response.publicApiVersions\n } catch (error) {\n if (error instanceof ClientError && error.response.status === 403) {\n const storeName = session.storeFqdn.replace('.myshopify.com', '')\n throw new AbortError(\n outputContent`Looks like you don't have access this dev store: (${outputToken.link(\n storeName,\n `https://${session.storeFqdn}`,\n )})`,\n outputContent`If you're not the owner, create a dev store staff account for yourself`,\n )\n }\n if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {\n throw new AbortError(\n `Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`,\n )\n } else {\n throw new BugError(\n `Unknown error connecting to your store ${session.storeFqdn}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n}\n\n/**\n * Returns the Admin API URL for the given store and version.\n *\n * @param store - Store FQDN.\n * @param version - API version.\n * @param session - User session.\n * @returns - Admin API URL.\n */\nexport function adminUrl(store: string, version: string | undefined, session?: AdminSession): string {\n const realVersion = version ?? 'unstable'\n\n const url =\n session && isThemeAccessSession(session)\n ? `https://${themeKitAccessDomain}/cli/admin/api/${realVersion}/graphql.json`\n : `https://${store}/admin/api/${realVersion}/graphql.json`\n return url\n}\n\ninterface ApiVersion {\n handle: string\n supported: boolean\n}\n\n/**\n * Executes a REST request against the Admin API.\n *\n * @param method - Request's HTTP method.\n * @param path - Path of the REST resource.\n * @param session - Shopify Admin session including token and Store FQDN.\n * @param requestBody - Request body of including REST resource specific parameters.\n * @param searchParams - Search params, appended to the URL.\n * @param apiVersion - Admin API version.\n * @returns - The {@link RestResponse}.\n */\nexport async function restRequest<T>(\n method: string,\n path: string,\n session: AdminSession,\n requestBody?: T,\n searchParams: {[name: string]: string} = {},\n apiVersion = 'unstable',\n): Promise<RestResponse> {\n const url = restRequestUrl(session, apiVersion, path, searchParams)\n const body = restRequestBody<T>(requestBody)\n\n const headers = restRequestHeaders(session)\n const response = await fetch(url, {\n headers,\n method,\n body,\n })\n\n const json = await response.json().catch(() => ({}))\n\n return {\n json,\n status: response.status,\n headers: response.headers.raw(),\n }\n}\n\n/**\n * Respose of a REST request.\n */\nexport interface RestResponse {\n /**\n * REST JSON respose.\n */\n // Using `any` to avoid introducing extra DTO layers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n json: any\n\n /**\n * HTTP response status.\n */\n status: number\n\n /**\n * HTTP response headers.\n */\n headers: {[key: string]: string[]}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { GraphQLResponse } from './graphql.js';
1
+ import { CacheOptions, GraphQLResponse } from './graphql.js';
2
2
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
3
3
  import { Variables } from 'graphql-request';
4
4
  /**
@@ -8,9 +8,10 @@ import { Variables } from 'graphql-request';
8
8
  * @param query - GraphQL query to execute.
9
9
  * @param token - Partners token.
10
10
  * @param variables - GraphQL variables to pass to the query.
11
+ * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
11
12
  * @returns The response of the query of generic type <T>.
12
13
  */
13
- export declare function appManagementRequestDoc<TResult, TVariables extends Variables>(orgId: string, query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables): Promise<TResult>;
14
+ export declare function appManagementRequestDoc<TResult, TVariables extends Variables>(orgId: string, query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, cacheOptions?: CacheOptions): Promise<TResult>;
14
15
  /**
15
16
  * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)
16
17
  * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).
@@ -27,13 +27,18 @@ async function setupRequest(orgId, token) {
27
27
  * @param query - GraphQL query to execute.
28
28
  * @param token - Partners token.
29
29
  * @param variables - GraphQL variables to pass to the query.
30
+ * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
30
31
  * @returns The response of the query of generic type <T>.
31
32
  */
32
- export async function appManagementRequestDoc(orgId, query, token, variables) {
33
+ export async function appManagementRequestDoc(orgId, query, token, variables, cacheOptions) {
34
+ // For app management, we need to cache the response based on the orgId.
35
+ const cacheExtraKey = (cacheOptions?.cacheExtraKey ?? '') + orgId;
36
+ const newCacheOptions = cacheOptions ? { ...cacheOptions, cacheExtraKey } : undefined;
33
37
  const result = limiter.schedule(async () => graphqlRequestDoc({
34
38
  ...(await setupRequest(orgId, token)),
35
39
  query,
36
40
  variables,
41
+ cacheOptions: newCacheOptions,
37
42
  }));
38
43
  return result;
39
44
  }