@shopify/cli-kit 4.6.1 → 4.7.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.
- package/dist/private/node/analytics/bounded-collections.js +1 -4
- package/dist/private/node/analytics/bounded-collections.js.map +1 -1
- package/dist/private/node/analytics/graphql-error-codes.d.ts +2 -2
- package/dist/private/node/analytics/graphql-error-codes.js +2 -2
- package/dist/private/node/analytics/graphql-error-codes.js.map +1 -1
- package/dist/private/node/analytics.js +12 -7
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/headers.js +3 -0
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/api.js +8 -8
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/conf-store.js +1 -1
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/content-tokens.js +27 -2
- package/dist/private/node/content-tokens.js.map +1 -1
- package/dist/private/node/otel-metrics.d.ts +1 -1
- package/dist/private/node/otel-metrics.js +5 -2
- package/dist/private/node/otel-metrics.js.map +1 -1
- package/dist/private/node/plugin-hints.d.ts +16 -0
- package/dist/private/node/plugin-hints.js +29 -0
- package/dist/private/node/plugin-hints.js.map +1 -0
- package/dist/private/node/request-ids.js +2 -3
- package/dist/private/node/request-ids.js.map +1 -1
- package/dist/private/node/session/device-authorization.js +4 -7
- package/dist/private/node/session/device-authorization.js.map +1 -1
- package/dist/private/node/session/exchange.d.ts +4 -4
- package/dist/private/node/session/exchange.js +21 -5
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/testing/ui.js +18 -19
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/ui/components/Alert.d.ts +1 -1
- package/dist/private/node/ui/components/Alert.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +2 -0
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
- package/dist/private/node/ui/components/List.d.ts +1 -1
- package/dist/private/node/ui/components/List.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +1 -1
- package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.test.js +1 -0
- package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
- package/dist/private/node/ui/components/TabularData.d.ts +1 -1
- package/dist/private/node/ui/components/TabularData.js +2 -1
- package/dist/private/node/ui/components/TabularData.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.d.ts +1 -1
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.d.ts +1 -38
- package/dist/private/node/ui/components/TokenizedText.js +0 -54
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.test.js +2 -1
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/private/node/ui/components/token-item.d.ts +38 -0
- package/dist/private/node/ui/components/token-item.js +63 -0
- package/dist/private/node/ui/components/token-item.js.map +1 -0
- package/dist/private/node/ui/hooks/use-abort-signal.js +5 -4
- package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
- package/dist/private/node/ui/hooks/use-select-state.js +2 -1
- package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
- package/dist/private/node/ui/utilities.d.ts +6 -6
- package/dist/private/node/ui/utilities.js +1 -1
- package/dist/private/node/ui/utilities.js.map +1 -1
- package/dist/private/node/ui.js +18 -15
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/string.d.ts +1 -1
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/abort.d.ts +14 -6
- package/dist/public/node/abort.js +7 -6
- package/dist/public/node/abort.js.map +1 -1
- package/dist/public/node/analytics.d.ts +1 -0
- package/dist/public/node/analytics.js +79 -32
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/api/admin.js +1 -1
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/base-command.d.ts +10 -0
- package/dist/public/node/base-command.js +31 -8
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.d.ts +13 -0
- package/dist/public/node/cli.js +18 -2
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/local.d.ts +3 -1
- package/dist/public/node/context/local.js +14 -7
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/custom-oclif-loader.js +19 -16
- package/dist/public/node/custom-oclif-loader.js.map +1 -1
- package/dist/public/node/doctor/framework.js +4 -5
- package/dist/public/node/doctor/framework.js.map +1 -1
- package/dist/public/node/environment.js +8 -11
- package/dist/public/node/environment.js.map +1 -1
- package/dist/public/node/error.d.ts +1 -4
- package/dist/public/node/error.js +20 -7
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/git.js +7 -5
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/global-context.js +1 -1
- package/dist/public/node/global-context.js.map +1 -1
- package/dist/public/node/hidden-folder.js +2 -4
- package/dist/public/node/hidden-folder.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +1 -1
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/hooks/prerun.js +5 -1
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/local-storage.js +1 -0
- package/dist/public/node/local-storage.js.map +1 -1
- package/dist/public/node/metadata.d.ts +3 -0
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/mimes.js +1 -3
- package/dist/public/node/mimes.js.map +1 -1
- package/dist/public/node/node-package-manager.js +31 -73
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/notifications-system.js +19 -3
- package/dist/public/node/notifications-system.js.map +1 -1
- package/dist/public/node/os.js +5 -10
- package/dist/public/node/os.js.map +1 -1
- package/dist/public/node/output.js +11 -20
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/plugins/tunnel.d.ts +1 -2
- package/dist/public/node/plugins/tunnel.js +2 -2
- package/dist/public/node/plugins/tunnel.js.map +1 -1
- package/dist/public/node/result.js +4 -2
- package/dist/public/node/result.js.map +1 -1
- package/dist/public/node/serial-batch-processor.js +4 -3
- package/dist/public/node/serial-batch-processor.js.map +1 -1
- package/dist/public/node/store-auth-session.js +1 -1
- package/dist/public/node/store-auth-session.js.map +1 -1
- package/dist/public/node/system.d.ts +15 -1
- package/dist/public/node/system.js +42 -6
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/themes/conf.js +2 -2
- package/dist/public/node/themes/conf.js.map +1 -1
- package/dist/public/node/themes/factories.js +2 -2
- package/dist/public/node/themes/factories.js.map +1 -1
- package/dist/public/node/themes/theme-manager.js +2 -0
- package/dist/public/node/themes/theme-manager.js.map +1 -1
- package/dist/public/node/themes/urls.js +7 -7
- package/dist/public/node/themes/urls.js.map +1 -1
- package/dist/public/node/toml/toml-file.js +12 -13
- package/dist/public/node/toml/toml-file.js.map +1 -1
- package/dist/public/node/ui.d.ts +1 -1
- package/dist/public/node/ui.js +1 -1
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2024.js +14 -2
- package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server.js +3 -0
- package/dist/public/node/vendor/dev_server/dev-server.js.map +1 -1
- package/dist/public/node/vendor/dev_server/network/index.js +1 -1
- package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js +1 -0
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js +5 -2
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/types.d.ts +2 -2
- package/dist/public/node/vendor/otel-js/service/types.js.map +1 -1
- package/dist/public/node/vscode.js +12 -11
- package/dist/public/node/vscode.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -9
|
@@ -54,10 +54,7 @@ export class BArray extends Array {
|
|
|
54
54
|
* events.set('event', 1) // Automatically removes oldest if over 1000
|
|
55
55
|
*/
|
|
56
56
|
export class BMap extends Map {
|
|
57
|
-
|
|
58
|
-
super(...arguments);
|
|
59
|
-
this.insertionOrder = [];
|
|
60
|
-
}
|
|
57
|
+
insertionOrder = [];
|
|
61
58
|
set(key, value) {
|
|
62
59
|
if (!this.has(key)) {
|
|
63
60
|
this.insertionOrder.push(key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bounded-collections.js","sourceRoot":"","sources":["../../../../src/private/node/analytics/bounded-collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,cAAc,GAAG,IAAI,CAAA;AAE3B;;GAEG;AACH,MAAM,YAAY,GAAG,IAAI,CAAA;AAEzB;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,MAAU,SAAQ,KAAQ;IACrC,IAAI,CAAC,GAAG,KAAU;QAChB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;QACnC,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;IACjB,CAAC;IAED,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IAClB,CAAC;IAEO,YAAY;QAClB,OAAO,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;IACH,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,IAAmB,SAAQ,GAAiB;
|
|
1
|
+
{"version":3,"file":"bounded-collections.js","sourceRoot":"","sources":["../../../../src/private/node/analytics/bounded-collections.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,cAAc,GAAG,IAAI,CAAA;AAE3B;;GAEG;AACH,MAAM,YAAY,GAAG,IAAI,CAAA;AAEzB;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,MAAU,SAAQ,KAAQ;IACrC,IAAI,CAAC,GAAG,KAAU;QAChB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;QACnC,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;IACjB,CAAC;IAED,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IAClB,CAAC;IAEO,YAAY;QAClB,OAAO,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;IACH,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,IAAmB,SAAQ,GAAiB;IAC/C,cAAc,GAAW,EAAE,CAAA;IAEnC,GAAG,CAAC,GAAS,EAAE,KAAa;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC/B,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACrB,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,CAAC,GAAS;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC9C,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACtC,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,cAAc,GAAG,EAAE,CAAA;QACxB,KAAK,CAAC,KAAK,EAAE,CAAA;IACf,CAAC;IAED,QAAQ;QACN,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAEO,YAAY;QAClB,OAAO,IAAI,CAAC,IAAI,GAAG,YAAY,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;YAC7C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;IACH,CAAC;CACF","sourcesContent":["/**\n * Ensures bounded arrays stay within reasonable memory limits.\n */\nconst MAX_ARRAY_SIZE = 1000\n\n/**\n * Estimated ~500KB total across timing, error, retry, and event entries.\n */\nconst MAX_MAP_KEYS = 1000\n\n/**\n * A bounded array that automatically maintains a maximum size by removing\n * the oldest entries when new items are added beyond the limit.\n *\n * Extends the native Array class to provide all standard array methods\n * while enforcing a fixed maximum size of MAX_ARRAY_SIZE (1000 entries).\n *\n * When the size limit is exceeded, the oldest entries (at the beginning\n * of the array) are automatically removed to make room for new ones.\n *\n * @example\n * const commands = new BArray()\n * commands.push(entry) // Automatically removes oldest if over 1000\n */\nexport class BArray<T> extends Array<T> {\n push(...items: T[]): number {\n const result = super.push(...items)\n this.enforceLimit()\n return result\n }\n\n clear(): void {\n this.length = 0\n }\n\n toArray(): T[] {\n return [...this]\n }\n\n private enforceLimit(): void {\n while (this.length > MAX_ARRAY_SIZE) {\n this.shift()\n }\n }\n}\n\n/**\n * A bounded map that automatically maintains a maximum number of keys by\n * removing the oldest entries when new keys are added beyond the limit.\n *\n * Extends the native Map class to provide all standard map methods while\n * enforcing a fixed maximum size of MAX_MAP_KEYS (1000 entries).\n *\n * Tracks insertion order to ensure the oldest keys are removed first when\n * the limit is exceeded. This provides LRU-like behavior based on insertion\n * time rather than access time.\n *\n * @example\n * const events = new BMap()\n * events.set('event', 1) // Automatically removes oldest if over 1000\n */\nexport class BMap<TKey, TValue> extends Map<TKey, TValue> {\n private insertionOrder: TKey[] = []\n\n set(key: TKey, value: TValue): this {\n if (!this.has(key)) {\n this.insertionOrder.push(key)\n }\n super.set(key, value)\n this.enforceLimit()\n return this\n }\n\n delete(key: TKey): boolean {\n const index = this.insertionOrder.indexOf(key)\n if (index > -1) {\n this.insertionOrder.splice(index, 1)\n }\n return super.delete(key)\n }\n\n clear(): void {\n this.insertionOrder = []\n super.clear()\n }\n\n toObject(): Record<string, TValue> {\n return Object.fromEntries(this)\n }\n\n private enforceLimit(): void {\n while (this.size > MAX_MAP_KEYS && this.insertionOrder.length > 0) {\n const oldestKey = this.insertionOrder.shift()\n if (oldestKey !== undefined) {\n super.delete(oldestKey)\n }\n }\n }\n}\n"]}
|
|
@@ -21,8 +21,8 @@ export declare function graphQLErrorCodes(errors: unknown): string[];
|
|
|
21
21
|
/**
|
|
22
22
|
* Whether a single code is a rate-limit signal (`THROTTLED` or `429`).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Shared with the retry path (`isThrottled` in `private/node/api.ts`), where these codes signal
|
|
25
|
+
* rate limiting even at HTTP 200.
|
|
26
26
|
*/
|
|
27
27
|
export declare function isRateLimitCode(code: string | undefined): boolean;
|
|
28
28
|
/**
|
|
@@ -48,8 +48,8 @@ export function graphQLErrorCodes(errors) {
|
|
|
48
48
|
/**
|
|
49
49
|
* Whether a single code is a rate-limit signal (`THROTTLED` or `429`).
|
|
50
50
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
* Shared with the retry path (`isThrottled` in `private/node/api.ts`), where these codes signal
|
|
52
|
+
* rate limiting even at HTTP 200.
|
|
53
53
|
*/
|
|
54
54
|
export function isRateLimitCode(code) {
|
|
55
55
|
return code !== undefined && RATE_LIMIT_CODES.has(code);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-error-codes.js","sourceRoot":"","sources":["../../../../src/private/node/analytics/graphql-error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAA;AAEtD;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAA;AAEpE;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAe;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAA;IAErC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,MAAM,KAAK,GAAG,KAAqF,CAAA;QAEnG,MAAM,IAAI,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,CAAA;QACpC,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE9C,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAA;QACvD,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAI,QAA6C,EAAE,QAAQ,CAAA;gBACzE,IAAI,OAAO,QAAQ,KAAK,QAAQ;oBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACxD,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAAwB;IACtD,OAAO,IAAI,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,OAAO,IAAI,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;AACxD,CAAC","sourcesContent":["/**\n * Pure helpers for reading routing-relevant codes out of a GraphQL error response.\n *\n * This module is intentionally dependency-free: it is imported by both the grouping logic\n * (`error-grouping.ts`) and the crash-report suppression logic (`../../public/node/error.ts`).\n * `error.ts` cannot import `error-grouping.ts` directly — that would create an\n * `error.ts → headers.ts → error.ts` import cycle — so the shared scanning logic lives here,\n * where it imports nothing from cli-kit.\n */\n\n/** GraphQL `extensions.code` values we treat as rate limiting. */\nconst RATE_LIMIT_CODES = new Set(['THROTTLED', '429'])\n\n/**\n * GraphQL `extensions.code` values (and nested App Management `app_errors` categories) we treat as\n * a permission / access-denied signal. The top-level admin code is `ACCESS_DENIED`; the App\n * Management nested shape uses the lowercase category `access_denied`.\n */\nconst PERMISSION_CODES = new Set(['ACCESS_DENIED', 'access_denied'])\n\n/**\n * Collects every routing-relevant code from a GraphQL `errors` value.\n *\n * Scans *all* errors (not just the first), reading both the top-level `extensions.code` and the\n * nested App Management shape `extensions.app_errors.errors[].category`. The API can also return\n * `errors` as a string (e.g. some 401s), which yields no codes.\n *\n * @param errors - The `errors` value from a GraphQL response (array, string, or undefined).\n * @returns Every string code/category found, in document order.\n */\nexport function graphQLErrorCodes(errors: unknown): string[] {\n if (!Array.isArray(errors)) return []\n\n return errors.flatMap((entry) => {\n const found: string[] = []\n const error = entry as {extensions?: {code?: unknown; app_errors?: {errors?: unknown}}} | undefined\n\n const code = error?.extensions?.code\n if (typeof code === 'string') found.push(code)\n\n const appErrors = error?.extensions?.app_errors?.errors\n if (Array.isArray(appErrors)) {\n for (const appError of appErrors) {\n const category = (appError as {category?: unknown} | undefined)?.category\n if (typeof category === 'string') found.push(category)\n }\n }\n\n return found\n })\n}\n\n/**\n * Whether a single code is a rate-limit signal (`THROTTLED` or `429`).\n *\n *
|
|
1
|
+
{"version":3,"file":"graphql-error-codes.js","sourceRoot":"","sources":["../../../../src/private/node/analytics/graphql-error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAA;AAEtD;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAA;AAEpE;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAe;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAA;IAErC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,MAAM,KAAK,GAAG,KAAqF,CAAA;QAEnG,MAAM,IAAI,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,CAAA;QACpC,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAE9C,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAA;QACvD,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,MAAM,QAAQ,GAAI,QAA6C,EAAE,QAAQ,CAAA;gBACzE,IAAI,OAAO,QAAQ,KAAK,QAAQ;oBAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACxD,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAAwB;IACtD,OAAO,IAAI,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,OAAO,IAAI,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;AACxD,CAAC","sourcesContent":["/**\n * Pure helpers for reading routing-relevant codes out of a GraphQL error response.\n *\n * This module is intentionally dependency-free: it is imported by both the grouping logic\n * (`error-grouping.ts`) and the crash-report suppression logic (`../../public/node/error.ts`).\n * `error.ts` cannot import `error-grouping.ts` directly — that would create an\n * `error.ts → headers.ts → error.ts` import cycle — so the shared scanning logic lives here,\n * where it imports nothing from cli-kit.\n */\n\n/** GraphQL `extensions.code` values we treat as rate limiting. */\nconst RATE_LIMIT_CODES = new Set(['THROTTLED', '429'])\n\n/**\n * GraphQL `extensions.code` values (and nested App Management `app_errors` categories) we treat as\n * a permission / access-denied signal. The top-level admin code is `ACCESS_DENIED`; the App\n * Management nested shape uses the lowercase category `access_denied`.\n */\nconst PERMISSION_CODES = new Set(['ACCESS_DENIED', 'access_denied'])\n\n/**\n * Collects every routing-relevant code from a GraphQL `errors` value.\n *\n * Scans *all* errors (not just the first), reading both the top-level `extensions.code` and the\n * nested App Management shape `extensions.app_errors.errors[].category`. The API can also return\n * `errors` as a string (e.g. some 401s), which yields no codes.\n *\n * @param errors - The `errors` value from a GraphQL response (array, string, or undefined).\n * @returns Every string code/category found, in document order.\n */\nexport function graphQLErrorCodes(errors: unknown): string[] {\n if (!Array.isArray(errors)) return []\n\n return errors.flatMap((entry) => {\n const found: string[] = []\n const error = entry as {extensions?: {code?: unknown; app_errors?: {errors?: unknown}}} | undefined\n\n const code = error?.extensions?.code\n if (typeof code === 'string') found.push(code)\n\n const appErrors = error?.extensions?.app_errors?.errors\n if (Array.isArray(appErrors)) {\n for (const appError of appErrors) {\n const category = (appError as {category?: unknown} | undefined)?.category\n if (typeof category === 'string') found.push(category)\n }\n }\n\n return found\n })\n}\n\n/**\n * Whether a single code is a rate-limit signal (`THROTTLED` or `429`).\n *\n * Shared with the retry path (`isThrottled` in `private/node/api.ts`), where these codes signal\n * rate limiting even at HTTP 200.\n */\nexport function isRateLimitCode(code: string | undefined): boolean {\n return code !== undefined && RATE_LIMIT_CODES.has(code)\n}\n\n/**\n * Whether a single code/category is a permission / access-denied signal.\n */\nexport function isPermissionCode(code: string | undefined): boolean {\n return code !== undefined && PERMISSION_CODES.has(code)\n}\n\n/**\n * Whether any GraphQL error carries a rate-limit code. Convenience for suppression logic that only\n * needs a boolean over the raw `errors` value.\n *\n * @param errors - The `errors` value from a GraphQL response.\n * @returns True when a rate-limit code is present in any error.\n */\nexport function hasRateLimitCode(errors: unknown): boolean {\n return graphQLErrorCodes(errors).some(isRateLimitCode)\n}\n"]}
|
|
@@ -22,6 +22,7 @@ export async function startAnalytics({ commandContent, args, currentTime = new D
|
|
|
22
22
|
startTime: currentTime,
|
|
23
23
|
startCommand,
|
|
24
24
|
startArgs: args,
|
|
25
|
+
requiresSyncAnalytics: commandClass?.requiresSyncAnalytics ?? false,
|
|
25
26
|
},
|
|
26
27
|
}));
|
|
27
28
|
await metadata.addPublicMetadata(() => ({
|
|
@@ -32,6 +33,16 @@ export async function startAnalytics({ commandContent, args, currentTime = new D
|
|
|
32
33
|
cmd_all_force: flagIncluded('force', commandClass) ? args.includes('--force') : undefined,
|
|
33
34
|
}));
|
|
34
35
|
}
|
|
36
|
+
const allowedShopifyEnvironmentVariableNames = new Set([
|
|
37
|
+
'SHOPIFY_INVOKED_BY',
|
|
38
|
+
'SHOPIFY_CLI_AGENT',
|
|
39
|
+
'SHOPIFY_CLI_AGENT_INFO',
|
|
40
|
+
'SHOPIFY_CLI_AGENT_IDS',
|
|
41
|
+
'SHOPIFY_CLI_AGENT_VERSION',
|
|
42
|
+
'SHOPIFY_CLI_AGENT_RUN_ID',
|
|
43
|
+
'SHOPIFY_CLI_AGENT_SESSION_ID',
|
|
44
|
+
'SHOPIFY_CLI_AGENT_PROVIDER',
|
|
45
|
+
]);
|
|
35
46
|
export async function getEnvironmentData(config) {
|
|
36
47
|
const ciplatform = ciPlatform();
|
|
37
48
|
const pluginNames = getPluginNames(config);
|
|
@@ -63,13 +74,7 @@ export async function getSensitiveEnvironmentData(config) {
|
|
|
63
74
|
};
|
|
64
75
|
}
|
|
65
76
|
function getShopifyEnvironmentVariables() {
|
|
66
|
-
|
|
67
|
-
// variables. The current contract is intentionally lightweight and is kept in
|
|
68
|
-
// the sensitive payload until we prove which dimensions deserve first-class
|
|
69
|
-
// Monorail fields, e.g. SHOPIFY_CLI_AGENT, SHOPIFY_CLI_AGENT_VERSION,
|
|
70
|
-
// SHOPIFY_CLI_AGENT_RUN_ID, SHOPIFY_CLI_AGENT_SESSION_ID, and
|
|
71
|
-
// SHOPIFY_CLI_AGENT_PROVIDER.
|
|
72
|
-
return Object.fromEntries(Object.entries(process.env).filter(([key]) => key.startsWith('SHOPIFY_')));
|
|
77
|
+
return Object.fromEntries(Object.entries(process.env).filter(([key]) => allowedShopifyEnvironmentVariableNames.has(key)));
|
|
73
78
|
}
|
|
74
79
|
function getPluginNames(config) {
|
|
75
80
|
const pluginNames = [...config.plugins.keys()];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAA;AAClD,OAAO,EAAC,qBAAqB,EAAC,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAC,iBAAiB,EAAE,2BAA2B,EAAC,MAAM,2CAA2C,CAAA;AAGxG,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AACzD,OAAO,EAAC,eAAe,EAAC,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAC,MAAM,oCAAoC,CAAA;AAC3F,OAAO,EAAC,GAAG,EAAC,MAAM,2BAA2B,CAAA;AAC7C,OAAO,EAAC,sBAAsB,EAAE,+BAA+B,EAAC,MAAM,gCAAgC,CAAA;AACtG,OAAO,EAAC,KAAK,EAAC,MAAM,6BAA6B,CAAA;AAWjD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EACnC,cAAc,EACd,IAAI,EACJ,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAClC,YAAY,GACC;IACb,IAAI,YAAY,GAAW,cAAc,CAAC,OAAO,CAAA;IACjD,IAAI,YAAY,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAChG,YAAY,GAAI,YAAmC,CAAC,qBAAqB,EAAE,IAAI,cAAc,CAAC,OAAO,CAAA;IACvG,CAAC;IAED,IAAI,UAAU,GAAG,YAAY,EAAE,MAAM,EAAE,IAAI,CAAA;IAC3C,IAAI,YAAY,IAAI,kBAAkB,IAAI,YAAY,EAAE,CAAC;QACvD,UAAU,GAAG,YAAY,CAAC,gBAA0B,CAAA;IACtD,CAAC;IAED,MAAM,QAAQ,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,mBAAmB,EAAE;YACnB,SAAS,EAAE,WAAW;YACtB,YAAY;YACZ,SAAS,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {getLastSeenAuthMethod} from './session.js'\nimport {getAutoUpgradeEnabled} from './conf-store.js'\nimport {hashString} from '../../public/node/crypto.js'\nimport {getPackageManager, packageManagerFromUserAgent} from '../../public/node/node-package-manager.js'\nimport BaseCommand from '../../public/node/base-command.js'\nimport {CommandContent} from '../../public/node/hooks/prerun.js'\nimport * as metadata from '../../public/node/metadata.js'\nimport {platformAndArch} from '../../public/node/os.js'\nimport {ciPlatform, cloudEnvironment, macAddress} from '../../public/node/context/local.js'\nimport {cwd} from '../../public/node/path.js'\nimport {currentProcessIsGlobal, inferPackageManagerForGlobalCLI} from '../../public/node/is-global.js'\nimport {isWsl} from '../../public/node/system.js'\n\nimport {Command, Interfaces} from '@oclif/core'\n\ninterface StartOptions {\n commandContent: CommandContent\n args: string[]\n currentTime?: number\n commandClass?: Command.Class | typeof BaseCommand\n}\n\nexport async function startAnalytics({\n commandContent,\n args,\n currentTime = new Date().getTime(),\n commandClass,\n}: StartOptions): Promise<void> {\n let startCommand: string = commandContent.command\n if (commandClass && Object.prototype.hasOwnProperty.call(commandClass, 'analyticsNameOverride')) {\n startCommand = (commandClass as typeof BaseCommand).analyticsNameOverride() ?? commandContent.command\n }\n\n let pluginName = commandClass?.plugin?.name\n if (commandClass && 'customPluginName' in commandClass) {\n pluginName = commandClass.customPluginName as string\n }\n\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n startTime: currentTime,\n startCommand,\n startArgs: args,\n requiresSyncAnalytics: (commandClass as typeof BaseCommand | undefined)?.requiresSyncAnalytics ?? false,\n },\n }))\n\n await metadata.addPublicMetadata(() => ({\n cmd_all_launcher: packageManagerFromUserAgent(),\n cmd_all_alias_used: commandContent.alias,\n cmd_all_topic: commandContent.topic,\n cmd_all_plugin: pluginName,\n cmd_all_force: flagIncluded('force', commandClass) ? args.includes('--force') : undefined,\n }))\n}\n\ninterface EnvironmentData {\n uname: string\n env_ci: boolean\n env_ci_platform?: string\n env_plugin_installed_any_custom: boolean\n env_plugin_installed_shopify: string\n env_shell: string\n env_web_ide: string | undefined\n env_device_id: string\n env_cloud: string\n env_package_manager: string\n env_install_package_manager: string\n env_is_global: boolean\n env_auth_method: string\n env_is_wsl: boolean\n env_build_repository: string\n env_auto_upgrade_enabled: boolean | null\n}\n\nconst allowedShopifyEnvironmentVariableNames = new Set([\n 'SHOPIFY_INVOKED_BY',\n 'SHOPIFY_CLI_AGENT',\n 'SHOPIFY_CLI_AGENT_INFO',\n 'SHOPIFY_CLI_AGENT_IDS',\n 'SHOPIFY_CLI_AGENT_VERSION',\n 'SHOPIFY_CLI_AGENT_RUN_ID',\n 'SHOPIFY_CLI_AGENT_SESSION_ID',\n 'SHOPIFY_CLI_AGENT_PROVIDER',\n])\n\nexport async function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData> {\n const ciplatform = ciPlatform()\n\n const pluginNames = getPluginNames(config)\n const shopifyPlugins = pluginNames.filter((plugin) => plugin.startsWith('@shopify/'))\n\n const {platform, arch} = platformAndArch()\n\n return {\n uname: `${platform} ${arch}`,\n env_ci: ciplatform.isCI,\n env_ci_platform: ciplatform.name,\n env_plugin_installed_any_custom: pluginNames.length !== shopifyPlugins.length,\n env_plugin_installed_shopify: JSON.stringify(shopifyPlugins),\n env_shell: config.shell,\n env_web_ide: cloudEnvironment().editor ? cloudEnvironment().platform : undefined,\n env_device_id: hashString(await macAddress()),\n env_cloud: cloudEnvironment().platform,\n env_package_manager: await getPackageManager(cwd()),\n env_install_package_manager: inferPackageManagerForGlobalCLI(),\n env_is_global: currentProcessIsGlobal(),\n env_auth_method: await getLastSeenAuthMethod(),\n env_is_wsl: await isWsl(),\n env_build_repository: process.env.SHOPIFY_CLI_BUILD_REPO ?? 'unknown',\n env_auto_upgrade_enabled: getAutoUpgradeEnabled() ?? null,\n }\n}\n\nexport async function getSensitiveEnvironmentData(config: Interfaces.Config) {\n return {\n env_plugin_installed_all: JSON.stringify(getPluginNames(config)),\n env_shopify_variables: JSON.stringify(getShopifyEnvironmentVariables()),\n }\n}\n\nfunction getShopifyEnvironmentVariables() {\n return Object.fromEntries(\n Object.entries(process.env).filter(([key]) => allowedShopifyEnvironmentVariableNames.has(key)),\n )\n}\n\nfunction getPluginNames(config: Interfaces.Config) {\n const pluginNames = [...config.plugins.keys()]\n return pluginNames.sort().filter((plugin) => !plugin.startsWith('@oclif/'))\n}\n\nfunction flagIncluded(flag: string, commandClass?: Command.Class | typeof BaseCommand) {\n if (!commandClass) return false\n\n const commandFlags = commandClass.flags ?? {}\n return Object.keys(commandFlags).includes(flag)\n}\n"]}
|
|
@@ -3,6 +3,7 @@ import { isUnitTest, isVerbose } from '../../../public/node/context/local.js';
|
|
|
3
3
|
import { AbortError } from '../../../public/node/error.js';
|
|
4
4
|
import https from 'https';
|
|
5
5
|
class RequestClientError extends AbortError {
|
|
6
|
+
statusCode;
|
|
6
7
|
constructor(message, statusCode) {
|
|
7
8
|
const tryMessage = statusCode === 403
|
|
8
9
|
? 'Ensure you are using the correct account. You can switch with `shopify auth login`'
|
|
@@ -12,6 +13,8 @@ class RequestClientError extends AbortError {
|
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
export class GraphQLClientError extends RequestClientError {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
errors;
|
|
15
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
19
|
constructor(message, statusCode, errors) {
|
|
17
20
|
super(message, statusCode);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../../../../src/private/node/api/headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,uCAAuC,CAAA;AAC3E,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,kBAAmB,SAAQ,UAAU;
|
|
1
|
+
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../../../../src/private/node/api/headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,mCAAmC,CAAA;AACjE,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,uCAAuC,CAAA;AAC3E,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,kBAAmB,SAAQ,UAAU;IACzC,UAAU,CAAQ;IAClB,YAAmB,OAAe,EAAE,UAAkB;QACpD,MAAM,UAAU,GACd,UAAU,KAAK,GAAG;YAChB,CAAC,CAAC,oFAAoF;YACtF,CAAC,CAAC,SAAS,CAAA;QACf,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC1B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;CACF;AACD,MAAM,OAAO,kBAAmB,SAAQ,kBAAkB;IACxD,8DAA8D;IAC9D,MAAM,CAAQ;IAEd,8DAA8D;IAC9D,YAAmB,OAAe,EAAE,UAAkB,EAAE,MAAc;QACpE,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAA;IACxB,CAAC;CACF;AAED,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;AAE5F;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA+B;IACpE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,SAAS,GAA2B,EAAE,CAAA;IAC5C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACtC,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9F,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAE,CAAA;QACtC,CAAC;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;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,MAAM,SAAS,GAAG,kBAAkB,eAAe,EAAE,CAAA;IAErD,MAAM,OAAO,GAA2B;QACtC,YAAY,EAAE,SAAS;QACvB,YAAY,EAAE,YAAY;QAC1B,0DAA0D;QAC1D,oBAAoB,EAAE,OAAO,CAAC,QAAQ;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAA;IACD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAA;QAEhF,OAAO,CAAC,aAAa,GAAG,UAAU,CAAA;QAClC,OAAO,CAAC,wBAAwB,CAAC,GAAG,UAAU,CAAA;IAChD,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC;QACrB,kBAAkB,EAAE,IAAI;QACxB,SAAS,EAAE,IAAI;KAChB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import {CLI_KIT_VERSION} from '../../../public/common/version.js'\nimport {isUnitTest, isVerbose} from '../../../public/node/context/local.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport https from 'https'\n\nclass RequestClientError extends AbortError {\n statusCode: number\n public constructor(message: string, statusCode: number) {\n const tryMessage =\n statusCode === 403\n ? 'Ensure you are using the correct account. You can switch with `shopify auth login`'\n : undefined\n super(message, tryMessage)\n this.statusCode = statusCode\n }\n}\nexport class GraphQLClientError extends RequestClientError {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n errors?: any[]\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public constructor(message: string, statusCode: number, errors?: any[]) {\n super(message, statusCode)\n this.errors = errors\n this.stack = undefined\n }\n}\n\nconst SENSITIVE_HEADERS = ['token', 'authorization', 'subject_token', 'cookie', 'signature']\n\n/**\n * Removes the sensitive data from the headers and outputs them as a string.\n * @param headers - HTTP headers.\n * @returns A sanitized version of the headers as a string.\n */\nexport function sanitizedHeadersOutput(headers: Record<string, string>): string {\n if (!isVerbose() && !isUnitTest()) {\n return ''\n }\n\n const sanitized: Record<string, string> = {}\n Object.keys(headers).forEach((header) => {\n if (SENSITIVE_HEADERS.find((keyword) => header.toLowerCase().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 function buildHeaders(token?: string): Record<string, string> {\n const userAgent = `Shopify CLI; v=${CLI_KIT_VERSION}`\n\n const headers: Record<string, string> = {\n 'User-Agent': userAgent,\n 'Keep-Alive': 'timeout=30',\n // 'Sec-CH-UA': secCHUA, This header requires the Git sha.\n 'Sec-CH-UA-PLATFORM': process.platform,\n 'Content-Type': 'application/json',\n }\n if (token) {\n const authString = token.match(/^shp(at|ua|ca|tka)/) ? token : `Bearer ${token}`\n\n headers.authorization = authString\n headers['X-Shopify-Access-Token'] = authString\n }\n\n return headers\n}\n\n/**\n * This utility function returns the https.Agent to use for a given service.\n */\nexport async function httpsAgent(): Promise<https.Agent> {\n return new https.Agent({\n rejectUnauthorized: true,\n keepAlive: true,\n })\n}\n"]}
|
package/dist/private/node/api.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { sanitizedHeadersOutput } from './api/headers.js';
|
|
2
2
|
import { sanitizeURL } from './api/urls.js';
|
|
3
|
+
import { hasRateLimitCode } from './analytics/graphql-error-codes.js';
|
|
3
4
|
import { sleepWithBackoffUntil } from './sleep-with-backoff.js';
|
|
4
5
|
import { outputDebug } from '../../public/node/output.js';
|
|
5
6
|
import { recordRetry } from '../../public/node/analytics.js';
|
|
@@ -128,7 +129,7 @@ async function makeVerboseRequest(requestOptions) {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
const sanitizedHeaders = sanitizedHeadersOutput(responseHeaders);
|
|
131
|
-
if (
|
|
132
|
+
if (isThrottled(err)) {
|
|
132
133
|
let delayMs;
|
|
133
134
|
try {
|
|
134
135
|
delayMs = responseHeaders['retry-after'] ? Number.parseInt(responseHeaders['retry-after'], 10) : undefined;
|
|
@@ -187,16 +188,15 @@ async function makeVerboseRequest(requestOptions) {
|
|
|
187
188
|
requestId: responseHeaders['x-request-id'],
|
|
188
189
|
};
|
|
189
190
|
}
|
|
190
|
-
|
|
191
|
+
// Shopify GraphQL APIs signal rate limiting with `extensions.code` set to
|
|
192
|
+
// `THROTTLED` (often on a 200 response) or `429` — the same codes that
|
|
193
|
+
// crash-report suppression and analytics grouping already treat as rate
|
|
194
|
+
// limiting via this shared helper.
|
|
195
|
+
function isThrottled(error) {
|
|
191
196
|
if (error.response.status === 429) {
|
|
192
197
|
return true;
|
|
193
198
|
}
|
|
194
|
-
|
|
195
|
-
// Therefore error.response.errors can be a string or GraphQLError[]
|
|
196
|
-
if (typeof error.response.errors === 'string') {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
return error.response.errors?.some((error) => error.extensions?.code === '429') ?? false;
|
|
199
|
+
return hasRateLimitCode(error.response.errors);
|
|
200
200
|
}
|
|
201
201
|
export async function simpleRequestWithDebugLog(requestOptions, errorHandler) {
|
|
202
202
|
const result = await makeVerboseRequest(requestOptions);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"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","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {sanitizeURL} from './api/urls.js'\nimport {sleepWithBackoffUntil} from './sleep-with-backoff.js'\nimport {outputDebug} from '../../public/node/output.js'\nimport {recordRetry} from '../../public/node/analytics.js'\n\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\n\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management']\n\nconst DEFAULT_RETRY_DELAY_MS = 1000\nconst DEFAULT_RETRY_LIMIT = 10\n\nexport type NetworkRetryBehaviour =\n | {\n useNetworkLevelRetry: true\n maxRetryTimeMs: number\n recordCommandRetries?: boolean\n }\n | {\n useNetworkLevelRetry: false\n recordCommandRetries?: boolean\n }\n\ntype RequestOptions<T> = {\n request: () => Promise<T>\n url: string\n} & NetworkRetryBehaviour\n\nconst interestingResponseHeaders = new Set([\n 'cache-control',\n 'content-type',\n 'etag',\n 'x-request-id',\n 'server-timing',\n 'retry-after',\n])\n\nfunction responseHeaderIsInteresting(header: string): boolean {\n return interestingResponseHeaders.has(header)\n}\n\ninterface CommonResponse {\n duration: number\n sanitizedHeaders: string\n sanitizedUrl: string\n requestId?: string\n}\n\ntype OkResponse<T> = CommonResponse & {status: 'ok'; response: T}\ntype ClientErrorResponse = CommonResponse & {status: 'client-error'; clientError: ClientError}\ntype UnknownErrorResponse = CommonResponse & {status: 'unknown-error'; error: unknown}\ntype CanRetryErrorResponse = CommonResponse & {\n status: 'can-retry'\n clientError: ClientError\n delayMs: number | undefined\n}\ntype UnauthorizedErrorResponse = CommonResponse & {\n status: 'unauthorized'\n clientError: ClientError\n delayMs: number | undefined\n}\n\ntype VerboseResponse<T> =\n | OkResponse<T>\n | ClientErrorResponse\n | UnknownErrorResponse\n | CanRetryErrorResponse\n | UnauthorizedErrorResponse\n\n/**\n * Checks if an error is a transient network error that is likely to recover with retries.\n *\n * Use this function for retry logic. Use isNetworkError for error classification.\n *\n * Examples of transient errors (worth retrying):\n * - Connection timeouts, resets, and aborts\n * - DNS failures (enotfound, getaddrinfo, eai_again) - can be temporary\n * - Socket disconnects and hang ups\n * - Premature connection closes\n */\nexport function isTransientNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n const transientErrorMessages = [\n 'socket hang up',\n 'econnreset',\n 'econnaborted',\n 'enotfound',\n 'enetunreach',\n 'network socket disconnected',\n 'etimedout',\n 'econnrefused',\n 'eai_again',\n 'epipe',\n 'the operation was aborted',\n 'timeout',\n 'premature close',\n 'getaddrinfo',\n ]\n const errorMessage = error.message.toLowerCase()\n const anyMatches = transientErrorMessages.some((issueMessage) => errorMessage.includes(issueMessage))\n const missingReason = /^request to .* failed, reason:\\s*$/.test(errorMessage)\n return anyMatches || missingReason\n }\n return false\n}\n\n/**\n * Checks if an error is any kind of network-related error (connection issues, timeouts, DNS failures,\n * TLS/certificate errors, etc.) rather than an application logic error.\n *\n * These errors should be reported as user-facing errors (AbortError) rather than bugs (BugError),\n * regardless of whether they are transient or permanent.\n *\n * Examples include:\n * - Transient: connection timeouts, socket hang ups, temporary DNS failures\n * - Permanent: certificate validation failures, misconfigured SSL\n */\nexport function isNetworkError(error: unknown): boolean {\n // First check if it's a transient network error\n if (isTransientNetworkError(error)) {\n return true\n }\n\n // Then check for permanent network errors (SSL/TLS/certificate issues)\n if (error instanceof Error) {\n const permanentNetworkErrorMessages = ['certificate', 'cert', 'tls', 'ssl', 'altnames']\n const errorMessage = error.message.toLowerCase()\n return permanentNetworkErrorMessages.some((issueMessage) => errorMessage.includes(issueMessage))\n }\n\n return false\n}\n\nasync function runRequestWithNetworkLevelRetry<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n): Promise<T> {\n if (!requestOptions.useNetworkLevelRetry) {\n return requestOptions.request()\n }\n\n let lastSeenError: unknown\n\n for await (const _delayMs of sleepWithBackoffUntil(requestOptions.maxRetryTimeMs)) {\n try {\n return await requestOptions.request()\n } catch (err) {\n lastSeenError = err\n if (!isTransientNetworkError(err)) {\n throw err\n }\n\n // Record command retries\n if (requestOptions.recordCommandRetries) {\n recordRetry(requestOptions.url, `network-retry:${(err as Error).message}`)\n }\n\n outputDebug(`Retrying request to ${requestOptions.url} due to network error ${err}`)\n }\n }\n throw lastSeenError\n}\n\nasync function makeVerboseRequest<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n): Promise<VerboseResponse<T>> {\n const t0 = performance.now()\n let duration = 0\n const responseHeaders: Record<string, string> = {}\n const sanitizedUrl = sanitizeURL(requestOptions.url)\n let response: T = {} as T\n try {\n response = await runRequestWithNetworkLevelRetry(requestOptions)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n response.headers.forEach((value: any, key: any) => {\n if (responseHeaderIsInteresting(key)) responseHeaders[key] = value\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err) {\n const t1 = performance.now()\n duration = Math.round(t1 - t0)\n\n if (err instanceof ClientError) {\n if (err.response.headers) {\n for (const [key, value] of err.response.headers as Iterable<[string, string]>) {\n if (responseHeaderIsInteresting(key)) responseHeaders[key] = value\n }\n }\n const sanitizedHeaders = sanitizedHeadersOutput(responseHeaders)\n\n if (errorsIncludeStatus429(err)) {\n let delayMs: number | undefined\n\n try {\n delayMs = responseHeaders['retry-after'] ? Number.parseInt(responseHeaders['retry-after'], 10) : undefined\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n // ignore errors in extracting retry-after header\n }\n return {\n status: 'can-retry',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n delayMs,\n }\n } else if (err.response.status === 401) {\n return {\n status: 'unauthorized',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n delayMs: 500,\n }\n }\n\n return {\n status: 'client-error',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n }\n return {\n status: 'unknown-error',\n error: err,\n duration,\n sanitizedHeaders: sanitizedHeadersOutput(responseHeaders),\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n }\n const t1 = performance.now()\n duration = Math.round(t1 - t0)\n return {\n status: 'ok',\n response,\n duration,\n sanitizedHeaders: sanitizedHeadersOutput(responseHeaders),\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n}\n\nfunction errorsIncludeStatus429(error: ClientError): boolean {\n if (error.response.status === 429) {\n return true\n }\n\n // GraphQL returns a 401 with a string error message when auth fails\n // Therefore error.response.errors can be a string or GraphQLError[]\n if (typeof error.response.errors === 'string') {\n return false\n }\n return error.response.errors?.some((error) => error.extensions?.code === '429') ?? false\n}\n\nexport async function simpleRequestWithDebugLog<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => unknown,\n): Promise<T> {\n const result = await makeVerboseRequest(requestOptions)\n\n outputDebug(`Request to ${result.sanitizedUrl} completed in ${result.duration} ms\nWith response headers:\n${result.sanitizedHeaders}\n `)\n\n switch (result.status) {\n case 'ok': {\n return result.response\n }\n case 'client-error': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n case 'unknown-error': {\n if (errorHandler) {\n throw errorHandler(result.error, result.requestId)\n } else {\n throw result.error\n }\n }\n case 'can-retry': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n case 'unauthorized': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n }\n}\n\n/**\n * Makes a HTTP request to some API, retrying if response headers indicate a retryable error.\n *\n * If a request fails with a 429, the retry-after header determines a delay before an automatic retry is performed.\n *\n * If unauthorizedHandler is provided, then it will be called in the case of a 401 and a retry performed. This allows\n * for a token refresh for instance.\n *\n * If there's a network error, e.g. DNS fails to resolve, then API calls are automatically retried.\n *\n * @param request - A function that returns a promise of the response\n * @param url - The URL to request\n * @param errorHandler - A function that handles errors\n * @param unauthorizedHandler - A function that handles unauthorized errors\n * @param retryOptions - Options for the retry\n * @returns The response from the request\n */\nexport async function retryAwareRequest<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => unknown,\n retryOptions: {\n limitRetriesTo?: number\n defaultDelayMs?: number\n scheduleDelay: (fn: () => void, delay: number) => void\n } = {\n scheduleDelay: setTimeout,\n },\n): Promise<T> {\n let retriesUsed = 0\n const limitRetriesTo = retryOptions.limitRetriesTo ?? DEFAULT_RETRY_LIMIT\n\n let result = await makeVerboseRequest(requestOptions)\n\n outputDebug(`Request to ${result.sanitizedUrl} completed in ${result.duration} ms\nWith response headers:\n${result.sanitizedHeaders}\n `)\n\n while (true) {\n if (result.status === 'ok') {\n if (retriesUsed > 0) {\n outputDebug(`Request to ${result.sanitizedUrl} succeeded after ${retriesUsed} retries`)\n }\n return result.response\n } else if (result.status === 'client-error') {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n } else if (result.status === 'unknown-error') {\n if (errorHandler) {\n throw errorHandler(result.error, result.requestId)\n } else {\n throw result.error\n }\n } else if (result.status === 'unauthorized') {\n throw result.clientError\n }\n\n if (limitRetriesTo <= retriesUsed) {\n outputDebug(`${limitRetriesTo} retries exhausted for request to ${result.sanitizedUrl}`)\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n retriesUsed += 1\n\n // Record command retries\n if (requestOptions.recordCommandRetries) {\n recordRetry(requestOptions.url, `http-retry-${retriesUsed}:${result.status}:`)\n }\n\n // prefer to wait based on a header if given; the caller's preference if not; and a default if neither.\n const retryDelayMs = result.delayMs ?? retryOptions.defaultDelayMs ?? DEFAULT_RETRY_DELAY_MS\n outputDebug(`Scheduling retry request #${retriesUsed} to ${result.sanitizedUrl} in ${retryDelayMs} ms`)\n\n // eslint-disable-next-line no-await-in-loop\n result = await new Promise<VerboseResponse<T>>((resolve) => {\n retryOptions.scheduleDelay(() => {\n resolve(makeVerboseRequest(requestOptions))\n }, retryDelayMs)\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"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","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {sanitizeURL} from './api/urls.js'\nimport {hasRateLimitCode} from './analytics/graphql-error-codes.js'\nimport {sleepWithBackoffUntil} from './sleep-with-backoff.js'\nimport {outputDebug} from '../../public/node/output.js'\nimport {recordRetry} from '../../public/node/analytics.js'\n\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\n\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management']\n\nconst DEFAULT_RETRY_DELAY_MS = 1000\nconst DEFAULT_RETRY_LIMIT = 10\n\nexport type NetworkRetryBehaviour =\n | {\n useNetworkLevelRetry: true\n maxRetryTimeMs: number\n recordCommandRetries?: boolean\n }\n | {\n useNetworkLevelRetry: false\n recordCommandRetries?: boolean\n }\n\ntype RequestOptions<T> = {\n request: () => Promise<T>\n url: string\n} & NetworkRetryBehaviour\n\nconst interestingResponseHeaders = new Set([\n 'cache-control',\n 'content-type',\n 'etag',\n 'x-request-id',\n 'server-timing',\n 'retry-after',\n])\n\nfunction responseHeaderIsInteresting(header: string): boolean {\n return interestingResponseHeaders.has(header)\n}\n\ninterface CommonResponse {\n duration: number\n sanitizedHeaders: string\n sanitizedUrl: string\n requestId?: string\n}\n\ntype OkResponse<T> = CommonResponse & {status: 'ok'; response: T}\ntype ClientErrorResponse = CommonResponse & {status: 'client-error'; clientError: ClientError}\ntype UnknownErrorResponse = CommonResponse & {status: 'unknown-error'; error: unknown}\ntype CanRetryErrorResponse = CommonResponse & {\n status: 'can-retry'\n clientError: ClientError\n delayMs: number | undefined\n}\ntype UnauthorizedErrorResponse = CommonResponse & {\n status: 'unauthorized'\n clientError: ClientError\n delayMs: number | undefined\n}\n\ntype VerboseResponse<T> =\n | OkResponse<T>\n | ClientErrorResponse\n | UnknownErrorResponse\n | CanRetryErrorResponse\n | UnauthorizedErrorResponse\n\n/**\n * Checks if an error is a transient network error that is likely to recover with retries.\n *\n * Use this function for retry logic. Use isNetworkError for error classification.\n *\n * Examples of transient errors (worth retrying):\n * - Connection timeouts, resets, and aborts\n * - DNS failures (enotfound, getaddrinfo, eai_again) - can be temporary\n * - Socket disconnects and hang ups\n * - Premature connection closes\n */\nexport function isTransientNetworkError(error: unknown): boolean {\n if (error instanceof Error) {\n const transientErrorMessages = [\n 'socket hang up',\n 'econnreset',\n 'econnaborted',\n 'enotfound',\n 'enetunreach',\n 'network socket disconnected',\n 'etimedout',\n 'econnrefused',\n 'eai_again',\n 'epipe',\n 'the operation was aborted',\n 'timeout',\n 'premature close',\n 'getaddrinfo',\n ]\n const errorMessage = error.message.toLowerCase()\n const anyMatches = transientErrorMessages.some((issueMessage) => errorMessage.includes(issueMessage))\n const missingReason = /^request to .* failed, reason:\\s*$/.test(errorMessage)\n return anyMatches || missingReason\n }\n return false\n}\n\n/**\n * Checks if an error is any kind of network-related error (connection issues, timeouts, DNS failures,\n * TLS/certificate errors, etc.) rather than an application logic error.\n *\n * These errors should be reported as user-facing errors (AbortError) rather than bugs (BugError),\n * regardless of whether they are transient or permanent.\n *\n * Examples include:\n * - Transient: connection timeouts, socket hang ups, temporary DNS failures\n * - Permanent: certificate validation failures, misconfigured SSL\n */\nexport function isNetworkError(error: unknown): boolean {\n // First check if it's a transient network error\n if (isTransientNetworkError(error)) {\n return true\n }\n\n // Then check for permanent network errors (SSL/TLS/certificate issues)\n if (error instanceof Error) {\n const permanentNetworkErrorMessages = ['certificate', 'cert', 'tls', 'ssl', 'altnames']\n const errorMessage = error.message.toLowerCase()\n return permanentNetworkErrorMessages.some((issueMessage) => errorMessage.includes(issueMessage))\n }\n\n return false\n}\n\nasync function runRequestWithNetworkLevelRetry<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n): Promise<T> {\n if (!requestOptions.useNetworkLevelRetry) {\n return requestOptions.request()\n }\n\n let lastSeenError: unknown\n\n for await (const _delayMs of sleepWithBackoffUntil(requestOptions.maxRetryTimeMs)) {\n try {\n return await requestOptions.request()\n } catch (err) {\n lastSeenError = err\n if (!isTransientNetworkError(err)) {\n throw err\n }\n\n // Record command retries\n if (requestOptions.recordCommandRetries) {\n recordRetry(requestOptions.url, `network-retry:${(err as Error).message}`)\n }\n\n outputDebug(`Retrying request to ${requestOptions.url} due to network error ${err}`)\n }\n }\n throw lastSeenError\n}\n\nasync function makeVerboseRequest<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n): Promise<VerboseResponse<T>> {\n const t0 = performance.now()\n let duration = 0\n const responseHeaders: Record<string, string> = {}\n const sanitizedUrl = sanitizeURL(requestOptions.url)\n let response: T = {} as T\n try {\n response = await runRequestWithNetworkLevelRetry(requestOptions)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n response.headers.forEach((value: any, key: any) => {\n if (responseHeaderIsInteresting(key)) responseHeaders[key] = value\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err) {\n const t1 = performance.now()\n duration = Math.round(t1 - t0)\n\n if (err instanceof ClientError) {\n if (err.response.headers) {\n for (const [key, value] of err.response.headers as Iterable<[string, string]>) {\n if (responseHeaderIsInteresting(key)) responseHeaders[key] = value\n }\n }\n const sanitizedHeaders = sanitizedHeadersOutput(responseHeaders)\n\n if (isThrottled(err)) {\n let delayMs: number | undefined\n\n try {\n delayMs = responseHeaders['retry-after'] ? Number.parseInt(responseHeaders['retry-after'], 10) : undefined\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n // ignore errors in extracting retry-after header\n }\n return {\n status: 'can-retry',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n delayMs,\n }\n } else if (err.response.status === 401) {\n return {\n status: 'unauthorized',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n delayMs: 500,\n }\n }\n\n return {\n status: 'client-error',\n clientError: err,\n duration,\n sanitizedHeaders,\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n }\n return {\n status: 'unknown-error',\n error: err,\n duration,\n sanitizedHeaders: sanitizedHeadersOutput(responseHeaders),\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n }\n const t1 = performance.now()\n duration = Math.round(t1 - t0)\n return {\n status: 'ok',\n response,\n duration,\n sanitizedHeaders: sanitizedHeadersOutput(responseHeaders),\n sanitizedUrl,\n requestId: responseHeaders['x-request-id'],\n }\n}\n\n// Shopify GraphQL APIs signal rate limiting with `extensions.code` set to\n// `THROTTLED` (often on a 200 response) or `429` — the same codes that\n// crash-report suppression and analytics grouping already treat as rate\n// limiting via this shared helper.\nfunction isThrottled(error: ClientError): boolean {\n if (error.response.status === 429) {\n return true\n }\n return hasRateLimitCode(error.response.errors)\n}\n\nexport async function simpleRequestWithDebugLog<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => unknown,\n): Promise<T> {\n const result = await makeVerboseRequest(requestOptions)\n\n outputDebug(`Request to ${result.sanitizedUrl} completed in ${result.duration} ms\nWith response headers:\n${result.sanitizedHeaders}\n `)\n\n switch (result.status) {\n case 'ok': {\n return result.response\n }\n case 'client-error': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n case 'unknown-error': {\n if (errorHandler) {\n throw errorHandler(result.error, result.requestId)\n } else {\n throw result.error\n }\n }\n case 'can-retry': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n case 'unauthorized': {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n }\n}\n\n/**\n * Makes a HTTP request to some API, retrying if response headers indicate a retryable error.\n *\n * If a request fails with a 429, the retry-after header determines a delay before an automatic retry is performed.\n *\n * If unauthorizedHandler is provided, then it will be called in the case of a 401 and a retry performed. This allows\n * for a token refresh for instance.\n *\n * If there's a network error, e.g. DNS fails to resolve, then API calls are automatically retried.\n *\n * @param request - A function that returns a promise of the response\n * @param url - The URL to request\n * @param errorHandler - A function that handles errors\n * @param unauthorizedHandler - A function that handles unauthorized errors\n * @param retryOptions - Options for the retry\n * @returns The response from the request\n */\nexport async function retryAwareRequest<T extends {headers: Headers; status: number}>(\n requestOptions: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => unknown,\n retryOptions: {\n limitRetriesTo?: number\n defaultDelayMs?: number\n scheduleDelay: (fn: () => void, delay: number) => void\n } = {\n scheduleDelay: setTimeout,\n },\n): Promise<T> {\n let retriesUsed = 0\n const limitRetriesTo = retryOptions.limitRetriesTo ?? DEFAULT_RETRY_LIMIT\n\n let result = await makeVerboseRequest(requestOptions)\n\n outputDebug(`Request to ${result.sanitizedUrl} completed in ${result.duration} ms\nWith response headers:\n${result.sanitizedHeaders}\n `)\n\n while (true) {\n if (result.status === 'ok') {\n if (retriesUsed > 0) {\n outputDebug(`Request to ${result.sanitizedUrl} succeeded after ${retriesUsed} retries`)\n }\n return result.response\n } else if (result.status === 'client-error') {\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n } else if (result.status === 'unknown-error') {\n if (errorHandler) {\n throw errorHandler(result.error, result.requestId)\n } else {\n throw result.error\n }\n } else if (result.status === 'unauthorized') {\n throw result.clientError\n }\n\n if (limitRetriesTo <= retriesUsed) {\n outputDebug(`${limitRetriesTo} retries exhausted for request to ${result.sanitizedUrl}`)\n if (errorHandler) {\n throw errorHandler(result.clientError, result.requestId)\n } else {\n throw result.clientError\n }\n }\n retriesUsed += 1\n\n // Record command retries\n if (requestOptions.recordCommandRetries) {\n recordRetry(requestOptions.url, `http-retry-${retriesUsed}:${result.status}:`)\n }\n\n // prefer to wait based on a header if given; the caller's preference if not; and a default if neither.\n const retryDelayMs = result.delayMs ?? retryOptions.defaultDelayMs ?? DEFAULT_RETRY_DELAY_MS\n outputDebug(`Scheduling retry request #${retriesUsed} to ${result.sanitizedUrl} in ${retryDelayMs} ms`)\n\n // eslint-disable-next-line no-await-in-loop\n result = await new Promise<VerboseResponse<T>>((resolve) => {\n retryOptions.scheduleDelay(() => {\n resolve(makeVerboseRequest(requestOptions))\n }, retryDelayMs)\n })\n }\n}\n"]}
|
|
@@ -9,7 +9,7 @@ let _instance;
|
|
|
9
9
|
* @returns CLIKitStore.
|
|
10
10
|
*/
|
|
11
11
|
function cliKitStore() {
|
|
12
|
-
_instance
|
|
12
|
+
_instance ??= new LocalStorage({ projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}` });
|
|
13
13
|
return _instance;
|
|
14
14
|
}
|
|
15
15
|
function sessionStoreKey() {
|
|
@@ -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 {isLocalEnvironment} from './context/service.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '../../public/node/output.js'\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 currentSessionId?: string\n devSessionStore?: string\n currentDevSessionId?: string\n cache?: Cache\n autoUpgradeEnabled?: boolean\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n _instance ??= new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n return _instance\n}\n\nfunction sessionStoreKey(): 'devSessionStore' | 'sessionStore' {\n return isLocalEnvironment() ? 'devSessionStore' : 'sessionStore'\n}\n\nfunction currentSessionIdKey(): 'currentDevSessionId' | 'currentSessionId' {\n return isLocalEnvironment() ? 'currentDevSessionId' : 'currentSessionId'\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSessions(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get(sessionStoreKey())\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSessions(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set(sessionStoreKey(), session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSessions(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete(sessionStoreKey())\n}\n\n/**\n * Get current session ID.\n *\n * @returns Current session ID.\n */\nexport function getCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting current session ID...`)\n return config.get(currentSessionIdKey())\n}\n\n/**\n * Set current session ID.\n *\n * @param sessionId - Session ID.\n */\nexport function setCurrentSessionId(sessionId: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting current session ID...`)\n config.set(currentSessionIdKey(), sessionId)\n}\n\n/**\n * Remove current session ID.\n */\nexport function removeCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing current session ID...`)\n config.delete(currentSessionIdKey())\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\n/**\n * Get auto-upgrade preference.\n * Defaults to true if the preference has never been explicitly set.\n *\n * @returns Whether auto-upgrade is enabled.\n */\nexport function getAutoUpgradeEnabled(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('autoUpgradeEnabled') ?? true\n}\n\n/**\n * Set auto-upgrade preference.\n *\n * @param enabled - Whether auto-upgrade should be enabled.\n */\nexport function setAutoUpgradeEnabled(enabled: boolean, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('autoUpgradeEnabled', enabled)\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<Record<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 {isLocalEnvironment} from './context/service.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '../../public/node/output.js'\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 currentSessionId?: string\n devSessionStore?: string\n currentDevSessionId?: string\n cache?: Cache\n autoUpgradeEnabled?: boolean\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n _instance ??= new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n return _instance\n}\n\nfunction sessionStoreKey(): 'devSessionStore' | 'sessionStore' {\n return isLocalEnvironment() ? 'devSessionStore' : 'sessionStore'\n}\n\nfunction currentSessionIdKey(): 'currentDevSessionId' | 'currentSessionId' {\n return isLocalEnvironment() ? 'currentDevSessionId' : 'currentSessionId'\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSessions(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get(sessionStoreKey())\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSessions(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set(sessionStoreKey(), session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSessions(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete(sessionStoreKey())\n}\n\n/**\n * Get current session ID.\n *\n * @returns Current session ID.\n */\nexport function getCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting current session ID...`)\n return config.get(currentSessionIdKey())\n}\n\n/**\n * Set current session ID.\n *\n * @param sessionId - Session ID.\n */\nexport function setCurrentSessionId(sessionId: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting current session ID...`)\n config.set(currentSessionIdKey(), sessionId)\n}\n\n/**\n * Remove current session ID.\n */\nexport function removeCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing current session ID...`)\n config.delete(currentSessionIdKey())\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\n/**\n * Get auto-upgrade preference.\n * Defaults to true if the preference has never been explicitly set.\n *\n * @returns Whether auto-upgrade is enabled.\n */\nexport function getAutoUpgradeEnabled(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('autoUpgradeEnabled') ?? true\n}\n\n/**\n * Set auto-upgrade preference.\n *\n * @param enabled - Whether auto-upgrade should be enabled.\n */\nexport function setAutoUpgradeEnabled(enabled: boolean, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('autoUpgradeEnabled', enabled)\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<Record<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"]}
|
|
@@ -3,8 +3,8 @@ import { stringifyMessage } from '../../public/node/output.js';
|
|
|
3
3
|
import { relativizePath } from '../../public/node/path.js';
|
|
4
4
|
import ansiEscapes from 'ansi-escapes';
|
|
5
5
|
import supportsHyperlinks from 'supports-hyperlinks';
|
|
6
|
-
import cjs from 'color-json';
|
|
7
6
|
export class ContentToken {
|
|
7
|
+
value;
|
|
8
8
|
constructor(value) {
|
|
9
9
|
this.value = value;
|
|
10
10
|
}
|
|
@@ -15,6 +15,8 @@ export class RawContentToken extends ContentToken {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
export class LinkContentToken extends ContentToken {
|
|
18
|
+
link;
|
|
19
|
+
fallback;
|
|
18
20
|
constructor(value, link, fallback) {
|
|
19
21
|
super(value);
|
|
20
22
|
this.link = link ?? stringifyMessage(value);
|
|
@@ -35,11 +37,33 @@ export class CommandContentToken extends ContentToken {
|
|
|
35
37
|
return `\`${colors.magentaBright(stringifyMessage(this.value))}\``;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
40
|
+
// Token-matching regex taken from the color-json package this implementation replaces:
|
|
41
|
+
// https://www.npmjs.com/package/color-json
|
|
42
|
+
const jsonTokenRegex = /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g;
|
|
43
|
+
function colorJson(input) {
|
|
44
|
+
const object = typeof input === 'string' ? JSON.parse(input) : input;
|
|
45
|
+
const json = JSON.stringify(object, undefined, 2);
|
|
46
|
+
const colorized = json.replace(jsonTokenRegex, (match) => {
|
|
47
|
+
if (match.startsWith('"')) {
|
|
48
|
+
return match.endsWith(':') ? colors.white(match) : colors.green(match);
|
|
49
|
+
}
|
|
50
|
+
if (match === 'true' || match === 'false') {
|
|
51
|
+
return colors.cyan(match);
|
|
52
|
+
}
|
|
53
|
+
if (match === 'null') {
|
|
54
|
+
return colors.red(match);
|
|
55
|
+
}
|
|
56
|
+
return colors.magenta(match);
|
|
57
|
+
});
|
|
58
|
+
// The outer yellow colors the structural characters (braces, brackets, commas);
|
|
59
|
+
// chalk reopens it after each nested token color.
|
|
60
|
+
return colors.yellow(colorized);
|
|
61
|
+
}
|
|
38
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
63
|
export class JsonContentToken extends ContentToken {
|
|
40
64
|
output() {
|
|
41
65
|
try {
|
|
42
|
-
return
|
|
66
|
+
return colorJson(stringifyMessage(this.value) ?? {});
|
|
43
67
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
44
68
|
}
|
|
45
69
|
catch (_) {
|
|
@@ -73,6 +97,7 @@ export class LinesDiffContentToken extends ContentToken {
|
|
|
73
97
|
}
|
|
74
98
|
}
|
|
75
99
|
export class ColorContentToken extends ContentToken {
|
|
100
|
+
color;
|
|
76
101
|
constructor(value, color) {
|
|
77
102
|
super(value);
|
|
78
103
|
this.color = color;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-tokens.js","sourceRoot":"","sources":["../../../src/private/node/content-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,6BAA6B,CAAA;AAChD,OAAO,EAAgB,gBAAgB,EAAC,MAAM,6BAA6B,CAAA;AAC3E,OAAO,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAA;AACxD,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,kBAAkB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"content-tokens.js","sourceRoot":"","sources":["../../../src/private/node/content-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import colors from '../../public/node/colors.js'\nimport {OutputMessage, stringifyMessage} from '../../public/node/output.js'\nimport {relativizePath} from '../../public/node/path.js'\nimport ansiEscapes from 'ansi-escapes'\nimport supportsHyperlinks from 'supports-hyperlinks'\nimport type {Change} from 'diff'\n\nexport abstract class ContentToken<T> {\n value: T\n\n constructor(value: T) {\n this.value = value\n }\n\n abstract output(): string | string[]\n}\n\nexport class RawContentToken extends ContentToken<string> {\n output(): string {\n return this.value\n }\n}\n\nexport class LinkContentToken extends ContentToken<OutputMessage> {\n link: string\n fallback: string | undefined\n\n constructor(value: OutputMessage, link?: string, fallback?: string) {\n super(value)\n this.link = link ?? stringifyMessage(value)\n this.fallback = fallback\n }\n\n output() {\n const text = colors.green(stringifyMessage(this.value))\n const url = this.link ?? ''\n const defaultFallback = this.value === this.link ? text : `${text} ( ${url} )`\n if (supportsHyperlinks.stdout) {\n return ansiEscapes.link(text, url)\n }\n return this.fallback ?? defaultFallback\n }\n}\n\nexport class CommandContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return `\\`${colors.magentaBright(stringifyMessage(this.value))}\\``\n }\n}\n\n// Token-matching regex taken from the color-json package this implementation replaces:\n// https://www.npmjs.com/package/color-json\nconst jsonTokenRegex =\n /(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)/g\n\nfunction colorJson(input: unknown): string {\n const object = typeof input === 'string' ? JSON.parse(input) : input\n const json = JSON.stringify(object, undefined, 2)\n const colorized = json.replace(jsonTokenRegex, (match) => {\n if (match.startsWith('\"')) {\n return match.endsWith(':') ? colors.white(match) : colors.green(match)\n }\n if (match === 'true' || match === 'false') {\n return colors.cyan(match)\n }\n if (match === 'null') {\n return colors.red(match)\n }\n return colors.magenta(match)\n })\n // The outer yellow colors the structural characters (braces, brackets, commas);\n // chalk reopens it after each nested token color.\n return colors.yellow(colorized)\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class JsonContentToken extends ContentToken<any> {\n output(): string {\n try {\n return colorJson(stringifyMessage(this.value) ?? {})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (_) {\n return JSON.stringify(stringifyMessage(this.value) ?? {}, null, 2)\n }\n }\n}\n\nexport class LinesDiffContentToken extends ContentToken<Change[]> {\n output(): string[] {\n return this.value.flatMap((part) => {\n if (part.added) {\n return part.value\n .split(/\\n/)\n .filter((line) => line !== '')\n .map((line) => {\n return colors.green(`+ ${line}\\n`)\n })\n } else if (part.removed) {\n return part.value\n .split(/\\n/)\n .filter((line) => line !== '')\n .map((line) => {\n return colors.magenta(`- ${line}\\n`)\n })\n } else {\n return part.value\n }\n })\n }\n}\n\nexport class ColorContentToken extends ContentToken<OutputMessage> {\n color: (text: string) => string\n\n constructor(value: OutputMessage, color: (text: string) => string) {\n super(value)\n this.color = color\n }\n\n output(): string {\n return this.color(stringifyMessage(this.value))\n }\n}\n\nexport class ErrorContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.bold.redBright(stringifyMessage(this.value))\n }\n}\n\nexport class PathContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return relativizePath(stringifyMessage(this.value))\n }\n}\n\nexport class HeadingContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.bold.underline(stringifyMessage(this.value))\n }\n}\n\nexport class SubHeadingContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.underline(stringifyMessage(this.value))\n }\n}\n\nexport class ItalicContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.italic(stringifyMessage(this.value))\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { OtelService } from '../../public/node/vendor/otel-js/service/types.js';
|
|
|
2
2
|
import { DefaultOtelServiceOptions } from '../../public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js';
|
|
3
3
|
type MetricRecorder = 'console' | {
|
|
4
4
|
type: 'otel';
|
|
5
|
-
otel: Pick<OtelService, 'record'>;
|
|
5
|
+
otel: Pick<OtelService, 'getMeterProvider' | 'record'>;
|
|
6
6
|
};
|
|
7
7
|
interface Timing {
|
|
8
8
|
active: number;
|
|
@@ -31,10 +31,13 @@ export async function recordMetrics(options, timing, recorderFactory = createMet
|
|
|
31
31
|
};
|
|
32
32
|
recordCommandCounter(recorder, labels);
|
|
33
33
|
recordCommandTiming(recorder, labels, timing);
|
|
34
|
+
if (recorder !== 'console') {
|
|
35
|
+
await recorder.otel.getMeterProvider().forceFlush({});
|
|
36
|
+
}
|
|
34
37
|
}
|
|
35
38
|
const COMMAND_DURATION_BOUNDARIES_MS = [
|
|
36
|
-
0, 100, 200, 300, 500, 750, 1000, 1500, 2000, 3000, 5000, 7500,
|
|
37
|
-
|
|
39
|
+
0, 100, 200, 300, 500, 750, 1000, 1500, 2000, 3000, 5000, 7500, 10_000, 15_000, 20_000, 30_000, 50_000, 70_000,
|
|
40
|
+
85_000, 100_000,
|
|
38
41
|
];
|
|
39
42
|
/**
|
|
40
43
|
* Get the default options for the OTEL service. These are the same across environments.
|