@shopify/cli-kit 3.3.3 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/analytics.d.ts +11 -5
  3. package/dist/analytics.js +62 -72
  4. package/dist/analytics.js.map +1 -1
  5. package/dist/api/admin.js +20 -34
  6. package/dist/api/admin.js.map +1 -1
  7. package/dist/api/common.d.ts +11 -1
  8. package/dist/api/common.js +50 -6
  9. package/dist/api/common.js.map +1 -1
  10. package/dist/api/identity.js +3 -4
  11. package/dist/api/identity.js.map +1 -1
  12. package/dist/api/partners.d.ts +0 -5
  13. package/dist/api/partners.js +22 -43
  14. package/dist/api/partners.js.map +1 -1
  15. package/dist/array.d.ts +1 -0
  16. package/dist/array.js +4 -0
  17. package/dist/array.js.map +1 -0
  18. package/dist/constants.d.ts +1 -0
  19. package/dist/constants.js +1 -2
  20. package/dist/constants.js.map +1 -1
  21. package/dist/environment/local.d.ts +1 -0
  22. package/dist/environment/local.js +3 -0
  23. package/dist/environment/local.js.map +1 -1
  24. package/dist/environment/service.d.ts +2 -1
  25. package/dist/environment/service.js +16 -0
  26. package/dist/environment/service.js.map +1 -1
  27. package/dist/error.d.ts +5 -0
  28. package/dist/error.js +10 -4
  29. package/dist/error.js.map +1 -1
  30. package/dist/file.d.ts +3 -1
  31. package/dist/file.js +14 -2
  32. package/dist/file.js.map +1 -1
  33. package/dist/git.js +12 -5
  34. package/dist/git.js.map +1 -1
  35. package/dist/haiku.d.ts +6 -1
  36. package/dist/haiku.js +67 -6
  37. package/dist/haiku.js.map +1 -1
  38. package/dist/http/fetch.d.ts +9 -2
  39. package/dist/http/fetch.js +11 -2
  40. package/dist/http/fetch.js.map +1 -1
  41. package/dist/http/graphql.d.ts +15 -0
  42. package/dist/http/graphql.js +12 -0
  43. package/dist/http/graphql.js.map +1 -0
  44. package/dist/http.d.ts +24 -0
  45. package/dist/http.js +27 -0
  46. package/dist/http.js.map +1 -1
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.js +2 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/json.d.ts +6 -0
  51. package/dist/json.js +2 -0
  52. package/dist/json.js.map +1 -0
  53. package/dist/metadata.d.ts +51 -0
  54. package/dist/metadata.js +29 -0
  55. package/dist/metadata.js.map +1 -0
  56. package/dist/monorail.d.ts +38 -0
  57. package/dist/monorail.js +38 -0
  58. package/dist/monorail.js.map +1 -0
  59. package/dist/network/service.d.ts +1 -1
  60. package/dist/network/service.js.map +1 -1
  61. package/dist/node/archiver.d.ts +4 -1
  62. package/dist/node/archiver.js +22 -13
  63. package/dist/node/archiver.js.map +1 -1
  64. package/dist/node/base-command.d.ts +1 -0
  65. package/dist/node/base-command.js +11 -2
  66. package/dist/node/base-command.js.map +1 -1
  67. package/dist/node/cli.d.ts +0 -2
  68. package/dist/node/cli.js +0 -4
  69. package/dist/node/cli.js.map +1 -1
  70. package/dist/node/error-handler.d.ts +23 -1
  71. package/dist/node/error-handler.js +64 -8
  72. package/dist/node/error-handler.js.map +1 -1
  73. package/dist/node/hooks/init.d.ts +2 -0
  74. package/dist/node/hooks/init.js +7 -0
  75. package/dist/node/hooks/init.js.map +1 -0
  76. package/dist/node/hooks/postrun.js +5 -2
  77. package/dist/node/hooks/postrun.js.map +1 -1
  78. package/dist/node/hooks/prerun.js +2 -0
  79. package/dist/node/hooks/prerun.js.map +1 -1
  80. package/dist/node/ruby.d.ts +7 -2
  81. package/dist/node/ruby.js +22 -7
  82. package/dist/node/ruby.js.map +1 -1
  83. package/dist/output.d.ts +18 -11
  84. package/dist/output.js +96 -28
  85. package/dist/output.js.map +1 -1
  86. package/dist/path.d.ts +3 -3
  87. package/dist/path.js +2 -4
  88. package/dist/path.js.map +1 -1
  89. package/dist/plugins.d.ts +38 -2
  90. package/dist/plugins.js +11 -0
  91. package/dist/plugins.js.map +1 -1
  92. package/dist/session/authorize.js +16 -4
  93. package/dist/session/authorize.js.map +1 -1
  94. package/dist/session/exchange.js +2 -8
  95. package/dist/session/exchange.js.map +1 -1
  96. package/dist/session/validate.js +3 -0
  97. package/dist/session/validate.js.map +1 -1
  98. package/dist/session.js +7 -1
  99. package/dist/session.js.map +1 -1
  100. package/dist/store.js +0 -2
  101. package/dist/store.js.map +1 -1
  102. package/dist/string.d.ts +4 -0
  103. package/dist/string.js +13 -0
  104. package/dist/string.js.map +1 -1
  105. package/dist/tsconfig.tsbuildinfo +1 -1
  106. package/dist/typing/overloaded-parameters.d.ts +6 -0
  107. package/dist/typing/overloaded-parameters.js +2 -0
  108. package/dist/typing/overloaded-parameters.js.map +1 -0
  109. package/dist/typing/simple-definitions.d.ts +4 -0
  110. package/dist/typing/simple-definitions.js +2 -0
  111. package/dist/typing/simple-definitions.js.map +1 -0
  112. package/dist/ui.d.ts +12 -0
  113. package/dist/ui.js +57 -5
  114. package/dist/ui.js.map +1 -1
  115. package/package.json +28 -22
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @shopify/cli-kit
2
2
 
3
+ ## 3.6.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 073e514c: Validation that port used for receiving autentication token from browser is not already in use
8
+ - d9351df4: Use a custom list of safe nouns and adjectives to generate default names for apps and extensions
9
+
10
+ ## 3.5.0
11
+
12
+ ### Patch Changes
13
+
14
+ - dabc4bab: Refactor rejection tests to follow recommended implementation by Vitest
15
+
16
+ ## 3.4.0
17
+
18
+ ### Minor Changes
19
+
20
+ - 0da6c7e8: • Run CLI2 commands from passed-in directory, defaulting to current working directory
21
+ • Fill in flags for theme check
22
+ • Add --path to theme check
23
+ • Add --verbose to theme check
24
+
25
+ ### Patch Changes
26
+
27
+ - 08366831: Better logging:
28
+ • include Prompt and List input/output
29
+ • distinguish commands via UUID and log lines for command start/finish
30
+ • use a command line flag to specify log stream to view (cli, create-app, create-hydrogen)
31
+ - feae2499: Fix support for using a private template repo when git credentials are not setup
32
+ - 19ab3f99: Report 5xx reponses coming from the Partners' API as aborts
33
+
3
34
  ## 3.3.3
4
35
 
5
36
  ### Patch Changes
@@ -1,13 +1,19 @@
1
- interface startOptions {
1
+ import { Interfaces } from '@oclif/core';
2
+ interface StartOptions {
2
3
  command: string;
3
4
  args: string[];
4
5
  currentTime?: number;
5
6
  }
6
- export declare const start: ({ command, args, currentTime }: startOptions) => void;
7
+ export declare const start: ({ command, args, currentTime }: StartOptions) => void;
7
8
  interface ReportEventOptions {
9
+ config: Interfaces.Config;
8
10
  errorMessage?: string;
9
11
  }
10
- export declare const reportEvent: (options?: ReportEventOptions) => Promise<void>;
11
- export declare type ProjectType = 'node' | 'php' | 'ruby' | undefined;
12
- export declare function getProjectType(directory: string): Promise<ProjectType>;
12
+ /**
13
+ * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.
14
+ *
15
+ * The payload for an event includes both generic data, and data gathered from installed plug-ins.
16
+ *
17
+ */
18
+ export declare function reportEvent(options: ReportEventOptions): Promise<void>;
13
19
  export {};
package/dist/analytics.js CHANGED
@@ -1,38 +1,42 @@
1
1
  /* eslint-disable @typescript-eslint/naming-convention */
2
2
  import * as environment from './environment.js';
3
- import { fetch } from './http.js';
4
3
  import { platformAndArch } from './os.js';
5
- import { exists as fileExists } from './file.js';
6
- import { join as joinPath, resolve } from './path.js';
4
+ import { resolve } from './path.js';
7
5
  import { version as rubyVersion } from './node/ruby.js';
8
- import { debug, content, token } from './output.js';
6
+ import { content, debug, token } from './output.js';
9
7
  import constants from './constants.js';
10
- import { cliKitStore } from './store.js';
11
- const url = 'https://monorail-edge.shopifysvc.com/v1/produce';
12
- let startTime;
13
- let startCommand;
14
- let startArgs;
8
+ import * as metadata from './metadata.js';
9
+ import { publishEvent } from './monorail.js';
10
+ import { fanoutHooks } from './plugins.js';
15
11
  export const start = ({ command, args, currentTime = new Date().getTime() }) => {
16
- startCommand = command;
17
- startArgs = args;
18
- startTime = currentTime;
12
+ metadata.addSensitive({
13
+ commandStartOptions: {
14
+ startTime: currentTime,
15
+ startCommand: command,
16
+ startArgs: args,
17
+ },
18
+ });
19
19
  };
20
- export const reportEvent = async (options = {}) => {
21
- if (environment.local.analyticsDisabled())
22
- return;
23
- if (startCommand === undefined)
24
- return;
20
+ /**
21
+ * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.
22
+ *
23
+ * The payload for an event includes both generic data, and data gathered from installed plug-ins.
24
+ *
25
+ */
26
+ export async function reportEvent(options) {
25
27
  try {
26
- const currentTime = new Date().getTime();
27
- const payload = await buildPayload(options.errorMessage, currentTime);
28
- const body = JSON.stringify(payload);
29
- const headers = buildHeaders(currentTime);
30
- const response = await fetch(url, { method: 'POST', body, headers });
31
- if (response.status === 200) {
32
- debug(content `Analytics event sent: ${token.json(payload)}`);
28
+ const payload = await buildPayload(options);
29
+ if (payload === undefined) {
30
+ // Nothing to log
31
+ return;
33
32
  }
34
- else {
35
- debug(`Failed to report usage analytics: ${response.statusText}`);
33
+ if (environment.local.analyticsDisabled()) {
34
+ debug(content `Skipping command analytics, payload: ${token.json(payload)}`);
35
+ return;
36
+ }
37
+ const response = await publishEvent('app_cli3_command/1.0', payload.public, payload.sensitive);
38
+ if (response.type === 'error') {
39
+ debug(response.message);
36
40
  }
37
41
  // eslint-disable-next-line no-catch-all/no-catch-all
38
42
  }
@@ -43,69 +47,55 @@ export const reportEvent = async (options = {}) => {
43
47
  }
44
48
  debug(message);
45
49
  }
46
- };
47
- const totalTime = (currentTime) => {
48
- if (startTime === undefined)
49
- return undefined;
50
- return currentTime - startTime;
51
- };
52
- const buildHeaders = (currentTime) => {
53
- return {
54
- 'Content-Type': 'application/json; charset=utf-8',
55
- 'X-Monorail-Edge-Event-Created-At-Ms': currentTime.toString(),
56
- 'X-Monorail-Edge-Event-Sent-At-Ms': currentTime.toString(),
57
- };
58
- };
59
- const buildPayload = async (errorMessage, currentTime) => {
50
+ }
51
+ const buildPayload = async ({ config, errorMessage }) => {
52
+ const { commandStartOptions, ...sensitiveMetadata } = metadata.getAllSensitive();
53
+ if (commandStartOptions === undefined) {
54
+ debug('Unable to log analytics event - no information on executed command');
55
+ return;
56
+ }
57
+ const { startCommand, startArgs, startTime } = commandStartOptions;
58
+ const currentTime = new Date().getTime();
60
59
  let directory = process.cwd();
61
60
  const pathFlagIndex = startArgs.indexOf('--path');
62
61
  if (pathFlagIndex >= 0) {
63
62
  directory = resolve(startArgs[pathFlagIndex + 1]);
64
63
  }
65
- const appInfo = cliKitStore().getAppInfo(directory);
66
64
  const { platform, arch } = platformAndArch();
67
- const rawPartnerId = appInfo?.orgId;
68
- let partnerIdAsInt;
69
- if (rawPartnerId !== undefined) {
70
- partnerIdAsInt = parseInt(rawPartnerId, 10);
71
- if (isNaN(partnerIdAsInt)) {
72
- partnerIdAsInt = undefined;
73
- }
74
- }
65
+ const { '@shopify/app': appPublic, ...otherPluginsPublic } = await fanoutHooks(config, 'public_command_metadata', {});
66
+ const { partner_id, project_type, api_key, ...otherShopifyAppPublic } = appPublic ?? {};
67
+ const sensitivePluginData = await fanoutHooks(config, 'sensitive_command_metadata', {});
68
+ const appSpecific = {
69
+ partner_id,
70
+ api_key,
71
+ project_type,
72
+ };
75
73
  return {
76
- schema_id: 'app_cli3_command/1.0',
77
- payload: {
78
- project_type: await getProjectType(joinPath(directory, 'web')),
74
+ public: {
79
75
  command: startCommand,
80
- args: startArgs.join(' '),
81
76
  time_start: startTime,
82
77
  time_end: currentTime,
83
- total_time: totalTime(currentTime),
78
+ total_time: currentTime - startTime,
84
79
  success: errorMessage === undefined,
85
- error_message: errorMessage,
86
80
  uname: `${platform} ${arch}`,
87
81
  cli_version: await constants.versions.cliKit(),
88
82
  ruby_version: (await rubyVersion()) || '',
89
83
  node_version: process.version.replace('v', ''),
90
84
  is_employee: await environment.local.isShopify(),
91
- api_key: appInfo?.appId,
92
- partner_id: partnerIdAsInt,
85
+ ...appSpecific,
86
+ },
87
+ sensitive: {
88
+ args: startArgs.join(' '),
89
+ error_message: errorMessage,
90
+ metadata: JSON.stringify({
91
+ ...sensitiveMetadata,
92
+ extraPublic: {
93
+ '@shopify/app': otherShopifyAppPublic,
94
+ ...otherPluginsPublic,
95
+ },
96
+ extraSensitive: sensitivePluginData,
97
+ }),
93
98
  },
94
99
  };
95
100
  };
96
- export async function getProjectType(directory) {
97
- const nodeConfigFile = joinPath(directory, 'package.json');
98
- const rubyConfigFile = joinPath(directory, 'Gemfile');
99
- const phpConfigFile = joinPath(directory, 'composer.json');
100
- if (await fileExists(nodeConfigFile)) {
101
- return 'node';
102
- }
103
- else if (await fileExists(rubyConfigFile)) {
104
- return 'ruby';
105
- }
106
- else if (await fileExists(phpConfigFile)) {
107
- return 'php';
108
- }
109
- return undefined;
110
- }
111
101
  //# sourceMappingURL=analytics.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport * as environment from './environment.js'\nimport {fetch} from './http.js'\nimport {platformAndArch} from './os.js'\nimport {exists as fileExists} from './file.js'\nimport {join as joinPath, resolve} from './path.js'\nimport {version as rubyVersion} from './node/ruby.js'\nimport {debug, content, token} from './output.js'\nimport constants from './constants.js'\nimport {cliKitStore} from './store.js'\n\nconst url = 'https://monorail-edge.shopifysvc.com/v1/produce'\nlet startTime: number | undefined\nlet startCommand: string\nlet startArgs: string[]\n\ninterface startOptions {\n command: string\n args: string[]\n currentTime?: number\n}\n\nexport const start = ({command, args, currentTime = new Date().getTime()}: startOptions) => {\n startCommand = command\n startArgs = args\n startTime = currentTime\n}\n\ninterface ReportEventOptions {\n errorMessage?: string\n}\n\nexport const reportEvent = async (options: ReportEventOptions = {}) => {\n if (environment.local.analyticsDisabled()) return\n if (startCommand === undefined) return\n\n try {\n const currentTime = new Date().getTime()\n const payload = await buildPayload(options.errorMessage, currentTime)\n const body = JSON.stringify(payload)\n const headers = buildHeaders(currentTime)\n\n const response = await fetch(url, {method: 'POST', body, headers})\n if (response.status === 200) {\n debug(content`Analytics event sent: ${token.json(payload)}`)\n } else {\n debug(`Failed to report usage analytics: ${response.statusText}`)\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n debug(message)\n }\n}\n\nconst totalTime = (currentTime: number): number | undefined => {\n if (startTime === undefined) return undefined\n return currentTime - startTime\n}\n\nconst buildHeaders = (currentTime: number) => {\n return {\n 'Content-Type': 'application/json; charset=utf-8',\n 'X-Monorail-Edge-Event-Created-At-Ms': currentTime.toString(),\n 'X-Monorail-Edge-Event-Sent-At-Ms': currentTime.toString(),\n }\n}\n\nconst buildPayload = async (errorMessage: string | undefined, currentTime: number) => {\n let directory = process.cwd()\n const pathFlagIndex = startArgs.indexOf('--path')\n if (pathFlagIndex >= 0) {\n directory = resolve(startArgs[pathFlagIndex + 1])\n }\n const appInfo = cliKitStore().getAppInfo(directory)\n const {platform, arch} = platformAndArch()\n\n const rawPartnerId = appInfo?.orgId\n let partnerIdAsInt: number | undefined\n if (rawPartnerId !== undefined) {\n partnerIdAsInt = parseInt(rawPartnerId, 10)\n if (isNaN(partnerIdAsInt)) {\n partnerIdAsInt = undefined\n }\n }\n\n return {\n schema_id: 'app_cli3_command/1.0',\n payload: {\n project_type: await getProjectType(joinPath(directory, 'web')),\n command: startCommand,\n args: startArgs.join(' '),\n time_start: startTime,\n time_end: currentTime,\n total_time: totalTime(currentTime),\n success: errorMessage === undefined,\n error_message: errorMessage,\n uname: `${platform} ${arch}`,\n cli_version: await constants.versions.cliKit(),\n ruby_version: (await rubyVersion()) || '',\n node_version: process.version.replace('v', ''),\n is_employee: await environment.local.isShopify(),\n api_key: appInfo?.appId,\n partner_id: partnerIdAsInt,\n },\n }\n}\n\nexport type ProjectType = 'node' | 'php' | 'ruby' | undefined\n\nexport async function getProjectType(directory: string): Promise<ProjectType> {\n const nodeConfigFile = joinPath(directory, 'package.json')\n const rubyConfigFile = joinPath(directory, 'Gemfile')\n const phpConfigFile = joinPath(directory, 'composer.json')\n\n if (await fileExists(nodeConfigFile)) {\n return 'node'\n } else if (await fileExists(rubyConfigFile)) {\n return 'ruby'\n } else if (await fileExists(phpConfigFile)) {\n return 'php'\n }\n return undefined\n}\n"]}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,eAAe,EAAC,MAAM,SAAS,CAAA;AACvC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AACjD,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,YAAY,EAAC,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAA;AASxC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAAe,EAAE,EAAE;IACzF,QAAQ,CAAC,YAAY,CAAC;QACpB,mBAAmB,EAAE;YACnB,SAAS,EAAE,WAAW;YACtB,YAAY,EAAE,OAAO;YACrB,SAAS,EAAE,IAAI;SAChB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA;AAOD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,IAAI;QACF,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAA;QAC3C,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,iBAAiB;YACjB,OAAM;SACP;QACD,IAAI,WAAW,CAAC,KAAK,CAAC,iBAAiB,EAAE,EAAE;YACzC,KAAK,CAAC,OAAO,CAAA,wCAAwC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAC3E,OAAM;SACP;QACD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,sBAAsB,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;QAC9F,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE;YAC7B,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;SACxB;QACD,qDAAqD;KACtD;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,OAAO,GAAG,kCAAkC,CAAA;QAChD,IAAI,KAAK,YAAY,KAAK,EAAE;YAC1B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;SAC/C;QACD,KAAK,CAAC,OAAO,CAAC,CAAA;KACf;AACH,CAAC;AAED,MAAM,YAAY,GAAG,KAAK,EAAE,EAAC,MAAM,EAAE,YAAY,EAAqB,EAAE,EAAE;IACxE,MAAM,EAAC,mBAAmB,EAAE,GAAG,iBAAiB,EAAC,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAA;IAC9E,IAAI,mBAAmB,KAAK,SAAS,EAAE;QACrC,KAAK,CAAC,oEAAoE,CAAC,CAAA;QAC3E,OAAM;KACP;IACD,MAAM,EAAC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAC,GAAG,mBAAmB,CAAA;IAChE,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;IAExC,IAAI,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAC7B,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACjD,IAAI,aAAa,IAAI,CAAC,EAAE;QACtB,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAA;KAClD;IAED,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAC,GAAG,eAAe,EAAE,CAAA;IAE1C,MAAM,EAAC,cAAc,EAAE,SAAS,EAAE,GAAG,kBAAkB,EAAC,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,yBAAyB,EAAE,EAAE,CAAC,CAAA;IACnH,MAAM,EAAC,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,qBAAqB,EAAC,GAAG,SAAS,IAAI,EAAE,CAAA;IAErF,MAAM,mBAAmB,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,4BAA4B,EAAE,EAAE,CAAC,CAAA;IAEvF,MAAM,WAAW,GAAG;QAClB,UAAU;QACV,OAAO;QACP,YAAY;KACb,CAAA;IAED,OAAO;QACL,MAAM,EAAE;YACN,OAAO,EAAE,YAAY;YACrB,UAAU,EAAE,SAAS;YACrB,QAAQ,EAAE,WAAW;YACrB,UAAU,EAAE,WAAW,GAAG,SAAS;YACnC,OAAO,EAAE,YAAY,KAAK,SAAS;YACnC,KAAK,EAAE,GAAG,QAAQ,IAAI,IAAI,EAAE;YAC5B,WAAW,EAAE,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE;YAC9C,YAAY,EAAE,CAAC,MAAM,WAAW,EAAE,CAAC,IAAI,EAAE;YACzC,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;YAC9C,WAAW,EAAE,MAAM,WAAW,CAAC,KAAK,CAAC,SAAS,EAAE;YAChD,GAAG,WAAW;SACf;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;YACzB,aAAa,EAAE,YAAY;YAC3B,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;gBACvB,GAAG,iBAAiB;gBACpB,WAAW,EAAE;oBACX,cAAc,EAAE,qBAAqB;oBACrC,GAAG,kBAAkB;iBACtB;gBACD,cAAc,EAAE,mBAAmB;aACpC,CAAC;SACH;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport * as environment from './environment.js'\nimport {platformAndArch} from './os.js'\nimport {resolve} from './path.js'\nimport {version as rubyVersion} from './node/ruby.js'\nimport {content, debug, token} from './output.js'\nimport constants from './constants.js'\nimport * as metadata from './metadata.js'\nimport {publishEvent} from './monorail.js'\nimport {fanoutHooks} from './plugins.js'\nimport {Interfaces} from '@oclif/core'\n\ninterface StartOptions {\n command: string\n args: string[]\n currentTime?: number\n}\n\nexport const start = ({command, args, currentTime = new Date().getTime()}: StartOptions) => {\n metadata.addSensitive({\n commandStartOptions: {\n startTime: currentTime,\n startCommand: command,\n startArgs: args,\n },\n })\n}\n\ninterface ReportEventOptions {\n config: Interfaces.Config\n errorMessage?: string\n}\n\n/**\n * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.\n *\n * The payload for an event includes both generic data, and data gathered from installed plug-ins.\n *\n */\nexport async function reportEvent(options: ReportEventOptions) {\n try {\n const payload = await buildPayload(options)\n if (payload === undefined) {\n // Nothing to log\n return\n }\n if (environment.local.analyticsDisabled()) {\n debug(content`Skipping command analytics, payload: ${token.json(payload)}`)\n return\n }\n const response = await publishEvent('app_cli3_command/1.0', payload.public, payload.sensitive)\n if (response.type === 'error') {\n debug(response.message)\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n debug(message)\n }\n}\n\nconst buildPayload = async ({config, errorMessage}: ReportEventOptions) => {\n const {commandStartOptions, ...sensitiveMetadata} = metadata.getAllSensitive()\n if (commandStartOptions === undefined) {\n debug('Unable to log analytics event - no information on executed command')\n return\n }\n const {startCommand, startArgs, startTime} = commandStartOptions\n const currentTime = new Date().getTime()\n\n let directory = process.cwd()\n const pathFlagIndex = startArgs.indexOf('--path')\n if (pathFlagIndex >= 0) {\n directory = resolve(startArgs[pathFlagIndex + 1])\n }\n\n const {platform, arch} = platformAndArch()\n\n const {'@shopify/app': appPublic, ...otherPluginsPublic} = await fanoutHooks(config, 'public_command_metadata', {})\n const {partner_id, project_type, api_key, ...otherShopifyAppPublic} = appPublic ?? {}\n\n const sensitivePluginData = await fanoutHooks(config, 'sensitive_command_metadata', {})\n\n const appSpecific = {\n partner_id,\n api_key,\n project_type,\n }\n\n return {\n public: {\n command: startCommand,\n time_start: startTime,\n time_end: currentTime,\n total_time: currentTime - startTime,\n success: errorMessage === undefined,\n uname: `${platform} ${arch}`,\n cli_version: await constants.versions.cliKit(),\n ruby_version: (await rubyVersion()) || '',\n node_version: process.version.replace('v', ''),\n is_employee: await environment.local.isShopify(),\n ...appSpecific,\n },\n sensitive: {\n args: startArgs.join(' '),\n error_message: errorMessage,\n metadata: JSON.stringify({\n ...sensitiveMetadata,\n extraPublic: {\n '@shopify/app': otherShopifyAppPublic,\n ...otherPluginsPublic,\n },\n extraSensitive: sensitivePluginData,\n }),\n },\n }\n}\n"]}
package/dist/api/admin.js CHANGED
@@ -1,7 +1,8 @@
1
- import { buildHeaders, sanitizedHeadersOutput } from './common.js';
1
+ import { buildHeaders, debugLogRequest, handlingErrors } from './common.js';
2
2
  import { debug, content, token as outputToken } from '../output.js';
3
3
  import { Bug, Abort } from '../error.js';
4
- import { request as graphqlRequest, gql, ClientError } from 'graphql-request';
4
+ import { graphqlClient } from '../http/graphql.js';
5
+ import { gql } from 'graphql-request';
5
6
  const UnauthorizedAccessError = (store) => {
6
7
  const adminLink = outputToken.link(`URL`, `https://${store}/admin`);
7
8
  const storeName = store.replace('.myshopify.com', '');
@@ -13,48 +14,33 @@ const UnknownError = () => {
13
14
  return new Bug(`Unknown error connecting to your store`);
14
15
  };
15
16
  export async function request(query, session, variables) {
16
- const version = await fetchApiVersion(session);
17
- const url = adminUrl(session.storeFqdn, version);
18
- const headers = await buildHeaders(session.token);
19
- debug(`
20
- Sending Admin GraphQL request:
21
- ${query}
22
-
23
- With variables:
24
- ${variables ? JSON.stringify(variables, null, 2) : ''}
25
-
26
- And headers:
27
- ${sanitizedHeadersOutput(headers)}
28
- `);
29
- try {
30
- const response = await graphqlRequest(url, query, variables, headers);
17
+ const api = 'Admin';
18
+ return handlingErrors(api, async () => {
19
+ const version = await fetchApiVersion(session);
20
+ const url = adminUrl(session.storeFqdn, version);
21
+ const headers = await buildHeaders(session.token);
22
+ const client = await graphqlClient({
23
+ headers,
24
+ url,
25
+ service: 'shopify',
26
+ });
27
+ debugLogRequest(api, query, variables, headers);
28
+ const response = await client.request(query, variables);
31
29
  return response;
32
- }
33
- catch (error) {
34
- if (error instanceof ClientError) {
35
- const errorMessage = content `
36
- The Admin GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:
37
-
38
- ${outputToken.json(error.response.errors)}
39
- `;
40
- const abortError = new Abort(errorMessage.value);
41
- abortError.stack = error.stack;
42
- throw abortError;
43
- }
44
- else {
45
- throw error;
46
- }
47
- }
30
+ });
48
31
  }
49
32
  async function fetchApiVersion(session) {
50
33
  const url = adminUrl(session.storeFqdn, 'unstable');
51
34
  const query = apiVersionQuery();
52
35
  const headers = await buildHeaders(session.token);
36
+ const client = await graphqlClient({ url, headers, service: 'shopify' });
53
37
  debug(`
54
38
  Sending Admin GraphQL request to URL ${url} with query:
55
39
  ${query}
56
40
  `);
57
- const data = await graphqlRequest(url, query, {}, headers).catch((err) => {
41
+ const data = await client
42
+ .request(query, {})
43
+ .catch((err) => {
58
44
  throw err.response.status === 403 ? UnauthorizedAccessError(session.storeFqdn) : UnknownError();
59
45
  });
60
46
  return data.publicApiVersions
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {buildHeaders, sanitizedHeadersOutput} from './common.js'\nimport {AdminSession} from '../session.js'\nimport {debug, content, token as outputToken} from '../output.js'\nimport {Bug, Abort} from '../error.js'\nimport {request as graphqlRequest, gql, RequestDocument, Variables, ClientError} from 'graphql-request'\n\nconst UnauthorizedAccessError = (store: string) => {\n const adminLink = outputToken.link(`URL`, `https://${store}/admin`)\n const storeName = store.replace('.myshopify.com', '')\n return new Abort(\n content`Looks like you need access to this dev store (${outputToken.link(storeName, `https://${store}`)})`,\n content`• Log in to the store directly from this ${adminLink}. If you're the store owner, then that direct log in should solve your access issue.\n• If you're not the owner, create a dev store staff account for yourself. Then log in directly from the link above.\n `,\n )\n}\n\nconst UnknownError = () => {\n return new Bug(`Unknown error connecting to your store`)\n}\n\nexport async function request<T>(query: RequestDocument, session: AdminSession, variables?: Variables): Promise<T> {\n const version = await fetchApiVersion(session)\n const url = adminUrl(session.storeFqdn, version)\n const headers = await buildHeaders(session.token)\n debug(`\nSending Admin GraphQL request:\n${query}\n\nWith variables:\n${variables ? JSON.stringify(variables, null, 2) : ''}\n\nAnd headers:\n${sanitizedHeadersOutput(headers)}\n`)\n try {\n const response = await graphqlRequest<T>(url, query, variables, headers)\n return response\n } catch (error) {\n if (error instanceof ClientError) {\n const errorMessage = content`\nThe Admin GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:\n\n${outputToken.json(error.response.errors)}\n `\n const abortError = new Abort(errorMessage.value)\n abortError.stack = error.stack\n throw abortError\n } else {\n throw error\n }\n }\n}\n\nasync function fetchApiVersion(session: AdminSession): Promise<string> {\n const url = adminUrl(session.storeFqdn, 'unstable')\n const query = apiVersionQuery()\n const headers = await buildHeaders(session.token)\n\n debug(`\nSending Admin GraphQL request to URL ${url} with query:\n${query}\n `)\n const data = await graphqlRequest<{\n publicApiVersions: {handle: string; supported: boolean}[]\n }>(url, query, {}, headers).catch((err) => {\n throw err.response.status === 403 ? UnauthorizedAccessError(session.storeFqdn) : UnknownError()\n })\n\n return data.publicApiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n .reverse()[0]\n}\n\nfunction adminUrl(store: string, version: string | undefined): string {\n const realVersion = version || 'unstable'\n return `https://${store}/admin/api/${realVersion}/graphql.json`\n}\n\nfunction apiVersionQuery(): string {\n return gql`\n query {\n publicApiVersions {\n handle\n supported\n }\n }\n `\n}\n"]}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {buildHeaders, debugLogRequest, handlingErrors} from './common.js'\nimport {AdminSession} from '../session.js'\nimport {debug, content, token as outputToken} from '../output.js'\nimport {Bug, Abort} from '../error.js'\nimport {graphqlClient} from '../http/graphql.js'\nimport {gql, RequestDocument, Variables} from 'graphql-request'\n\nconst UnauthorizedAccessError = (store: string) => {\n const adminLink = outputToken.link(`URL`, `https://${store}/admin`)\n const storeName = store.replace('.myshopify.com', '')\n return new Abort(\n content`Looks like you need access to this dev store (${outputToken.link(storeName, `https://${store}`)})`,\n content`• Log in to the store directly from this ${adminLink}. If you're the store owner, then that direct log in should solve your access issue.\n• If you're not the owner, create a dev store staff account for yourself. Then log in directly from the link above.\n `,\n )\n}\n\nconst UnknownError = () => {\n return new Bug(`Unknown error connecting to your store`)\n}\n\nexport async function request<T>(query: RequestDocument, session: AdminSession, variables?: Variables): Promise<T> {\n const api = 'Admin'\n return handlingErrors(api, async () => {\n const version = await fetchApiVersion(session)\n const url = adminUrl(session.storeFqdn, version)\n const headers = await buildHeaders(session.token)\n const client = await graphqlClient({\n headers,\n url,\n service: 'shopify',\n })\n debugLogRequest(api, query, variables, headers)\n const response = await client.request<T>(query, variables)\n return response\n })\n}\n\nasync function fetchApiVersion(session: AdminSession): Promise<string> {\n const url = adminUrl(session.storeFqdn, 'unstable')\n const query = apiVersionQuery()\n const headers = await buildHeaders(session.token)\n const client = await graphqlClient({url, headers, service: 'shopify'})\n debug(`\nSending Admin GraphQL request to URL ${url} with query:\n${query}\n `)\n const data = await client\n .request<{\n publicApiVersions: {handle: string; supported: boolean}[]\n }>(query, {})\n .catch((err) => {\n throw err.response.status === 403 ? UnauthorizedAccessError(session.storeFqdn) : UnknownError()\n })\n\n return data.publicApiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n .reverse()[0]\n}\n\nfunction adminUrl(store: string, version: string | undefined): string {\n const realVersion = version || 'unstable'\n return `https://${store}/admin/api/${realVersion}/graphql.json`\n}\n\nfunction apiVersionQuery(): string {\n return gql`\n query {\n publicApiVersions {\n handle\n supported\n }\n }\n `\n}\n"]}
@@ -1,11 +1,21 @@
1
+ import { ExtendableError } from '../error.js';
2
+ import { RequestDocument, Variables } from 'graphql-request';
3
+ export declare class RequestClientError extends ExtendableError {
4
+ statusCode: number;
5
+ constructor(message: string, statusCode: number);
6
+ }
1
7
  export declare function buildHeaders(token: string): Promise<{
2
8
  [key: string]: string;
3
9
  }>;
4
10
  /**
5
- * Remvoes the sensitive data from the headers and outputs them as a string.
11
+ * Removes the sensitive data from the headers and outputs them as a string.
6
12
  * @param headers {{[key: string]: string}} HTTP headers.
7
13
  * @returns {string} A sanitized version of the headers as a string.
8
14
  */
9
15
  export declare function sanitizedHeadersOutput(headers: {
10
16
  [key: string]: string;
11
17
  }): string;
18
+ export declare function debugLogRequest<T>(api: string, query: RequestDocument, variables?: Variables, headers?: {
19
+ [key: string]: string;
20
+ }): Promise<void>;
21
+ export declare function handlingErrors<T>(api: string, action: () => Promise<T>): Promise<T>;
@@ -1,11 +1,18 @@
1
- import { isShopify } from '../environment/local.js';
1
+ import { firstPartyDev } from '../environment/local.js';
2
2
  import constants from '../constants.js';
3
+ import { stringifyMessage, content, token as outputToken, token, debug } from '../output.js';
4
+ import { Abort, ExtendableError } from '../error.js';
5
+ import { ClientError } from 'graphql-request';
3
6
  import { randomUUID } from 'crypto';
7
+ export class RequestClientError extends ExtendableError {
8
+ constructor(message, statusCode) {
9
+ super(message);
10
+ this.statusCode = statusCode;
11
+ }
12
+ }
4
13
  export async function buildHeaders(token) {
5
14
  const userAgent = `Shopify CLI; v=${await constants.versions.cliKit()}`;
6
- const isEmployee = await isShopify();
7
15
  const headers = {
8
- /* eslint-disable @typescript-eslint/naming-convention */
9
16
  'User-Agent': userAgent,
10
17
  // 'Sec-CH-UA': secCHUA, This header requires the Git sha.
11
18
  'Sec-CH-UA-PLATFORM': process.platform,
@@ -13,13 +20,12 @@ export async function buildHeaders(token) {
13
20
  authorization: `Bearer ${token}`,
14
21
  'X-Shopify-Access-Token': `Bearer ${token}`,
15
22
  'Content-Type': 'application/json',
16
- // ...(isEmployee && {'X-Shopify-Cli-Employee': '1'}),
17
- /* eslint-enable @typescript-eslint/naming-convention */
23
+ ...(firstPartyDev() && { 'X-Shopify-Cli-Employee': '1' }),
18
24
  };
19
25
  return headers;
20
26
  }
21
27
  /**
22
- * Remvoes the sensitive data from the headers and outputs them as a string.
28
+ * Removes the sensitive data from the headers and outputs them as a string.
23
29
  * @param headers {{[key: string]: string}} HTTP headers.
24
30
  * @returns {string} A sanitized version of the headers as a string.
25
31
  */
@@ -37,4 +43,42 @@ export function sanitizedHeadersOutput(headers) {
37
43
  })
38
44
  .join('\n');
39
45
  }
46
+ export async function debugLogRequest(api, query, variables, headers = {}) {
47
+ debug(`
48
+ Sending ${token.raw(api)} GraphQL request:
49
+ ${query}
50
+
51
+ With variables:
52
+ ${variables ? JSON.stringify(variables, null, 2) : ''}
53
+
54
+ And headers:
55
+ ${sanitizedHeadersOutput(headers)}
56
+ `);
57
+ }
58
+ export async function handlingErrors(api, action) {
59
+ try {
60
+ return await action();
61
+ }
62
+ catch (error) {
63
+ if (error instanceof ClientError) {
64
+ const errorMessage = stringifyMessage(content `
65
+ The ${token.raw(api)} GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:
66
+
67
+ ${outputToken.json(error.response.errors)}
68
+ `);
69
+ let mappedError;
70
+ if (error.response.status < 500) {
71
+ mappedError = new RequestClientError(errorMessage, error.response.status);
72
+ }
73
+ else {
74
+ mappedError = new Abort(errorMessage);
75
+ }
76
+ mappedError.stack = error.stack;
77
+ throw mappedError;
78
+ }
79
+ else {
80
+ throw error;
81
+ }
82
+ }
83
+ }
40
84
  //# sourceMappingURL=common.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/api/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yBAAyB,CAAA;AACjD,OAAO,SAAS,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAC,UAAU,EAAC,MAAM,QAAQ,CAAA;AAEjC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa;IAC9C,MAAM,SAAS,GAAG,kBAAkB,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAA;IACvE,MAAM,UAAU,GAAG,MAAM,SAAS,EAAE,CAAA;IAEpC,MAAM,OAAO,GAAG;QACd,yDAAyD;QACzD,YAAY,EAAE,SAAS;QACvB,0DAA0D;QAC1D,oBAAoB,EAAE,OAAO,CAAC,QAAQ;QACtC,cAAc,EAAE,UAAU,EAAE;QAC5B,aAAa,EAAE,UAAU,KAAK,EAAE;QAChC,wBAAwB,EAAE,UAAU,KAAK,EAAE;QAC3C,cAAc,EAAE,kBAAkB;QAClC,sDAAsD;QACtD,wDAAwD;KACzD,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgC;IACrE,MAAM,SAAS,GAA4B,EAAE,CAAA;IAC7C,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IAC3C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACtC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,SAAS,EAAE;YAC1F,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;SACpC;IACH,CAAC,CAAC,CAAA;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;SAC1B,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,OAAO,MAAM,MAAM,KAAK,SAAS,CAAC,MAAM,CAAC,EAAE,CAAA;IAC7C,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC","sourcesContent":["import {isShopify} from '../environment/local.js'\nimport constants from '../constants.js'\nimport {randomUUID} from 'crypto'\n\nexport async function buildHeaders(token: string): Promise<{[key: string]: string}> {\n const userAgent = `Shopify CLI; v=${await constants.versions.cliKit()}`\n const isEmployee = await isShopify()\n\n const headers = {\n /* eslint-disable @typescript-eslint/naming-convention */\n 'User-Agent': userAgent,\n // 'Sec-CH-UA': secCHUA, This header requires the Git sha.\n 'Sec-CH-UA-PLATFORM': process.platform,\n 'X-Request-Id': randomUUID(),\n authorization: `Bearer ${token}`,\n 'X-Shopify-Access-Token': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n // ...(isEmployee && {'X-Shopify-Cli-Employee': '1'}),\n /* eslint-enable @typescript-eslint/naming-convention */\n }\n\n return headers\n}\n\n/**\n * Remvoes the sensitive data from the headers and outputs them as a string.\n * @param headers {{[key: string]: string}} HTTP headers.\n * @returns {string} A sanitized version of the headers as a string.\n */\nexport function sanitizedHeadersOutput(headers: {[key: string]: string}): string {\n const sanitized: {[key: string]: string} = {}\n const keywords = ['token', 'authorization']\n Object.keys(headers).forEach((header) => {\n if (keywords.find((keyword) => header.toLocaleLowerCase().includes(keyword)) === undefined) {\n sanitized[header] = headers[header]\n }\n })\n return Object.keys(sanitized)\n .map((header) => {\n return ` - ${header}: ${sanitized[header]}`\n })\n .join('\\n')\n}\n"]}
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/api/common.ts"],"names":[],"mappings":"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","sourcesContent":["import {firstPartyDev} from '../environment/local.js'\nimport constants from '../constants.js'\nimport {stringifyMessage, content, token as outputToken, token, debug} from '../output.js'\nimport {Abort, ExtendableError} from '../error.js'\nimport {ClientError, RequestDocument, Variables} from 'graphql-request'\nimport {randomUUID} from 'crypto'\n\nexport class RequestClientError extends ExtendableError {\n statusCode: number\n public constructor(message: string, statusCode: number) {\n super(message)\n this.statusCode = statusCode\n }\n}\n\nexport async function buildHeaders(token: string): Promise<{[key: string]: string}> {\n const userAgent = `Shopify CLI; v=${await constants.versions.cliKit()}`\n\n const headers = {\n 'User-Agent': userAgent,\n // 'Sec-CH-UA': secCHUA, This header requires the Git sha.\n 'Sec-CH-UA-PLATFORM': process.platform,\n 'X-Request-Id': randomUUID(),\n authorization: `Bearer ${token}`,\n 'X-Shopify-Access-Token': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n ...(firstPartyDev() && {'X-Shopify-Cli-Employee': '1'}),\n }\n\n return headers\n}\n\n/**\n * Removes the sensitive data from the headers and outputs them as a string.\n * @param headers {{[key: string]: string}} HTTP headers.\n * @returns {string} A sanitized version of the headers as a string.\n */\nexport function sanitizedHeadersOutput(headers: {[key: string]: string}): string {\n const sanitized: {[key: string]: string} = {}\n const keywords = ['token', 'authorization']\n Object.keys(headers).forEach((header) => {\n if (keywords.find((keyword) => header.toLocaleLowerCase().includes(keyword)) === undefined) {\n sanitized[header] = headers[header]\n }\n })\n return Object.keys(sanitized)\n .map((header) => {\n return ` - ${header}: ${sanitized[header]}`\n })\n .join('\\n')\n}\n\nexport async function debugLogRequest<T>(\n api: string,\n query: RequestDocument,\n variables?: Variables,\n headers: {[key: string]: string} = {},\n) {\n debug(`\nSending ${token.raw(api)} GraphQL request:\n${query}\n\nWith variables:\n${variables ? JSON.stringify(variables, null, 2) : ''}\n\nAnd headers:\n${sanitizedHeadersOutput(headers)}\n`)\n}\n\nexport async function handlingErrors<T>(api: string, action: () => Promise<T>): Promise<T> {\n try {\n return await action()\n } catch (error) {\n if (error instanceof ClientError) {\n const errorMessage = stringifyMessage(content`\n The ${token.raw(\n api,\n )} GraphQL API responded unsuccessfully with the HTTP status ${`${error.response.status}`} and errors:\n\n ${outputToken.json(error.response.errors)}\n `)\n let mappedError: Error\n if (error.response.status < 500) {\n mappedError = new RequestClientError(errorMessage, error.response.status)\n } else {\n mappedError = new Abort(errorMessage)\n }\n mappedError.stack = error.stack\n throw mappedError\n } else {\n throw error\n }\n }\n}\n"]}
@@ -1,17 +1,16 @@
1
1
  import { identity } from '../environment/fqdn.js';
2
2
  import { debug } from '../output.js';
3
- import { fetch } from '../http.js';
3
+ import { shopifyFetch } from '../http.js';
4
4
  export async function validateIdentityToken(token) {
5
5
  try {
6
6
  const instrospectionURL = await getInstrospectionEndpoint();
7
7
  const options = {
8
8
  method: 'POST',
9
- // eslint-disable-next-line @typescript-eslint/naming-convention
10
9
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
11
10
  body: JSON.stringify({ token }),
12
11
  };
13
12
  debug(`Sending Identity Introspection request to URL: ${instrospectionURL}`);
14
- const response = await fetch(instrospectionURL, options);
13
+ const response = await shopifyFetch('shopify', instrospectionURL, options);
15
14
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
15
  const json = await response.json();
17
16
  debug(`The identity token is valid: ${json.valid}`);
@@ -24,7 +23,7 @@ export async function validateIdentityToken(token) {
24
23
  }
25
24
  }
26
25
  async function getInstrospectionEndpoint() {
27
- const response = await fetch(`https://${await identity()}/.well-known/openid-configuration.json`);
26
+ const response = await shopifyFetch('identity', `https://${await identity()}/.well-known/openid-configuration.json`);
28
27
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
28
  const json = await response.json();
30
29
  return json.introspection_endpoint;
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/api/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAA;AAClC,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAEhC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAa;IACvD,IAAI;QACF,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,EAAE,CAAA;QAC3D,MAAM,OAAO,GAAG;YACd,MAAM,EAAE,MAAM;YACd,gEAAgE;YAChE,OAAO,EAAE,EAAC,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAC;YAC/E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAC,KAAK,EAAC,CAAC;SAC9B,CAAA;QACD,KAAK,CAAC,kDAAkD,iBAAiB,EAAE,CAAC,CAAA;QAE5E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;QACxD,8DAA8D;QAC9D,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAEvC,KAAK,CAAC,gCAAgC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;QACnD,OAAO,IAAI,CAAC,KAAK,CAAA;QACjB,qDAAqD;KACtD;IAAC,OAAO,KAAK,EAAE;QACd,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAA;QAChD,OAAO,KAAK,CAAA;KACb;AACH,CAAC;AAED,KAAK,UAAU,yBAAyB;IACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,MAAM,QAAQ,EAAE,wCAAwC,CAAC,CAAA;IACjG,8DAA8D;IAC9D,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IACvC,OAAO,IAAI,CAAC,sBAAsB,CAAA;AACpC,CAAC","sourcesContent":["import {identity} from '../environment/fqdn.js'\nimport {debug} from '../output.js'\nimport {fetch} from '../http.js'\n\nexport async function validateIdentityToken(token: string) {\n try {\n const instrospectionURL = await getInstrospectionEndpoint()\n const options = {\n method: 'POST',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n debug(`Sending Identity Introspection request to URL: ${instrospectionURL}`)\n\n const response = await fetch(instrospectionURL, options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n\n debug(`The identity token is valid: ${json.valid}`)\n return json.valid\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n debug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function getInstrospectionEndpoint(): Promise<string> {\n const response = await fetch(`https://${await identity()}/.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.js","sourceRoot":"","sources":["../../src/api/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAA;AAClC,OAAO,EAAC,YAAY,EAAC,MAAM,YAAY,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAa;IACvD,IAAI;QACF,MAAM,iBAAiB,GAAG,MAAM,yBAAyB,EAAE,CAAA;QAC3D,MAAM,OAAO,GAAG;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAC,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAC;YAC/E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAC,KAAK,EAAC,CAAC;SAC9B,CAAA;QACD,KAAK,CAAC,kDAAkD,iBAAiB,EAAE,CAAC,CAAA;QAE5E,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAA;QAC1E,8DAA8D;QAC9D,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAEvC,KAAK,CAAC,gCAAgC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;QACnD,OAAO,IAAI,CAAC,KAAK,CAAA;QACjB,qDAAqD;KACtD;IAAC,OAAO,KAAK,EAAE;QACd,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAA;QAChD,OAAO,KAAK,CAAA;KACb;AACH,CAAC;AAED,KAAK,UAAU,yBAAyB;IACtC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,WAAW,MAAM,QAAQ,EAAE,wCAAwC,CAAC,CAAA;IACpH,8DAA8D;IAC9D,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IACvC,OAAO,IAAI,CAAC,sBAAsB,CAAA;AACpC,CAAC","sourcesContent":["import {identity} from '../environment/fqdn.js'\nimport {debug} from '../output.js'\nimport {shopifyFetch} from '../http.js'\n\nexport async function validateIdentityToken(token: string) {\n try {\n const instrospectionURL = await getInstrospectionEndpoint()\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n debug(`Sending Identity Introspection request to URL: ${instrospectionURL}`)\n\n const response = await shopifyFetch('shopify', instrospectionURL, options)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n\n debug(`The identity token is valid: ${json.valid}`)\n return json.valid\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n debug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function getInstrospectionEndpoint(): Promise<string> {\n const response = await shopifyFetch('identity', `https://${await identity()}/.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,9 +1,4 @@
1
- import { ExtendableError } from '../error.js';
2
1
  import { Variables, RequestDocument } from 'graphql-request';
3
- export declare class RequestClientError extends ExtendableError {
4
- statusCode: number;
5
- constructor(message: string, statusCode: number);
6
- }
7
2
  export declare function request<T>(query: RequestDocument, token: string, variables?: Variables): Promise<T>;
8
3
  /**
9
4
  * Check if the given token is revoked and no longer valid to interact with the Partners API.