@shopify/cli-kit 3.87.3 → 3.88.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/private/node/api.d.ts +2 -0
  2. package/dist/private/node/api.js +9 -0
  3. package/dist/private/node/api.js.map +1 -1
  4. package/dist/private/node/constants.d.ts +1 -0
  5. package/dist/private/node/constants.js +1 -0
  6. package/dist/private/node/constants.js.map +1 -1
  7. package/dist/private/node/context/deprecations-store.js +4 -7
  8. package/dist/private/node/context/deprecations-store.js.map +1 -1
  9. package/dist/private/node/ui/components/SingleTask.d.ts +6 -5
  10. package/dist/private/node/ui/components/SingleTask.js +7 -5
  11. package/dist/private/node/ui/components/SingleTask.js.map +1 -1
  12. package/dist/private/node/ui/components/SingleTask.test.js +87 -35
  13. package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
  14. package/dist/private/node/ui/components/Tasks.d.ts +2 -1
  15. package/dist/private/node/ui/components/Tasks.js +2 -1
  16. package/dist/private/node/ui/components/Tasks.js.map +1 -1
  17. package/dist/private/node/ui/components/Tasks.test.js +21 -1
  18. package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
  19. package/dist/public/common/string.d.ts +8 -0
  20. package/dist/public/common/string.js +23 -0
  21. package/dist/public/common/string.js.map +1 -1
  22. package/dist/public/common/version.d.ts +1 -1
  23. package/dist/public/common/version.js +1 -1
  24. package/dist/public/common/version.js.map +1 -1
  25. package/dist/public/node/context/fqdn.js +1 -1
  26. package/dist/public/node/context/fqdn.js.map +1 -1
  27. package/dist/public/node/environment.d.ts +1 -1
  28. package/dist/public/node/environment.js +11 -2
  29. package/dist/public/node/environment.js.map +1 -1
  30. package/dist/public/node/fs.d.ts +7 -0
  31. package/dist/public/node/fs.js +23 -1
  32. package/dist/public/node/fs.js.map +1 -1
  33. package/dist/public/node/session.d.ts +11 -0
  34. package/dist/public/node/session.js +35 -1
  35. package/dist/public/node/session.js.map +1 -1
  36. package/dist/public/node/system.d.ts +19 -0
  37. package/dist/public/node/system.js +39 -0
  38. package/dist/public/node/system.js.map +1 -1
  39. package/dist/public/node/themes/api.js +1 -0
  40. package/dist/public/node/themes/api.js.map +1 -1
  41. package/dist/public/node/ui.d.ts +12 -9
  42. package/dist/public/node/ui.js +11 -14
  43. package/dist/public/node/ui.js.map +1 -1
  44. package/dist/public/node/vendor/dev_server/network/index.js +1 -1
  45. package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
  46. package/dist/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +1 -1
@@ -4,8 +4,10 @@ export declare const allAPIs: API[];
4
4
  export type NetworkRetryBehaviour = {
5
5
  useNetworkLevelRetry: true;
6
6
  maxRetryTimeMs: number;
7
+ recordCommandRetries?: boolean;
7
8
  } | {
8
9
  useNetworkLevelRetry: false;
10
+ recordCommandRetries?: boolean;
9
11
  };
10
12
  type RequestOptions<T> = {
11
13
  request: () => Promise<T>;
@@ -2,6 +2,7 @@ import { sanitizedHeadersOutput } from './api/headers.js';
2
2
  import { sanitizeURL } from './api/urls.js';
3
3
  import { sleepWithBackoffUntil } from './sleep-with-backoff.js';
4
4
  import { outputDebug } from '../../public/node/output.js';
5
+ import { recordRetry } from '../../public/node/analytics.js';
5
6
  import { ClientError } from 'graphql-request';
6
7
  import { performance } from 'perf_hooks';
7
8
  export const allAPIs = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management'];
@@ -92,6 +93,10 @@ async function runRequestWithNetworkLevelRetry(requestOptions) {
92
93
  if (!isTransientNetworkError(err)) {
93
94
  throw err;
94
95
  }
96
+ // Record command retries
97
+ if (requestOptions.recordCommandRetries) {
98
+ recordRetry(requestOptions.url, `network-retry:${err.message}`);
99
+ }
95
100
  outputDebug(`Retrying request to ${requestOptions.url} due to network error ${err}`);
96
101
  }
97
102
  }
@@ -300,6 +305,10 @@ ${result.sanitizedHeaders}
300
305
  }
301
306
  }
302
307
  retriesUsed += 1;
308
+ // Record command retries
309
+ if (requestOptions.recordCommandRetries) {
310
+ recordRetry(requestOptions.url, `http-retry-${retriesUsed}:${result.status}:`);
311
+ }
303
312
  // prefer to wait based on a header if given; the caller's preference if not; and a default if neither.
304
313
  const retryDelayMs = result.delayMs ?? retryOptions.defaultDelayMs ?? DEFAULT_RETRY_DELAY_MS;
305
314
  outputDebug(`Scheduling retry request #${retriesUsed} to ${result.sanitizedUrl} in ${retryDelayMs} ms`);
@@ -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 {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management']\n\nconst DEFAULT_RETRY_DELAY_MS = 1000\nconst DEFAULT_RETRY_LIMIT = 10\n\nexport type NetworkRetryBehaviour =\n | {\n useNetworkLevelRetry: true\n maxRetryTimeMs: number\n }\n | {\n useNetworkLevelRetry: false\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 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: {[key: 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 // 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 {sleepWithBackoffUntil} from './sleep-with-backoff.js'\nimport {outputDebug} from '../../public/node/output.js'\nimport {recordRetry} from '../../public/node/analytics.js'\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform' | 'app-management'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform', 'app-management']\n\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: {[key: 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"]}
@@ -29,6 +29,7 @@ export declare const environmentVariables: {
29
29
  themeKitAccessDomain: string;
30
30
  json: string;
31
31
  neverUsePartnersApi: string;
32
+ usePartnersApi: string;
32
33
  skipNetworkLevelRetry: string;
33
34
  maxRequestTimeForNetworkCalls: string;
34
35
  };
@@ -40,6 +40,7 @@ export const environmentVariables = {
40
40
  themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',
41
41
  json: 'SHOPIFY_FLAG_JSON',
42
42
  neverUsePartnersApi: 'SHOPIFY_CLI_NEVER_USE_PARTNERS_API',
43
+ usePartnersApi: 'SHOPIFY_CLI_USE_PARTNERS_API',
43
44
  skipNetworkLevelRetry: 'SHOPIFY_CLI_SKIP_NETWORK_LEVEL_RETRY',
44
45
  maxRequestTimeForNetworkCalls: 'SHOPIFY_CLI_MAX_REQUEST_TIME_FOR_NETWORK_CALLS',
45
46
  };
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,gBAAgB,EAAE,gCAAgC;IAClD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,mEAAmE;IACnE,UAAU,EAAE,YAAY;IACxB,aAAa,EAAE,gBAAgB;IAC/B,6BAA6B,EAAE,0CAA0C;IACzE,MAAM,EAAE,sBAAsB;IAC9B,UAAU,EAAE,aAAa;IACzB,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,0BAA0B;IACxC,aAAa,EAAE,4BAA4B;IAC3C,YAAY,EAAE,2BAA2B;IACzC,OAAO,EAAE,yCAAyC;IAClD,oBAAoB,EAAE,qCAAqC;IAC3D,IAAI,EAAE,mBAAmB;IACzB,mBAAmB,EAAE,oCAAoC;IACzD,qBAAqB,EAAE,sCAAsC;IAC7D,6BAA6B,EAAE,gDAAgD;CAChF,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,kCAAkC,CAAA;AAE7E,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE;QACX,GAAG,EAAE,kBAAkB;KACxB;IACD,WAAW,EAAE;QACX,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,OAAO,WAAW,EAAE,CAAA;YACtB,CAAC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,GAAG,EAAE;oBACT,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;gBAC1C,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACtD,CAAC;aACF;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6BAA6B,EAAE,CAAC;CACjC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,kCAAkC,CAAA;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,CAAC,EAAC,EAAC,CAAA;AAElE,MAAM,CAAC,MAAM,oBAAoB,GAC/B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,2BAA2B,CAAA","sourcesContent":["import {joinPath} from '../../public/node/path.js'\nimport envPaths from 'env-paths'\n\nconst identifier = 'shopify-cli'\n\nconst cacheFolder = () => {\n if (process.env.XDG_CACHE_HOME) return process.env.XDG_CACHE_HOME\n return envPaths(identifier).cache\n}\n\nexport const logsFolder = () => {\n return envPaths(identifier).log\n}\n\nexport const environmentVariables = {\n alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',\n alwaysLogMetrics: 'SHOPIFY_CLI_ALWAYS_LOG_METRICS',\n deviceAuth: 'SHOPIFY_CLI_DEVICE_AUTH',\n enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT',\n env: 'SHOPIFY_CLI_ENV',\n firstPartyDev: 'SHOPIFY_CLI_1P_DEV',\n noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS',\n partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',\n runAsUser: 'SHOPIFY_RUN_AS_USER',\n serviceEnv: 'SHOPIFY_SERVICE_ENV',\n skipCliRedirect: 'SHOPIFY_CLI_SKIP_CLI_REDIRECT',\n spinInstance: 'SPIN_INSTANCE',\n themeToken: 'SHOPIFY_CLI_THEME_TOKEN',\n unitTest: 'SHOPIFY_UNIT_TEST',\n verbose: 'SHOPIFY_FLAG_VERBOSE',\n // Variables to detect if the CLI is running in a cloud environment\n codespaces: 'CODESPACES',\n codespaceName: 'CODESPACE_NAME',\n codespacePortForwardingDomain: 'GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN',\n gitpod: 'GITPOD_WORKSPACE_URL',\n cloudShell: 'CLOUD_SHELL',\n spinAppPort: 'SERVER_PORT',\n spinAppHost: 'SPIN_APP_HOST',\n organization: 'SHOPIFY_CLI_ORGANIZATION',\n identityToken: 'SHOPIFY_CLI_IDENTITY_TOKEN',\n refreshToken: 'SHOPIFY_CLI_REFRESH_TOKEN',\n otelURL: 'SHOPIFY_CLI_OTEL_EXPORTER_OTLP_ENDPOINT',\n themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',\n json: 'SHOPIFY_FLAG_JSON',\n neverUsePartnersApi: 'SHOPIFY_CLI_NEVER_USE_PARTNERS_API',\n skipNetworkLevelRetry: 'SHOPIFY_CLI_SKIP_NETWORK_LEVEL_RETRY',\n maxRequestTimeForNetworkCalls: 'SHOPIFY_CLI_MAX_REQUEST_TIME_FOR_NETWORK_CALLS',\n}\n\nexport const defaultThemeKitAccessDomain = 'theme-kit-access.shopifyapps.com'\n\nexport const systemEnvironmentVariables = {\n backendPort: 'BACKEND_PORT',\n}\n\nexport const pathConstants = {\n executables: {\n dev: '/opt/dev/bin/dev',\n },\n directories: {\n cache: {\n path: () => {\n return cacheFolder()\n },\n vendor: {\n path: () => {\n return joinPath(cacheFolder(), 'vendor')\n },\n binaries: () => {\n return joinPath(cacheFolder(), 'vendor', 'binaries')\n },\n },\n },\n },\n}\n\nexport const sessionConstants = {\n expirationTimeMarginInMinutes: 4,\n}\n\nexport const bugsnagApiKey = '9e1e6889176fd0c795d5c659225e0fae'\n\nexport const reportingRateLimit = {limit: 300, timeout: {days: 1}}\n\nexport const themeKitAccessDomain =\n process.env[environmentVariables.themeKitAccessDomain] ?? defaultThemeKitAccessDomain\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/private/node/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAA;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEhC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAA;IACjE,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,CAAA;AACnC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,kBAAkB,EAAE,kCAAkC;IACtD,gBAAgB,EAAE,gCAAgC;IAClD,UAAU,EAAE,yBAAyB;IACrC,iBAAiB,EAAE,iCAAiC;IACpD,GAAG,EAAE,iBAAiB;IACtB,aAAa,EAAE,oBAAoB;IACnC,WAAW,EAAE,0BAA0B;IACvC,aAAa,EAAE,4BAA4B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,qBAAqB;IACjC,eAAe,EAAE,+BAA+B;IAChD,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,mEAAmE;IACnE,UAAU,EAAE,YAAY;IACxB,aAAa,EAAE,gBAAgB;IAC/B,6BAA6B,EAAE,0CAA0C;IACzE,MAAM,EAAE,sBAAsB;IAC9B,UAAU,EAAE,aAAa;IACzB,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,0BAA0B;IACxC,aAAa,EAAE,4BAA4B;IAC3C,YAAY,EAAE,2BAA2B;IACzC,OAAO,EAAE,yCAAyC;IAClD,oBAAoB,EAAE,qCAAqC;IAC3D,IAAI,EAAE,mBAAmB;IACzB,mBAAmB,EAAE,oCAAoC;IACzD,cAAc,EAAE,8BAA8B;IAC9C,qBAAqB,EAAE,sCAAsC;IAC7D,6BAA6B,EAAE,gDAAgD;CAChF,CAAA;AAED,MAAM,CAAC,MAAM,2BAA2B,GAAG,kCAAkC,CAAA;AAE7E,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,WAAW,EAAE;QACX,GAAG,EAAE,kBAAkB;KACxB;IACD,WAAW,EAAE;QACX,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,EAAE;gBACT,OAAO,WAAW,EAAE,CAAA;YACtB,CAAC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,GAAG,EAAE;oBACT,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAA;gBAC1C,CAAC;gBACD,QAAQ,EAAE,GAAG,EAAE;oBACb,OAAO,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;gBACtD,CAAC;aACF;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,6BAA6B,EAAE,CAAC;CACjC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,kCAAkC,CAAA;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,CAAC,EAAC,EAAC,CAAA;AAElE,MAAM,CAAC,MAAM,oBAAoB,GAC/B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,IAAI,2BAA2B,CAAA","sourcesContent":["import {joinPath} from '../../public/node/path.js'\nimport envPaths from 'env-paths'\n\nconst identifier = 'shopify-cli'\n\nconst cacheFolder = () => {\n if (process.env.XDG_CACHE_HOME) return process.env.XDG_CACHE_HOME\n return envPaths(identifier).cache\n}\n\nexport const logsFolder = () => {\n return envPaths(identifier).log\n}\n\nexport const environmentVariables = {\n alwaysLogAnalytics: 'SHOPIFY_CLI_ALWAYS_LOG_ANALYTICS',\n alwaysLogMetrics: 'SHOPIFY_CLI_ALWAYS_LOG_METRICS',\n deviceAuth: 'SHOPIFY_CLI_DEVICE_AUTH',\n enableCliRedirect: 'SHOPIFY_CLI_ENABLE_CLI_REDIRECT',\n env: 'SHOPIFY_CLI_ENV',\n firstPartyDev: 'SHOPIFY_CLI_1P_DEV',\n noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS',\n partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',\n runAsUser: 'SHOPIFY_RUN_AS_USER',\n serviceEnv: 'SHOPIFY_SERVICE_ENV',\n skipCliRedirect: 'SHOPIFY_CLI_SKIP_CLI_REDIRECT',\n spinInstance: 'SPIN_INSTANCE',\n themeToken: 'SHOPIFY_CLI_THEME_TOKEN',\n unitTest: 'SHOPIFY_UNIT_TEST',\n verbose: 'SHOPIFY_FLAG_VERBOSE',\n // Variables to detect if the CLI is running in a cloud environment\n codespaces: 'CODESPACES',\n codespaceName: 'CODESPACE_NAME',\n codespacePortForwardingDomain: 'GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN',\n gitpod: 'GITPOD_WORKSPACE_URL',\n cloudShell: 'CLOUD_SHELL',\n spinAppPort: 'SERVER_PORT',\n spinAppHost: 'SPIN_APP_HOST',\n organization: 'SHOPIFY_CLI_ORGANIZATION',\n identityToken: 'SHOPIFY_CLI_IDENTITY_TOKEN',\n refreshToken: 'SHOPIFY_CLI_REFRESH_TOKEN',\n otelURL: 'SHOPIFY_CLI_OTEL_EXPORTER_OTLP_ENDPOINT',\n themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',\n json: 'SHOPIFY_FLAG_JSON',\n neverUsePartnersApi: 'SHOPIFY_CLI_NEVER_USE_PARTNERS_API',\n usePartnersApi: 'SHOPIFY_CLI_USE_PARTNERS_API',\n skipNetworkLevelRetry: 'SHOPIFY_CLI_SKIP_NETWORK_LEVEL_RETRY',\n maxRequestTimeForNetworkCalls: 'SHOPIFY_CLI_MAX_REQUEST_TIME_FOR_NETWORK_CALLS',\n}\n\nexport const defaultThemeKitAccessDomain = 'theme-kit-access.shopifyapps.com'\n\nexport const systemEnvironmentVariables = {\n backendPort: 'BACKEND_PORT',\n}\n\nexport const pathConstants = {\n executables: {\n dev: '/opt/dev/bin/dev',\n },\n directories: {\n cache: {\n path: () => {\n return cacheFolder()\n },\n vendor: {\n path: () => {\n return joinPath(cacheFolder(), 'vendor')\n },\n binaries: () => {\n return joinPath(cacheFolder(), 'vendor', 'binaries')\n },\n },\n },\n },\n}\n\nexport const sessionConstants = {\n expirationTimeMarginInMinutes: 4,\n}\n\nexport const bugsnagApiKey = '9e1e6889176fd0c795d5c659225e0fae'\n\nexport const reportingRateLimit = {limit: 300, timeout: {days: 1}}\n\nexport const themeKitAccessDomain =\n process.env[environmentVariables.themeKitAccessDomain] ?? defaultThemeKitAccessDomain\n"]}
@@ -1,8 +1,5 @@
1
- const globalWithDeprecationsStore = {
2
- ...globalThis,
3
- deprecationsStore: {
4
- nextDeprecationDate: undefined,
5
- },
1
+ const deprecationsStore = {
2
+ nextDeprecationDate: undefined,
6
3
  };
7
4
  /**
8
5
  * Get the earliest date in the future when deprecations will no longer be supported, if any.
@@ -10,7 +7,7 @@ const globalWithDeprecationsStore = {
10
7
  * @returns The next deprecation date.
11
8
  */
12
9
  export function getNextDeprecationDate() {
13
- return globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate;
10
+ return deprecationsStore.nextDeprecationDate;
14
11
  }
15
12
  /**
16
13
  * Set the next deprecation date to the earliest date in the future.
@@ -25,7 +22,7 @@ export function setNextDeprecationDate(dates) {
25
22
  return;
26
23
  const nextDeprecationDate = getNextDeprecationDate();
27
24
  if (!nextDeprecationDate || earliestFutureDateTime < nextDeprecationDate.getTime()) {
28
- globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime);
25
+ deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime);
29
26
  }
30
27
  }
31
28
  function earliestDateTimeAfter(afterTime, dates) {
@@ -1 +1 @@
1
- {"version":3,"file":"deprecations-store.js","sourceRoot":"","sources":["../../../../src/private/node/context/deprecations-store.ts"],"names":[],"mappings":"AAQA,MAAM,2BAA2B,GAAgC;IAC/D,GAAG,UAAU;IACb,iBAAiB,EAAE;QACjB,mBAAmB,EAAE,SAAS;KAC/B;CACF,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,2BAA2B,CAAC,iBAAiB,CAAC,mBAAmB,CAAA;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAM;IAE5B,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IACvE,IAAI,CAAC,sBAAsB;QAAE,OAAM;IAEnC,MAAM,mBAAmB,GAAG,sBAAsB,EAAE,CAAA;IACpD,IAAI,CAAC,mBAAmB,IAAI,sBAAsB,GAAG,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC;QACnF,2BAA2B,CAAC,iBAAiB,CAAC,mBAAmB,GAAG,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAA;IACtG,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,KAAa;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;IACjD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,CAAC,CAAA;AACtD,CAAC","sourcesContent":["interface DeprecationsStore {\n nextDeprecationDate: Date | undefined\n}\n\ninterface GlobalWithDeprecationsStore {\n deprecationsStore: DeprecationsStore\n}\n\nconst globalWithDeprecationsStore: GlobalWithDeprecationsStore = {\n ...globalThis,\n deprecationsStore: {\n nextDeprecationDate: undefined,\n },\n}\n\n/**\n * Get the earliest date in the future when deprecations will no longer be supported, if any.\n *\n * @returns The next deprecation date.\n */\nexport function getNextDeprecationDate(): Date | undefined {\n return globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate\n}\n\n/**\n * Set the next deprecation date to the earliest date in the future.\n *\n * @param dates - Dates when deprecations will no longer be supported.\n */\nexport function setNextDeprecationDate(dates: Date[]): Date | undefined {\n if (dates.length < 1) return\n\n const earliestFutureDateTime = earliestDateTimeAfter(Date.now(), dates)\n if (!earliestFutureDateTime) return\n\n const nextDeprecationDate = getNextDeprecationDate()\n if (!nextDeprecationDate || earliestFutureDateTime < nextDeprecationDate.getTime()) {\n globalWithDeprecationsStore.deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime)\n }\n}\n\nfunction earliestDateTimeAfter(afterTime: number, dates: Date[]): number | undefined {\n const times = dates.map((date) => date.getTime())\n return times.sort().find((time) => time > afterTime)\n}\n"]}
1
+ {"version":3,"file":"deprecations-store.js","sourceRoot":"","sources":["../../../../src/private/node/context/deprecations-store.ts"],"names":[],"mappings":"AAIA,MAAM,iBAAiB,GAAsB;IAC3C,mBAAmB,EAAE,SAAS;CAC/B,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,iBAAiB,CAAC,mBAAmB,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAM;IAE5B,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IACvE,IAAI,CAAC,sBAAsB;QAAE,OAAM;IAEnC,MAAM,mBAAmB,GAAG,sBAAsB,EAAE,CAAA;IACpD,IAAI,CAAC,mBAAmB,IAAI,sBAAsB,GAAG,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC;QACnF,iBAAiB,CAAC,mBAAmB,GAAG,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAA;IAC1E,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,KAAa;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;IACjD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,CAAC,CAAA;AACtD,CAAC","sourcesContent":["interface DeprecationsStore {\n nextDeprecationDate: Date | undefined\n}\n\nconst deprecationsStore: DeprecationsStore = {\n nextDeprecationDate: undefined,\n}\n\n/**\n * Get the earliest date in the future when deprecations will no longer be supported, if any.\n *\n * @returns The next deprecation date.\n */\nexport function getNextDeprecationDate(): Date | undefined {\n return deprecationsStore.nextDeprecationDate\n}\n\n/**\n * Set the next deprecation date to the earliest date in the future.\n *\n * @param dates - Dates when deprecations will no longer be supported.\n */\nexport function setNextDeprecationDate(dates: Date[]): Date | undefined {\n if (dates.length < 1) return\n\n const earliestFutureDateTime = earliestDateTimeAfter(Date.now(), dates)\n if (!earliestFutureDateTime) return\n\n const nextDeprecationDate = getNextDeprecationDate()\n if (!nextDeprecationDate || earliestFutureDateTime < nextDeprecationDate.getTime()) {\n deprecationsStore.nextDeprecationDate = new Date(earliestFutureDateTime)\n }\n}\n\nfunction earliestDateTimeAfter(afterTime: number, dates: Date[]): number | undefined {\n const times = dates.map((date) => date.getTime())\n return times.sort().find((time) => time > afterTime)\n}\n"]}
@@ -1,8 +1,9 @@
1
- import React from 'react';
2
- interface SingleTaskProps {
3
- title: string;
4
- taskPromise: Promise<unknown>;
1
+ import { TokenizedString } from '../../../../public/node/output.js';
2
+ interface SingleTaskProps<T> {
3
+ title: TokenizedString;
4
+ task: (updateStatus: (status: TokenizedString) => void) => Promise<T>;
5
+ onComplete?: (result: T) => void;
5
6
  noColor?: boolean;
6
7
  }
7
- declare const SingleTask: ({ taskPromise, title, noColor }: React.PropsWithChildren<SingleTaskProps>) => JSX.Element | null;
8
+ declare const SingleTask: <T>({ task, title, onComplete, noColor }: SingleTaskProps<T>) => JSX.Element | null;
8
9
  export { SingleTask };
@@ -2,26 +2,28 @@ import { LoadingBar } from './LoadingBar.js';
2
2
  import { useExitOnCtrlC } from '../hooks/use-exit-on-ctrl-c.js';
3
3
  import React, { useEffect, useState } from 'react';
4
4
  import { useApp } from 'ink';
5
- const SingleTask = ({ taskPromise, title, noColor }) => {
5
+ const SingleTask = ({ task, title, onComplete, noColor }) => {
6
+ const [status, setStatus] = useState(title);
6
7
  const [isDone, setIsDone] = useState(false);
7
8
  const { exit: unmountInk } = useApp();
8
9
  useExitOnCtrlC();
9
10
  useEffect(() => {
10
- taskPromise
11
- .then(() => {
11
+ task(setStatus)
12
+ .then((result) => {
12
13
  setIsDone(true);
14
+ onComplete?.(result);
13
15
  unmountInk();
14
16
  })
15
17
  .catch((error) => {
16
18
  setIsDone(true);
17
19
  unmountInk(error);
18
20
  });
19
- }, [taskPromise, unmountInk]);
21
+ }, [task, unmountInk, onComplete]);
20
22
  if (isDone) {
21
23
  // clear things once done
22
24
  return null;
23
25
  }
24
- return React.createElement(LoadingBar, { title: title, noColor: noColor });
26
+ return React.createElement(LoadingBar, { title: status.value, noColor: noColor });
25
27
  };
26
28
  export { SingleTask };
27
29
  //# sourceMappingURL=SingleTask.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,cAAc,EAAC,MAAM,gCAAgC,CAAA;AAC7D,OAAO,KAAK,EAAE,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAChD,OAAO,EAAC,MAAM,EAAC,MAAM,KAAK,CAAA;AAQ1B,MAAM,UAAU,GAAG,CAAC,EAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAA2C,EAAE,EAAE;IAC7F,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,cAAc,EAAE,CAAA;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,WAAW;aACR,IAAI,CAAC,GAAG,EAAE;YACT,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,EAAE,CAAA;QACd,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;IAE7B,IAAI,MAAM,EAAE,CAAC;QACX,yBAAyB;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AACvD,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {useExitOnCtrlC} from '../hooks/use-exit-on-ctrl-c.js'\nimport React, {useEffect, useState} from 'react'\nimport {useApp} from 'ink'\n\ninterface SingleTaskProps {\n title: string\n taskPromise: Promise<unknown>\n noColor?: boolean\n}\n\nconst SingleTask = ({taskPromise, title, noColor}: React.PropsWithChildren<SingleTaskProps>) => {\n const [isDone, setIsDone] = useState(false)\n const {exit: unmountInk} = useApp()\n useExitOnCtrlC()\n\n useEffect(() => {\n taskPromise\n .then(() => {\n setIsDone(true)\n unmountInk()\n })\n .catch((error) => {\n setIsDone(true)\n unmountInk(error)\n })\n }, [taskPromise, unmountInk])\n\n if (isDone) {\n // clear things once done\n return null\n }\n\n return <LoadingBar title={title} noColor={noColor} />\n}\n\nexport {SingleTask}\n"]}
1
+ {"version":3,"file":"SingleTask.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,cAAc,EAAC,MAAM,gCAAgC,CAAA;AAE7D,OAAO,KAAK,EAAE,EAAC,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAChD,OAAO,EAAC,MAAM,EAAC,MAAM,KAAK,CAAA;AAS1B,MAAM,UAAU,GAAG,CAAK,EAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAqB,EAAE,EAAE;IAChF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,cAAc,EAAE,CAAA;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,CAAC;aACZ,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,EAAE,CAAC,MAAM,CAAC,CAAA;YACpB,UAAU,EAAE,CAAA;QACd,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA;IAElC,IAAI,MAAM,EAAE,CAAC;QACX,yBAAyB;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,oBAAC,UAAU,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AAC9D,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {useExitOnCtrlC} from '../hooks/use-exit-on-ctrl-c.js'\nimport {TokenizedString} from '../../../../public/node/output.js'\nimport React, {useEffect, useState} from 'react'\nimport {useApp} from 'ink'\n\ninterface SingleTaskProps<T> {\n title: TokenizedString\n task: (updateStatus: (status: TokenizedString) => void) => Promise<T>\n onComplete?: (result: T) => void\n noColor?: boolean\n}\n\nconst SingleTask = <T,>({task, title, onComplete, noColor}: SingleTaskProps<T>) => {\n const [status, setStatus] = useState(title)\n const [isDone, setIsDone] = useState(false)\n const {exit: unmountInk} = useApp()\n useExitOnCtrlC()\n\n useEffect(() => {\n task(setStatus)\n .then((result) => {\n setIsDone(true)\n onComplete?.(result)\n unmountInk()\n })\n .catch((error) => {\n setIsDone(true)\n unmountInk(error)\n })\n }, [task, unmountInk, onComplete])\n\n if (isDone) {\n // clear things once done\n return null\n }\n\n return <LoadingBar title={status.value} noColor={noColor} />\n}\n\nexport {SingleTask}\n"]}
@@ -1,17 +1,18 @@
1
1
  import { SingleTask } from './SingleTask.js';
2
2
  import { render } from '../../testing/ui.js';
3
+ import { TokenizedString } from '../../../../public/node/output.js';
3
4
  import React from 'react';
4
5
  import { describe, expect, test } from 'vitest';
5
6
  describe('SingleTask', () => {
6
7
  test('unmounts when promise resolves successfully', async () => {
7
8
  // Given
8
- const title = 'Uploading files';
9
+ const title = new TokenizedString('Uploading files');
9
10
  let resolvePromise;
10
- const taskPromise = new Promise((resolve) => {
11
+ const task = () => new Promise((resolve) => {
11
12
  resolvePromise = resolve;
12
13
  });
13
14
  // When
14
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
15
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
15
16
  // Wait for initial render
16
17
  await new Promise((resolve) => setTimeout(resolve, 10));
17
18
  // Resolve the promise
@@ -23,13 +24,13 @@ describe('SingleTask', () => {
23
24
  });
24
25
  test('unmounts when promise rejects', async () => {
25
26
  // Given
26
- const title = 'Failed task';
27
+ const title = new TokenizedString('Failed task');
27
28
  let rejectPromise;
28
- const taskPromise = new Promise((resolve, reject) => {
29
+ const task = () => new Promise((resolve, reject) => {
29
30
  rejectPromise = reject;
30
31
  });
31
32
  // When
32
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
33
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
33
34
  // Wait for initial render
34
35
  await new Promise((resolve) => setTimeout(resolve, 10));
35
36
  // Reject the promise and expect waitUntilExit to reject
@@ -39,53 +40,60 @@ describe('SingleTask', () => {
39
40
  });
40
41
  test('handles promise that resolves immediately', async () => {
41
42
  // Given
42
- const title = 'Instant task';
43
- const taskPromise = Promise.resolve('immediate success');
43
+ const title = new TokenizedString('Instant task');
44
+ const task = () => Promise.resolve('immediate success');
44
45
  // When
45
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
46
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
46
47
  await renderInstance.waitUntilExit();
47
48
  // Then - component should complete successfully
48
49
  expect(renderInstance.lastFrame()).toBeDefined();
49
50
  });
50
51
  test('handles promise that rejects immediately', async () => {
51
52
  // Given
52
- const title = 'Instant failure';
53
- const taskPromise = Promise.reject(new Error('Immediate error'));
53
+ const title = new TokenizedString('Instant failure');
54
+ const task = () => Promise.reject(new Error('Immediate error'));
54
55
  // When
55
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
56
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
56
57
  // Then - should exit with error
57
58
  await expect(renderInstance.waitUntilExit()).rejects.toThrow('Immediate error');
58
59
  });
59
60
  test('handles different types of promise return values', async () => {
60
61
  // Test with string
61
- const stringTask = Promise.resolve('task completed');
62
- const stringRender = render(React.createElement(SingleTask, { title: "String task", taskPromise: stringTask }));
62
+ let stringResult;
63
+ const stringTask = () => Promise.resolve('task completed');
64
+ const stringRender = render(React.createElement(SingleTask, { title: new TokenizedString('String task'), task: stringTask, onComplete: (result) => (stringResult = result) }));
63
65
  await stringRender.waitUntilExit();
64
66
  expect(stringRender.lastFrame()).toBeDefined();
67
+ expect(stringResult).toBe('task completed');
65
68
  // Test with object
66
- const objectTask = Promise.resolve({ id: 1, name: 'test' });
67
- const objectRender = render(React.createElement(SingleTask, { title: "Object task", taskPromise: objectTask }));
69
+ let objectResult;
70
+ const objectTask = () => Promise.resolve({ id: 1, name: 'test' });
71
+ const objectRender = render(React.createElement(SingleTask, { title: new TokenizedString('Object task'), task: objectTask, onComplete: (result) => (objectResult = result) }));
68
72
  await objectRender.waitUntilExit();
69
73
  expect(objectRender.lastFrame()).toBeDefined();
70
74
  // Test with number
71
- const numberTask = Promise.resolve(42);
72
- const numberRender = render(React.createElement(SingleTask, { title: "Number task", taskPromise: numberTask }));
75
+ let numberResult;
76
+ const numberTask = () => Promise.resolve(42);
77
+ const numberRender = render(React.createElement(SingleTask, { title: new TokenizedString('Number task'), task: numberTask, onComplete: (result) => (numberResult = result) }));
73
78
  await numberRender.waitUntilExit();
74
79
  expect(numberRender.lastFrame()).toBeDefined();
80
+ expect(numberResult).toBe(42);
75
81
  // Test with boolean
76
- const booleanTask = Promise.resolve(true);
77
- const booleanRender = render(React.createElement(SingleTask, { title: "Boolean task", taskPromise: booleanTask }));
82
+ let booleanResult;
83
+ const booleanTask = () => Promise.resolve(true);
84
+ const booleanRender = render(React.createElement(SingleTask, { title: new TokenizedString('Boolean task'), task: booleanTask, onComplete: (result) => (booleanResult = result) }));
78
85
  await booleanRender.waitUntilExit();
79
86
  expect(booleanRender.lastFrame()).toBeDefined();
87
+ expect(booleanResult).toBe(true);
80
88
  });
81
89
  test('handles promise with delayed resolution', async () => {
82
90
  // Given
83
- const title = 'Delayed task';
84
- const taskPromise = new Promise((resolve) => {
91
+ const title = new TokenizedString('Delayed task');
92
+ const task = () => new Promise((resolve) => {
85
93
  setTimeout(() => resolve('completed'), 100);
86
94
  });
87
95
  // When
88
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
96
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
89
97
  // Wait for completion
90
98
  await renderInstance.waitUntilExit();
91
99
  // Then
@@ -93,12 +101,12 @@ describe('SingleTask', () => {
93
101
  });
94
102
  test('handles promise with delayed rejection', async () => {
95
103
  // Given
96
- const title = 'Delayed failure';
97
- const taskPromise = new Promise((resolve, reject) => {
104
+ const title = new TokenizedString('Delayed failure');
105
+ const task = () => new Promise((resolve, reject) => {
98
106
  setTimeout(() => reject(new Error('delayed error')), 100);
99
107
  });
100
108
  // When
101
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise }));
109
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task }));
102
110
  // Wait for completion - should throw error
103
111
  await expect(renderInstance.waitUntilExit()).rejects.toThrow('delayed error');
104
112
  });
@@ -112,19 +120,19 @@ describe('SingleTask', () => {
112
120
  }
113
121
  }
114
122
  const customError = new CustomError('Custom error message', 'CUSTOM_CODE');
115
- const taskPromise = Promise.reject(customError);
123
+ const task = () => Promise.reject(customError);
116
124
  // When
117
- const renderInstance = render(React.createElement(SingleTask, { title: "Custom error task", taskPromise: taskPromise }));
125
+ const renderInstance = render(React.createElement(SingleTask, { title: new TokenizedString('Custom error task'), task: task }));
118
126
  // Then - should preserve the exact error
119
127
  await expect(renderInstance.waitUntilExit()).rejects.toThrow('Custom error message');
120
128
  });
121
129
  test('handles concurrent promise operations', async () => {
122
130
  // Given - Multiple SingleTask components with different promises
123
- const fastPromise = new Promise((resolve) => setTimeout(() => resolve('fast'), 50));
124
- const slowPromise = new Promise((resolve) => setTimeout(() => resolve('slow'), 150));
131
+ const fastPromise = () => new Promise((resolve) => setTimeout(() => resolve('fast'), 50));
132
+ const slowPromise = () => new Promise((resolve) => setTimeout(() => resolve('slow'), 150));
125
133
  // When
126
- const fastRender = render(React.createElement(SingleTask, { title: "Fast task", taskPromise: fastPromise }));
127
- const slowRender = render(React.createElement(SingleTask, { title: "Slow task", taskPromise: slowPromise }));
134
+ const fastRender = render(React.createElement(SingleTask, { title: new TokenizedString('Fast task'), task: fastPromise }));
135
+ const slowRender = render(React.createElement(SingleTask, { title: new TokenizedString('Slow task'), task: slowPromise }));
128
136
  // Then - Both should complete successfully
129
137
  await fastRender.waitUntilExit();
130
138
  await slowRender.waitUntilExit();
@@ -133,13 +141,57 @@ describe('SingleTask', () => {
133
141
  });
134
142
  test('passes noColor prop to LoadingBar component', async () => {
135
143
  // Given
136
- const title = 'No color task';
137
- const taskPromise = Promise.resolve();
144
+ const title = new TokenizedString('No color task');
145
+ const task = () => Promise.resolve();
138
146
  // When - Test that noColor prop doesn't break the component
139
- const renderInstance = render(React.createElement(SingleTask, { title: title, taskPromise: taskPromise, noColor: true }));
147
+ const renderInstance = render(React.createElement(SingleTask, { title: title, task: task, noColor: true }));
140
148
  await renderInstance.waitUntilExit();
141
149
  // Then - Component should complete successfully with noColor prop
142
150
  expect(renderInstance.lastFrame()).toBeDefined();
143
151
  });
152
+ test('updates status message during task execution', async () => {
153
+ // Given
154
+ const initialTitle = new TokenizedString('Starting task');
155
+ let step1Resolve;
156
+ let step2Resolve;
157
+ let step3Resolve;
158
+ const step1Promise = new Promise((resolve) => {
159
+ step1Resolve = resolve;
160
+ });
161
+ const step2Promise = new Promise((resolve) => {
162
+ step2Resolve = resolve;
163
+ });
164
+ const step3Promise = new Promise((resolve) => {
165
+ step3Resolve = resolve;
166
+ });
167
+ const task = async (updateStatus) => {
168
+ updateStatus(new TokenizedString('Running (1 complete)...'));
169
+ await step1Promise;
170
+ updateStatus(new TokenizedString('Running (2 complete)...'));
171
+ await step2Promise;
172
+ updateStatus(new TokenizedString('Running (3 complete)...'));
173
+ await step3Promise;
174
+ return 'completed';
175
+ };
176
+ // When
177
+ const renderInstance = render(React.createElement(SingleTask, { title: initialTitle, task: task }));
178
+ // Wait for component to render with first status
179
+ await new Promise((resolve) => setTimeout(resolve, 10));
180
+ const frame1 = renderInstance.lastFrame();
181
+ expect(frame1).toContain('1 complete');
182
+ // Progress to step 2
183
+ step1Resolve();
184
+ await new Promise((resolve) => setTimeout(resolve, 10));
185
+ const frame2 = renderInstance.lastFrame();
186
+ expect(frame2).toContain('2 complete');
187
+ // Progress to step 3
188
+ step2Resolve();
189
+ await new Promise((resolve) => setTimeout(resolve, 10));
190
+ const frame3 = renderInstance.lastFrame();
191
+ expect(frame3).toContain('3 complete');
192
+ // Complete the task
193
+ step3Resolve();
194
+ await renderInstance.waitUntilExit();
195
+ });
144
196
  });
145
197
  //# sourceMappingURL=SingleTask.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SingleTask.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SingleTask} from './SingleTask.js'\nimport {render} from '../../testing/ui.js'\nimport React from 'react'\nimport {describe, expect, test} from 'vitest'\n\ndescribe('SingleTask', () => {\n test('unmounts when promise resolves successfully', async () => {\n // Given\n const title = 'Uploading files'\n let resolvePromise: (value: string) => void\n const taskPromise = new Promise<string>((resolve) => {\n resolvePromise = resolve\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n\n // Wait for initial render\n await new Promise((resolve) => setTimeout(resolve, 10))\n\n // Resolve the promise\n resolvePromise!('success')\n\n // Wait for component to update and unmount\n await renderInstance.waitUntilExit()\n\n // Then - component should unmount cleanly\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('unmounts when promise rejects', async () => {\n // Given\n const title = 'Failed task'\n let rejectPromise: (error: Error) => void\n const taskPromise = new Promise<string>((resolve, reject) => {\n rejectPromise = reject\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n\n // Wait for initial render\n await new Promise((resolve) => setTimeout(resolve, 10))\n\n // Reject the promise and expect waitUntilExit to reject\n rejectPromise!(new Error('Task failed'))\n\n // The component should exit with the error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Task failed')\n })\n\n test('handles promise that resolves immediately', async () => {\n // Given\n const title = 'Instant task'\n const taskPromise = Promise.resolve('immediate success')\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n await renderInstance.waitUntilExit()\n\n // Then - component should complete successfully\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('handles promise that rejects immediately', async () => {\n // Given\n const title = 'Instant failure'\n const taskPromise = Promise.reject(new Error('Immediate error'))\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n\n // Then - should exit with error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Immediate error')\n })\n\n test('handles different types of promise return values', async () => {\n // Test with string\n const stringTask = Promise.resolve('task completed')\n const stringRender = render(<SingleTask title=\"String task\" taskPromise={stringTask} />)\n await stringRender.waitUntilExit()\n expect(stringRender.lastFrame()).toBeDefined()\n\n // Test with object\n const objectTask = Promise.resolve({id: 1, name: 'test'})\n const objectRender = render(<SingleTask title=\"Object task\" taskPromise={objectTask} />)\n await objectRender.waitUntilExit()\n expect(objectRender.lastFrame()).toBeDefined()\n\n // Test with number\n const numberTask = Promise.resolve(42)\n const numberRender = render(<SingleTask title=\"Number task\" taskPromise={numberTask} />)\n await numberRender.waitUntilExit()\n expect(numberRender.lastFrame()).toBeDefined()\n\n // Test with boolean\n const booleanTask = Promise.resolve(true)\n const booleanRender = render(<SingleTask title=\"Boolean task\" taskPromise={booleanTask} />)\n await booleanRender.waitUntilExit()\n expect(booleanRender.lastFrame()).toBeDefined()\n })\n\n test('handles promise with delayed resolution', async () => {\n // Given\n const title = 'Delayed task'\n const taskPromise = new Promise<string>((resolve) => {\n setTimeout(() => resolve('completed'), 100)\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n\n // Wait for completion\n await renderInstance.waitUntilExit()\n\n // Then\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('handles promise with delayed rejection', async () => {\n // Given\n const title = 'Delayed failure'\n const taskPromise = new Promise<string>((resolve, reject) => {\n setTimeout(() => reject(new Error('delayed error')), 100)\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} />)\n\n // Wait for completion - should throw error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('delayed error')\n })\n\n test('preserves error types and messages', async () => {\n // Test with custom error\n class CustomError extends Error {\n constructor(message: string, public code: string) {\n super(message)\n this.name = 'CustomError'\n }\n }\n\n const customError = new CustomError('Custom error message', 'CUSTOM_CODE')\n const taskPromise = Promise.reject(customError)\n\n // When\n const renderInstance = render(<SingleTask title=\"Custom error task\" taskPromise={taskPromise} />)\n\n // Then - should preserve the exact error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Custom error message')\n })\n\n test('handles concurrent promise operations', async () => {\n // Given - Multiple SingleTask components with different promises\n const fastPromise = new Promise((resolve) => setTimeout(() => resolve('fast'), 50))\n const slowPromise = new Promise((resolve) => setTimeout(() => resolve('slow'), 150))\n\n // When\n const fastRender = render(<SingleTask title=\"Fast task\" taskPromise={fastPromise} />)\n const slowRender = render(<SingleTask title=\"Slow task\" taskPromise={slowPromise} />)\n\n // Then - Both should complete successfully\n await fastRender.waitUntilExit()\n await slowRender.waitUntilExit()\n\n expect(fastRender.lastFrame()).toBeDefined()\n expect(slowRender.lastFrame()).toBeDefined()\n })\n\n test('passes noColor prop to LoadingBar component', async () => {\n // Given\n const title = 'No color task'\n const taskPromise = Promise.resolve()\n\n // When - Test that noColor prop doesn't break the component\n const renderInstance = render(<SingleTask title={title} taskPromise={taskPromise} noColor />)\n await renderInstance.waitUntilExit()\n\n // Then - Component should complete successfully with noColor prop\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n})\n"]}
1
+ {"version":3,"file":"SingleTask.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SingleTask.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SingleTask} from './SingleTask.js'\nimport {render} from '../../testing/ui.js'\nimport {TokenizedString} from '../../../../public/node/output.js'\nimport React from 'react'\nimport {describe, expect, test} from 'vitest'\n\ndescribe('SingleTask', () => {\n test('unmounts when promise resolves successfully', async () => {\n // Given\n const title = new TokenizedString('Uploading files')\n let resolvePromise: (value: string) => void\n const task = () =>\n new Promise<string>((resolve) => {\n resolvePromise = resolve\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n\n // Wait for initial render\n await new Promise((resolve) => setTimeout(resolve, 10))\n\n // Resolve the promise\n resolvePromise!('success')\n\n // Wait for component to update and unmount\n await renderInstance.waitUntilExit()\n\n // Then - component should unmount cleanly\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('unmounts when promise rejects', async () => {\n // Given\n const title = new TokenizedString('Failed task')\n let rejectPromise: (error: Error) => void\n const task = () =>\n new Promise<string>((resolve, reject) => {\n rejectPromise = reject\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n\n // Wait for initial render\n await new Promise((resolve) => setTimeout(resolve, 10))\n\n // Reject the promise and expect waitUntilExit to reject\n rejectPromise!(new Error('Task failed'))\n\n // The component should exit with the error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Task failed')\n })\n\n test('handles promise that resolves immediately', async () => {\n // Given\n const title = new TokenizedString('Instant task')\n const task = () => Promise.resolve('immediate success')\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n await renderInstance.waitUntilExit()\n\n // Then - component should complete successfully\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('handles promise that rejects immediately', async () => {\n // Given\n const title = new TokenizedString('Instant failure')\n const task = () => Promise.reject(new Error('Immediate error'))\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n\n // Then - should exit with error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Immediate error')\n })\n\n test('handles different types of promise return values', async () => {\n // Test with string\n let stringResult: string | undefined\n const stringTask = () => Promise.resolve('task completed')\n const stringRender = render(\n <SingleTask\n title={new TokenizedString('String task')}\n task={stringTask}\n onComplete={(result) => (stringResult = result)}\n />,\n )\n await stringRender.waitUntilExit()\n expect(stringRender.lastFrame()).toBeDefined()\n expect(stringResult).toBe('task completed')\n\n // Test with object\n let objectResult: {id: number; name: string} | undefined\n const objectTask = () => Promise.resolve({id: 1, name: 'test'})\n const objectRender = render(\n <SingleTask\n title={new TokenizedString('Object task')}\n task={objectTask}\n onComplete={(result) => (objectResult = result)}\n />,\n )\n await objectRender.waitUntilExit()\n expect(objectRender.lastFrame()).toBeDefined()\n\n // Test with number\n let numberResult: number | undefined\n const numberTask = () => Promise.resolve(42)\n const numberRender = render(\n <SingleTask\n title={new TokenizedString('Number task')}\n task={numberTask}\n onComplete={(result) => (numberResult = result)}\n />,\n )\n await numberRender.waitUntilExit()\n expect(numberRender.lastFrame()).toBeDefined()\n expect(numberResult).toBe(42)\n\n // Test with boolean\n let booleanResult: boolean | undefined\n const booleanTask = () => Promise.resolve(true)\n const booleanRender = render(\n <SingleTask\n title={new TokenizedString('Boolean task')}\n task={booleanTask}\n onComplete={(result) => (booleanResult = result)}\n />,\n )\n await booleanRender.waitUntilExit()\n expect(booleanRender.lastFrame()).toBeDefined()\n expect(booleanResult).toBe(true)\n })\n\n test('handles promise with delayed resolution', async () => {\n // Given\n const title = new TokenizedString('Delayed task')\n const task = () =>\n new Promise<string>((resolve) => {\n setTimeout(() => resolve('completed'), 100)\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n\n // Wait for completion\n await renderInstance.waitUntilExit()\n\n // Then\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('handles promise with delayed rejection', async () => {\n // Given\n const title = new TokenizedString('Delayed failure')\n const task = () =>\n new Promise<string>((resolve, reject) => {\n setTimeout(() => reject(new Error('delayed error')), 100)\n })\n\n // When\n const renderInstance = render(<SingleTask title={title} task={task} />)\n\n // Wait for completion - should throw error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('delayed error')\n })\n\n test('preserves error types and messages', async () => {\n // Test with custom error\n class CustomError extends Error {\n constructor(message: string, public code: string) {\n super(message)\n this.name = 'CustomError'\n }\n }\n\n const customError = new CustomError('Custom error message', 'CUSTOM_CODE')\n const task = () => Promise.reject(customError)\n\n // When\n const renderInstance = render(<SingleTask title={new TokenizedString('Custom error task')} task={task} />)\n\n // Then - should preserve the exact error\n await expect(renderInstance.waitUntilExit()).rejects.toThrow('Custom error message')\n })\n\n test('handles concurrent promise operations', async () => {\n // Given - Multiple SingleTask components with different promises\n const fastPromise = () => new Promise((resolve) => setTimeout(() => resolve('fast'), 50))\n const slowPromise = () => new Promise((resolve) => setTimeout(() => resolve('slow'), 150))\n\n // When\n const fastRender = render(<SingleTask title={new TokenizedString('Fast task')} task={fastPromise} />)\n const slowRender = render(<SingleTask title={new TokenizedString('Slow task')} task={slowPromise} />)\n\n // Then - Both should complete successfully\n await fastRender.waitUntilExit()\n await slowRender.waitUntilExit()\n\n expect(fastRender.lastFrame()).toBeDefined()\n expect(slowRender.lastFrame()).toBeDefined()\n })\n\n test('passes noColor prop to LoadingBar component', async () => {\n // Given\n const title = new TokenizedString('No color task')\n const task = () => Promise.resolve()\n\n // When - Test that noColor prop doesn't break the component\n const renderInstance = render(<SingleTask title={title} task={task} noColor />)\n await renderInstance.waitUntilExit()\n\n // Then - Component should complete successfully with noColor prop\n expect(renderInstance.lastFrame()).toBeDefined()\n })\n\n test('updates status message during task execution', async () => {\n // Given\n const initialTitle = new TokenizedString('Starting task')\n let step1Resolve: () => void\n let step2Resolve: () => void\n let step3Resolve: () => void\n\n const step1Promise = new Promise<void>((resolve) => {\n step1Resolve = resolve\n })\n const step2Promise = new Promise<void>((resolve) => {\n step2Resolve = resolve\n })\n const step3Promise = new Promise<void>((resolve) => {\n step3Resolve = resolve\n })\n\n const task = async (updateStatus: (status: TokenizedString) => void) => {\n updateStatus(new TokenizedString('Running (1 complete)...'))\n await step1Promise\n\n updateStatus(new TokenizedString('Running (2 complete)...'))\n await step2Promise\n\n updateStatus(new TokenizedString('Running (3 complete)...'))\n await step3Promise\n\n return 'completed'\n }\n\n // When\n const renderInstance = render(<SingleTask title={initialTitle} task={task} />)\n\n // Wait for component to render with first status\n await new Promise((resolve) => setTimeout(resolve, 10))\n const frame1 = renderInstance.lastFrame()\n expect(frame1).toContain('1 complete')\n\n // Progress to step 2\n step1Resolve!()\n await new Promise((resolve) => setTimeout(resolve, 10))\n const frame2 = renderInstance.lastFrame()\n expect(frame2).toContain('2 complete')\n\n // Progress to step 3\n step2Resolve!()\n await new Promise((resolve) => setTimeout(resolve, 10))\n const frame3 = renderInstance.lastFrame()\n expect(frame3).toContain('3 complete')\n\n // Complete the task\n step3Resolve!()\n await renderInstance.waitUntilExit()\n })\n})\n"]}
@@ -1,7 +1,8 @@
1
1
  import { AbortSignal } from '../../../../public/node/abort.js';
2
+ import { TokenizedString } from '../../../../public/node/output.js';
2
3
  import React from 'react';
3
4
  export interface Task<TContext = unknown> {
4
- title: string;
5
+ title: string | TokenizedString;
5
6
  task: (ctx: TContext, task: Task<TContext>) => Promise<void | Task<TContext>[]>;
6
7
  retry?: number;
7
8
  retryCount?: number;