@shopify/cli-kit 3.48.5 → 3.49.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/README.md +3 -1
- package/assets/cli-ruby/lib/project_types/theme/commands/console.rb +9 -3
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/proxy_param_builder.rb +2 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/api.rb +7 -7
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/auth_dev_server.rb +18 -3
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/auth_middleware.rb +27 -6
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/remote_evaluator.rb +158 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/resources/success.html +0 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/snippet.rb +81 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl.rb +31 -89
- package/dist/private/node/analytics.js +2 -2
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/graphql.d.ts +2 -2
- package/dist/private/node/api/graphql.js +12 -6
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api.d.ts +1 -1
- package/dist/private/node/api.js +1 -1
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/context/utilities.d.ts +2 -0
- package/dist/private/node/context/utilities.js +3 -2
- package/dist/private/node/context/utilities.js.map +1 -1
- package/dist/private/node/demo-recorder.d.ts +0 -3
- package/dist/private/node/demo-recorder.js +3 -5
- package/dist/private/node/demo-recorder.js.map +1 -1
- package/dist/private/node/session/exchange.js +1 -0
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/testing/ui.d.ts +6 -1
- package/dist/private/node/testing/ui.js +25 -1
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +2 -0
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Command.js +1 -1
- package/dist/private/node/ui/components/Command.js.map +1 -1
- package/dist/private/node/ui/components/Command.test.js +1 -1
- package/dist/private/node/ui/components/Command.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +2 -23
- package/dist/private/node/ui/components/ConcurrentOutput.js +39 -103
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +22 -208
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +2 -0
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +2 -0
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +2 -0
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/hooks/use-abort-signal.d.ts +1 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js +8 -3
- package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
- package/dist/private/node/ui/utilities.d.ts +1 -1
- package/dist/private/node/ui.js +1 -1
- package/dist/private/node/ui.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/base-command.d.ts +2 -4
- package/dist/public/node/base-command.js +18 -4
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/dot-env.d.ts +0 -7
- package/dist/public/node/dot-env.js +1 -9
- package/dist/public/node/dot-env.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +16 -5
- package/dist/public/node/node-package-manager.js +28 -13
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -1
- package/dist/public/node/output.js +4 -0
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/system.js +3 -6
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/testing/ui.d.ts +1 -0
- package/dist/public/node/testing/ui.js +2 -0
- package/dist/public/node/testing/ui.js.map +1 -0
- package/dist/public/node/tree-kill.d.ts +7 -2
- package/dist/public/node/tree-kill.js +165 -4
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui/components.d.ts +1 -0
- package/dist/public/node/ui/components.js +2 -0
- package/dist/public/node/ui/components.js.map +1 -0
- package/dist/public/node/ui/hooks.d.ts +1 -0
- package/dist/public/node/ui/hooks.js +2 -0
- package/dist/public/node/ui/hooks.js.map +1 -0
- package/dist/public/node/ui.d.ts +3 -10
- package/dist/public/node/ui.js +5 -14
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -15
|
@@ -18,16 +18,22 @@ function sanitizeVariables(variables) {
|
|
|
18
18
|
return JSON.stringify(result, null, 2);
|
|
19
19
|
}
|
|
20
20
|
export function errorHandler(api) {
|
|
21
|
-
return (error) => {
|
|
21
|
+
return (error, requestId) => {
|
|
22
22
|
if (error instanceof ClientError) {
|
|
23
|
-
const
|
|
24
|
-
|
|
23
|
+
const { status } = error.response;
|
|
24
|
+
let errorMessage = stringifyMessage(outputContent `
|
|
25
|
+
The ${outputToken.raw(api)} GraphQL API responded unsuccessfully with${status === 200 ? '' : ` the HTTP status ${status} and`} errors:
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
${outputToken.json(error.response.errors)}
|
|
27
28
|
`);
|
|
29
|
+
if (requestId) {
|
|
30
|
+
errorMessage += `
|
|
31
|
+
Request ID: ${requestId}
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
28
34
|
let mappedError;
|
|
29
|
-
if (
|
|
30
|
-
mappedError = new GraphQLClientError(errorMessage,
|
|
35
|
+
if (status < 500) {
|
|
36
|
+
mappedError = new GraphQLClientError(errorMessage, status, error.response.errors);
|
|
31
37
|
}
|
|
32
38
|
else {
|
|
33
39
|
mappedError = new AbortError(errorMessage);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACvE,OAAO,EAAC,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AACxG,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,EAAC,WAAW,EAA6B,MAAM,iBAAiB,CAAA;AAEvE,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,KAAsB,EACtB,SAAqB,EACrB,UAAmC,EAAE;IAErC,WAAW,CAAC,aAAa,CAAA,WAAW,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;IACvD,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;EAC1C,SAAS,CAAC,CAAC,CAAC,sBAAsB,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;;EAEvE,sBAAsB,CAAC,OAAO,CAAC;CAChC,CAAC,CAAA;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAoB;IAC7C,MAAM,MAAM,GAAc,EAAC,GAAG,SAAS,EAAC,CAAA;IACxC,IAAI,QAAQ,IAAI,MAAM,EAAE;QACtB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAA;KACxB;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAI,GAAW;IACzC,OAAO,CAAC,KAAc,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/private/node/api/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,cAAc,CAAA;AACvE,OAAO,EAAC,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAC,MAAM,gCAAgC,CAAA;AACxG,OAAO,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAA;AACxD,OAAO,EAAC,WAAW,EAA6B,MAAM,iBAAiB,CAAA;AAEvE,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,KAAsB,EACtB,SAAqB,EACrB,UAAmC,EAAE;IAErC,WAAW,CAAC,aAAa,CAAA,WAAW,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;IACvD,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;EAC1C,SAAS,CAAC,CAAC,CAAC,sBAAsB,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;;EAEvE,sBAAsB,CAAC,OAAO,CAAC;CAChC,CAAC,CAAA;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,SAAoB;IAC7C,MAAM,MAAM,GAAc,EAAC,GAAG,SAAS,EAAC,CAAA;IACxC,IAAI,QAAQ,IAAI,MAAM,EAAE;QACtB,MAAM,CAAC,MAAM,GAAG,OAAO,CAAA;KACxB;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAI,GAAW;IACzC,OAAO,CAAC,KAAc,EAAE,SAAkB,EAAE,EAAE;QAC5C,IAAI,KAAK,YAAY,WAAW,EAAE;YAChC,MAAM,EAAC,MAAM,EAAC,GAAG,KAAK,CAAC,QAAQ,CAAA;YAC/B,IAAI,YAAY,GAAG,gBAAgB,CAAC,aAAa,CAAA;MACjD,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,6CAClB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,MAAM,MAClD;;EAEJ,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;OAClC,CAAC,CAAA;YACF,IAAI,SAAS,EAAE;gBACb,YAAY,IAAI;cACV,SAAS;CACtB,CAAA;aACM;YACD,IAAI,WAAkB,CAAA;YACtB,IAAI,MAAM,GAAG,GAAG,EAAE;gBAChB,WAAW,GAAG,IAAI,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;aAClF;iBAAM;gBACL,WAAW,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAA;aAC3C;YACD,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;YAC/B,OAAO,WAAW,CAAA;SACnB;aAAM;YACL,OAAO,KAAK,CAAA;SACb;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {GraphQLClientError, sanitizedHeadersOutput} from './headers.js'\nimport {stringifyMessage, outputContent, outputToken, outputDebug} from '../../../public/node/output.js'\nimport {AbortError} from '../../../public/node/error.js'\nimport {ClientError, RequestDocument, Variables} from 'graphql-request'\n\nexport function debugLogRequestInfo(\n api: string,\n query: RequestDocument,\n variables?: Variables,\n headers: {[key: string]: string} = {},\n) {\n outputDebug(outputContent`Sending ${outputToken.json(api)} GraphQL request:\n ${outputToken.raw(query.toString().trim())}\n${variables ? `\\nWith variables:\\n${sanitizeVariables(variables)}\\n` : ''}\nWith request headers:\n${sanitizedHeadersOutput(headers)}\n`)\n}\n\nfunction sanitizeVariables(variables: Variables): string {\n const result: Variables = {...variables}\n if ('apiKey' in result) {\n result.apiKey = '*****'\n }\n return JSON.stringify(result, null, 2)\n}\n\nexport function errorHandler<T>(api: string): (error: unknown, requestId?: string) => Error | unknown {\n return (error: unknown, requestId?: string) => {\n if (error instanceof ClientError) {\n const {status} = error.response\n let errorMessage = stringifyMessage(outputContent`\nThe ${outputToken.raw(api)} GraphQL API responded unsuccessfully with${\n status === 200 ? '' : ` the HTTP status ${status} and`\n } errors:\n\n${outputToken.json(error.response.errors)}\n `)\n if (requestId) {\n errorMessage += `\nRequest ID: ${requestId}\n`\n }\n let mappedError: Error\n if (status < 500) {\n mappedError = new GraphQLClientError(errorMessage, status, error.response.errors)\n } else {\n mappedError = new AbortError(errorMessage)\n }\n mappedError.stack = error.stack\n return mappedError\n } else {\n return error\n }\n }\n}\n"]}
|
|
@@ -8,5 +8,5 @@ interface RequestOptions<T> {
|
|
|
8
8
|
export declare function debugLogResponseInfo<T extends {
|
|
9
9
|
headers: Headers;
|
|
10
10
|
status: number;
|
|
11
|
-
}>({ request, url }: RequestOptions<T>, errorHandler?: (error: unknown) => Error | unknown): Promise<T>;
|
|
11
|
+
}>({ request, url }: RequestOptions<T>, errorHandler?: (error: unknown, requestId: string | undefined) => Error | unknown): Promise<T>;
|
|
12
12
|
export {};
|
package/dist/private/node/api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAExD,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAA;AAO/F,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAC,OAAO,EAAE,GAAG,EAAoB,EACjC,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/private/node/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAExD,OAAO,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAA;AAItC,MAAM,CAAC,MAAM,OAAO,GAAU,CAAC,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAA;AAO/F,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAErG,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAC,OAAO,EAAE,GAAG,EAAoB,EACjC,YAAiF;IAEjF,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,eAAe,GAA4B,EAAE,CAAA;IACnD,IAAI,QAAQ,GAAM,EAAO,CAAA;IACzB,IAAI;QACF,QAAQ,GAAG,MAAM,OAAO,CAAA;QACxB,8DAA8D;QAC9D,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,GAAQ,EAAE,EAAE;YAChD,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACvE,CAAC,CAAC,CAAA;KACH;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,GAAG,YAAY,WAAW,EAAE;YAC9B,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE;gBACzB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAqC,EAAE;oBAC9E,IAAI,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC;wBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;iBACtE;aACF;SACF;QACD,IAAI,YAAY,EAAE;YAChB,MAAM,YAAY,CAAC,GAAG,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC,CAAA;SACzD;aAAM;YACL,MAAM,GAAG,CAAA;SACV;KACF;YAAS;QACR,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC5B,WAAW,CAAC,cAAc,WAAW,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;;EAEhF,sBAAsB,CAAC,eAAe,CAAC;KACpC,CAAC,CAAA;KACH;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["import {sanitizedHeadersOutput} from './api/headers.js'\nimport {sanitizeURL} from './api/urls.js'\nimport {outputDebug} from '@shopify/cli-kit/node/output'\nimport {Headers} from 'form-data'\nimport {ClientError} from 'graphql-request'\nimport {performance} from 'perf_hooks'\n\nexport type API = 'admin' | 'storefront-renderer' | 'partners' | 'business-platform'\n\nexport const allAPIs: API[] = ['admin', 'storefront-renderer', 'partners', 'business-platform']\n\ninterface RequestOptions<T> {\n request: Promise<T>\n url: string\n}\n\nconst interestingResponseHeaders = new Set(['cache-control', 'content-type', 'etag', 'x-request-id'])\n\nexport async function debugLogResponseInfo<T extends {headers: Headers; status: number}>(\n {request, url}: RequestOptions<T>,\n errorHandler?: (error: unknown, requestId: string | undefined) => Error | unknown,\n): Promise<T> {\n const t0 = performance.now()\n const responseHeaders: {[key: string]: string} = {}\n let response: T = {} as T\n try {\n response = await request\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n response.headers.forEach((value: any, key: any) => {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n })\n } catch (err) {\n if (err instanceof ClientError) {\n if (err.response?.headers) {\n for (const [key, value] of err.response?.headers as Iterable<[string, string]>) {\n if (interestingResponseHeaders.has(key)) responseHeaders[key] = value\n }\n }\n }\n if (errorHandler) {\n throw errorHandler(err, responseHeaders['x-request-id'])\n } else {\n throw err\n }\n } finally {\n const t1 = performance.now()\n outputDebug(`Request to ${sanitizeURL(url)} completed in ${Math.round(t1 - t0)} ms\nWith response headers:\n${sanitizedHeadersOutput(responseHeaders)}\n `)\n }\n return response\n}\n"]}
|
|
@@ -9,10 +9,12 @@ export declare function isSet(variable: string | undefined): boolean;
|
|
|
9
9
|
export declare function getCIMetadata(envName: string, envs: NodeJS.ProcessEnv): Metadata;
|
|
10
10
|
export interface Metadata {
|
|
11
11
|
actor?: string;
|
|
12
|
+
attempt?: string;
|
|
12
13
|
branch?: string;
|
|
13
14
|
build?: string;
|
|
14
15
|
commitMessage?: string;
|
|
15
16
|
commitSha?: string;
|
|
16
17
|
run?: string;
|
|
18
|
+
runNumber?: string;
|
|
17
19
|
url?: string;
|
|
18
20
|
}
|
|
@@ -33,12 +33,13 @@ export function getCIMetadata(envName, envs) {
|
|
|
33
33
|
case 'github':
|
|
34
34
|
return {
|
|
35
35
|
actor: envs.GITHUB_ACTOR,
|
|
36
|
+
attempt: envs.GITHUB_RUN_ATTEMPT,
|
|
36
37
|
branch: envs.GITHUB_REF_NAME,
|
|
37
38
|
build: envs.GITHUB_RUN_ID,
|
|
38
|
-
commitMessage: envs.GITHUB_COMMIT_MESSAGE,
|
|
39
39
|
commitSha: envs.GITHUB_SHA,
|
|
40
40
|
run: envs.GITHUB_RUN_ID,
|
|
41
|
-
|
|
41
|
+
runNumber: envs.GITHUB_RUN_NUMBER,
|
|
42
|
+
url: `${envs.GITHUB_SERVER_URL}/${envs.GITHUB_REPOSITORY}/actions/runs/${envs.GITHUB_RUN_ID}`,
|
|
42
43
|
};
|
|
43
44
|
case 'gitlab':
|
|
44
45
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../../../../src/private/node/context/utilities.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,QAA4B;IAChD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACpD,OAAO,KAAK,CAAA;KACb;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,IAAuB;IACpE,QAAQ,OAAO,EAAE;QACf,KAAK,WAAW;YACd,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,uBAAuB;gBACnC,MAAM,EAAE,IAAI,CAAC,gBAAgB;gBAC7B,KAAK,EAAE,IAAI,CAAC,sBAAsB;gBAClC,SAAS,EAAE,IAAI,CAAC,gBAAgB;gBAChC,GAAG,EAAE,IAAI,CAAC,sBAAsB;gBAChC,GAAG,EAAE,IAAI,CAAC,mBAAmB;aAC9B,CAAA;QACH,KAAK,UAAU;YACb,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,eAAe;gBAC3B,MAAM,EAAE,IAAI,CAAC,aAAa;gBAC1B,KAAK,EAAE,IAAI,CAAC,gBAAgB;gBAC5B,SAAS,EAAE,IAAI,CAAC,WAAW;gBAC3B,GAAG,EAAE,IAAI,CAAC,kBAAkB;gBAC5B,GAAG,EAAE,IAAI,CAAC,gBAAgB;aAC3B,CAAA;QACH,KAAK,QAAQ;YACX,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,YAAY;gBACxB,
|
|
1
|
+
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../../../../src/private/node/context/utilities.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,QAA4B;IAChD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACpD,OAAO,KAAK,CAAA;KACb;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,IAAuB;IACpE,QAAQ,OAAO,EAAE;QACf,KAAK,WAAW;YACd,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,uBAAuB;gBACnC,MAAM,EAAE,IAAI,CAAC,gBAAgB;gBAC7B,KAAK,EAAE,IAAI,CAAC,sBAAsB;gBAClC,SAAS,EAAE,IAAI,CAAC,gBAAgB;gBAChC,GAAG,EAAE,IAAI,CAAC,sBAAsB;gBAChC,GAAG,EAAE,IAAI,CAAC,mBAAmB;aAC9B,CAAA;QACH,KAAK,UAAU;YACb,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,eAAe;gBAC3B,MAAM,EAAE,IAAI,CAAC,aAAa;gBAC1B,KAAK,EAAE,IAAI,CAAC,gBAAgB;gBAC5B,SAAS,EAAE,IAAI,CAAC,WAAW;gBAC3B,GAAG,EAAE,IAAI,CAAC,kBAAkB;gBAC5B,GAAG,EAAE,IAAI,CAAC,gBAAgB;aAC3B,CAAA;QACH,KAAK,QAAQ;YACX,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,YAAY;gBACxB,OAAO,EAAE,IAAI,CAAC,kBAAkB;gBAChC,MAAM,EAAE,IAAI,CAAC,eAAe;gBAC5B,KAAK,EAAE,IAAI,CAAC,aAAa;gBACzB,SAAS,EAAE,IAAI,CAAC,UAAU;gBAC1B,GAAG,EAAE,IAAI,CAAC,aAAa;gBACvB,SAAS,EAAE,IAAI,CAAC,iBAAiB;gBACjC,GAAG,EAAE,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,iBAAiB,iBAAiB,IAAI,CAAC,aAAa,EAAE;aAC9F,CAAA;QACH,KAAK,QAAQ;YACX,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,iBAAiB;gBAC7B,MAAM,EAAE,IAAI,CAAC,kBAAkB;gBAC/B,KAAK,EAAE,IAAI,CAAC,cAAc;gBAC1B,SAAS,EAAE,IAAI,CAAC,aAAa;gBAC7B,aAAa,EAAE,IAAI,CAAC,iBAAiB;gBACrC,GAAG,EAAE,IAAI,CAAC,YAAY;gBACtB,GAAG,EAAE,IAAI,CAAC,cAAc;aACzB,CAAA;QACH;YACE,OAAO,EAAE,CAAA;KACZ;AACH,CAAC","sourcesContent":["/**\n * Returns whether an environment variable has been set and is non-empty\n */\nexport function isSet(variable: string | undefined): boolean {\n if (variable === undefined || variable.trim() === '') {\n return false\n }\n return true\n}\n\n/**\n * Returns an object with environment variables from the specified CI environment.\n */\nexport function getCIMetadata(envName: string, envs: NodeJS.ProcessEnv): Metadata {\n switch (envName) {\n case 'bitbucket':\n return {\n actor: envs.BITBUCKET_COMMIT_AUTHOR,\n branch: envs.BITBUCKET_BRANCH,\n build: envs.BITBUCKET_BUILD_NUMBER,\n commitSha: envs.BITBUCKET_COMMIT,\n run: envs.BITBUCKET_BUILD_NUMBER,\n url: envs.BITBUCKET_BUILD_URL,\n }\n case 'circleci':\n return {\n actor: envs.CIRCLE_USERNAME,\n branch: envs.CIRCLE_BRANCH,\n build: envs.CIRCLE_BUILD_NUM,\n commitSha: envs.CIRCLE_SHA1,\n run: envs.CIRCLE_WORKFLOW_ID,\n url: envs.CIRCLE_BUILD_URL,\n }\n case 'github':\n return {\n actor: envs.GITHUB_ACTOR,\n attempt: envs.GITHUB_RUN_ATTEMPT,\n branch: envs.GITHUB_REF_NAME,\n build: envs.GITHUB_RUN_ID,\n commitSha: envs.GITHUB_SHA,\n run: envs.GITHUB_RUN_ID,\n runNumber: envs.GITHUB_RUN_NUMBER,\n url: `${envs.GITHUB_SERVER_URL}/${envs.GITHUB_REPOSITORY}/actions/runs/${envs.GITHUB_RUN_ID}`,\n }\n case 'gitlab':\n return {\n actor: envs.GITLAB_USER_LOGIN,\n branch: envs.CI_COMMIT_REF_NAME,\n build: envs.CI_PIPELINE_ID,\n commitSha: envs.CI_COMMIT_SHA,\n commitMessage: envs.CI_COMMIT_MESSAGE,\n run: envs.CI_RUNNER_ID,\n url: envs.CI_PROJECT_URL,\n }\n default:\n return {}\n }\n}\n\nexport interface Metadata {\n actor?: string\n attempt?: string\n branch?: string\n build?: string\n commitMessage?: string\n commitSha?: string\n run?: string\n runNumber?: string\n url?: string\n}\n"]}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ConcurrentOutputProps } from './ui/components/ConcurrentOutput.js';
|
|
2
1
|
interface Event {
|
|
3
2
|
type: string;
|
|
4
3
|
properties: {
|
|
@@ -14,7 +13,5 @@ export declare function addOrUpdateConcurrentUIEventOutput(data: {
|
|
|
14
13
|
prefix: string;
|
|
15
14
|
index: number;
|
|
16
15
|
output: string;
|
|
17
|
-
}, componentData: {
|
|
18
|
-
footer: ConcurrentOutputProps['footer'];
|
|
19
16
|
}): void;
|
|
20
17
|
export {};
|
|
@@ -31,7 +31,7 @@ class DemoRecorder {
|
|
|
31
31
|
resetSleep() {
|
|
32
32
|
this.sleepStart = Date.now();
|
|
33
33
|
}
|
|
34
|
-
addOrUpdateConcurrentOutput({ prefix, index, output
|
|
34
|
+
addOrUpdateConcurrentOutput({ prefix, index, output }) {
|
|
35
35
|
let last = this.recorded[this.recorded.length - 1];
|
|
36
36
|
if (last?.type === 'concurrent') {
|
|
37
37
|
// Don't sleep between concurrent lines
|
|
@@ -42,8 +42,6 @@ class DemoRecorder {
|
|
|
42
42
|
type: 'concurrent',
|
|
43
43
|
properties: { processes: [], concurrencyStart: Date.now() },
|
|
44
44
|
};
|
|
45
|
-
if (footer)
|
|
46
|
-
eventProperties.properties.footer = footer;
|
|
47
45
|
this.addEvent(eventProperties);
|
|
48
46
|
last = this.recorded[this.recorded.length - 1];
|
|
49
47
|
}
|
|
@@ -112,9 +110,9 @@ export function printEventsJson() {
|
|
|
112
110
|
console.log(_instance.recordedEventsJson());
|
|
113
111
|
}
|
|
114
112
|
}
|
|
115
|
-
export function addOrUpdateConcurrentUIEventOutput(data
|
|
113
|
+
export function addOrUpdateConcurrentUIEventOutput(data) {
|
|
116
114
|
ensureInstance();
|
|
117
|
-
_instance.addOrUpdateConcurrentOutput(data
|
|
115
|
+
_instance.addOrUpdateConcurrentOutput(data);
|
|
118
116
|
}
|
|
119
117
|
function isRecording() {
|
|
120
118
|
return isTruthy(process.env.RECORD_DEMO);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"demo-recorder.js","sourceRoot":"","sources":["../../../src/private/node/demo-recorder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"demo-recorder.js","sourceRoot":"","sources":["../../../src/private/node/demo-recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,wCAAwC,CAAA;AAmB/D,MAAM,YAAY;IAKhB;QACE,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAClB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChE,CAAC;IAED,QAAQ,CAAC,EAAC,IAAI,EAAE,UAAU,EAAQ;QAChC,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,IAAI,CAAC,UAAU,EAAE,CAAA;SAClB;aAAM;YACL,IAAI,CAAC,QAAQ,EAAE,CAAA;SAChB;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,EAAC,CAAC,CAAA;QAC9E,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC9B,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,SAAS,CACnB;YACE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC;SACnD,EACD,IAAI,EACJ,CAAC,CACF,CAAA;IACH,CAAC;IAED,QAAQ;QACN,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;QACtD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC5B,IAAI,QAAQ,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAC,QAAQ,EAAC,EAAC,CAAC,CAAA;SAC5D;IACH,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC9B,CAAC;IAED,2BAA2B,CAAC,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAkD;QAClG,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAClD,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY,EAAE;YAC/B,uCAAuC;YACvC,IAAI,CAAC,UAAU,EAAE,CAAA;SAClB;aAAM;YACL,MAAM,eAAe,GAAU;gBAC7B,IAAI,EAAE,YAAY;gBAClB,UAAU,EAAE,EAAC,SAAS,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC;aAC1D,CAAA;YACD,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAA;YAC9B,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;SAC/C;QACD,MAAM,EAAC,SAAS,EAAC,GAAG,IAAK,CAAC,UAA+C,CAAA;QACzE,OAAO,SAAS,CAAC,MAAM,IAAI,KAAK,EAAE;YAChC,SAAS,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAC,CAAC,CAAA;SACxC;QACD,SAAS,CAAC,KAAK,CAAE,CAAC,MAAM,GAAG,MAAM,CAAA;QACjC,SAAS,CAAC,KAAK,CAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,EAAC,CAAC,CAAA;IAC3E,CAAC;IAED,uBAAuB,CAAC,QAAiB;QACvC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE;gBAC/B,MAAM,EAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAC,GAAG,KAAK,CAAC,UAInD,CAAA;gBACD,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAC,MAAM,EAAE,KAAK,EAA6C,EAAE,EAAE;oBAC9F,IAAI,mBAAmB,GAAG,gBAAgB,CAAA;oBAC1C,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAC,SAAS,EAAE,UAAU,EAAC,EAAE,EAAE;wBAC3D,MAAM,QAAQ,GAAG,CAAC,SAAS,GAAG,mBAAmB,CAAC,GAAG,IAAI,CAAA;wBACzD,mBAAmB,GAAG,SAAS,CAAA;wBAC/B,OAAO,EAAC,QAAQ,EAAE,UAAU,EAAC,CAAA;oBAC/B,CAAC,CAAC,CAAA;oBACF,OAAO,EAAC,MAAM,EAAE,KAAK,EAAE,cAAc,EAAC,CAAA;gBACxC,CAAC,CAAC,CAAA;gBACF,OAAO,EAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,EAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAC,EAAC,CAAA;aACxE;YACD,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,gBAAgB;IACpB,QAAQ,CAAC,MAAa,IAAG,CAAC;IAE1B,kBAAkB;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,EAAC,KAAK,EAAE,EAAE,EAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC7C,CAAC;IAED,QAAQ,KAAI,CAAC;IACb,UAAU,KAAI,CAAC;IAEf,2BAA2B,CAAC,GAAG,KAAgB,IAAG,CAAC;CACpD;AAED,IAAI,SAMH,CAAA;AAED,SAAS,cAAc;IACrB,IAAI,CAAC,SAAS,EAAE;QACd,IAAI,WAAW,EAAE,EAAE;YACjB,SAAS,GAAG,IAAI,YAAY,EAAE,CAAA;SAC/B;aAAM;YACL,SAAS,GAAG,IAAI,gBAAgB,EAAE,CAAA;SACnC;KACF;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,cAAc,EAAE,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAY;IACxC,cAAc,EAAE,CAAA;IAChB,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,cAAc,EAAE,CAAA;IAChB,SAAS,CAAC,UAAU,EAAE,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,WAAW,EAAE,EAAE;QACjB,cAAc,EAAE,CAAA;QAChB,SAAS,CAAC,QAAQ,EAAE,CAAA;QACpB,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC,CAAA;KAC5C;AACH,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,IAAqD;IACtG,cAAc,EAAE,CAAA;IAChB,SAAS,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAA;AAC7C,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import {isTruthy} from '../../public/node/context/utilities.js'\n\ninterface Event {\n type: string\n properties: {[key: string]: unknown}\n // Only used within this recorder for tracking concurrency timeline\n concurrencyStart?: number\n}\n\ninterface ConcurrencyStep {\n timestamp: number\n endMessage: string\n}\n\ninterface ConcurrencyProcess {\n prefix: string\n steps: ConcurrencyStep[]\n}\n\nclass DemoRecorder {\n recorded: Event[]\n sleepStart: number\n command: string\n\n constructor() {\n this.recorded = []\n this.sleepStart = Date.now()\n this.command = ['shopify', ...process.argv.slice(2)].join(' ')\n }\n\n addEvent({type, properties}: Event) {\n if (type === 'taskbar') {\n this.resetSleep()\n } else {\n this.addSleep()\n }\n this.recorded.push({type, properties: JSON.parse(JSON.stringify(properties))})\n this.sleepStart = Date.now()\n }\n\n recordedEventsJson() {\n return JSON.stringify(\n {\n command: this.command,\n steps: this.withFormattedConcurrent(this.recorded),\n },\n null,\n 2,\n )\n }\n\n addSleep() {\n const duration = (Date.now() - this.sleepStart) / 1000\n this.sleepStart = Date.now()\n if (duration > 0.1) {\n this.recorded.push({type: 'sleep', properties: {duration}})\n }\n }\n\n resetSleep() {\n this.sleepStart = Date.now()\n }\n\n addOrUpdateConcurrentOutput({prefix, index, output}: {prefix: string; index: number; output: string}) {\n let last = this.recorded[this.recorded.length - 1]\n if (last?.type === 'concurrent') {\n // Don't sleep between concurrent lines\n this.resetSleep()\n } else {\n const eventProperties: Event = {\n type: 'concurrent',\n properties: {processes: [], concurrencyStart: Date.now()},\n }\n this.addEvent(eventProperties)\n last = this.recorded[this.recorded.length - 1]\n }\n const {processes} = last!.properties as {processes: ConcurrencyProcess[]}\n while (processes.length <= index) {\n processes.push({prefix: '', steps: []})\n }\n processes[index]!.prefix = prefix\n processes[index]!.steps.push({timestamp: Date.now(), endMessage: output})\n }\n\n withFormattedConcurrent(recorded: Event[]) {\n return recorded.map((event) => {\n if (event.type === 'concurrent') {\n const {processes, footer, concurrencyStart} = event.properties as {\n processes: ConcurrencyProcess[]\n footer?: string\n concurrencyStart: number\n }\n const formatted = processes.map(({prefix, steps}: {prefix: string; steps: ConcurrencyStep[]}) => {\n let mostRecentTimestamp = concurrencyStart\n const formattedSteps = steps.map(({timestamp, endMessage}) => {\n const duration = (timestamp - mostRecentTimestamp) / 1000\n mostRecentTimestamp = timestamp\n return {duration, endMessage}\n })\n return {prefix, steps: formattedSteps}\n })\n return {type: 'concurrent', properties: {footer, processes: formatted}}\n }\n return event\n })\n }\n}\n\nclass NoopDemoRecorder {\n addEvent(_event: Event) {}\n\n recordedEventsJson() {\n return JSON.stringify({steps: []}, null, 2)\n }\n\n addSleep() {}\n resetSleep() {}\n\n addOrUpdateConcurrentOutput(..._args: unknown[]) {}\n}\n\nlet _instance: {\n addEvent: (event: Event) => void\n recordedEventsJson: () => string\n resetSleep: () => void\n addSleep: () => void\n addOrUpdateConcurrentOutput: ({prefix, index, output}: {prefix: string; index: number; output: string}) => void\n}\n\nfunction ensureInstance() {\n if (!_instance) {\n if (isRecording()) {\n _instance = new DemoRecorder()\n } else {\n _instance = new NoopDemoRecorder()\n }\n }\n}\n\nexport function initDemoRecorder() {\n ensureInstance()\n}\n\nexport function recordUIEvent(event: Event) {\n ensureInstance()\n _instance.addEvent(event)\n}\n\nexport function resetRecordedSleep() {\n ensureInstance()\n _instance.resetSleep()\n}\n\nexport function printEventsJson(): void {\n if (isRecording()) {\n ensureInstance()\n _instance.addSleep()\n // eslint-disable-next-line no-console\n console.log(_instance.recordedEventsJson())\n }\n}\n\nexport function addOrUpdateConcurrentUIEventOutput(data: {prefix: string; index: number; output: string}) {\n ensureInstance()\n _instance.addOrUpdateConcurrentOutput(data)\n}\n\nfunction isRecording() {\n return isTruthy(process.env.RECORD_DEMO)\n}\n"]}
|
|
@@ -126,6 +126,7 @@ function tokenRequestErrorHandler(error) {
|
|
|
126
126
|
// This means the token is invalid. We clear the session and throw an error to let the caller know.
|
|
127
127
|
return new InvalidRequestError();
|
|
128
128
|
}
|
|
129
|
+
// eslint-disable-next-line @shopify/cli/no-error-factory-functions
|
|
129
130
|
return new AbortError(error);
|
|
130
131
|
}
|
|
131
132
|
async function tokenRequest(params) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {CodeAuthResult} from './authorize.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, ExtendableError} from '../../../public/node/error.js'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n}\n/**\n * Given a valid authorization code, request an identity access token.\n * This token can then be used to get API specific tokens.\n * @param codeData - code and codeVerifier from the authorize endpoint\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n const params = {\n grant_type: 'authorization_code',\n code: codeData.code,\n redirect_uri: 'http://127.0.0.1:3456',\n client_id: clientId,\n code_verifier: codeData.codeVerifier,\n }\n\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const [partners, storefront, businessPlatform, admin] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<ApplicationToken> {\n const appId = applicationId('partners')\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n}\n\nexport type IdentityDeviceError =\n | 'authorization_pending'\n | 'access_denied'\n | 'expired_token'\n | 'slow_down'\n | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = await buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n}\n\nfunction tokenRequestErrorHandler(error: string) {\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult): IdentityToken {\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {CodeAuthResult} from './authorize.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, ExtendableError} from '../../../public/node/error.js'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n}\n/**\n * Given a valid authorization code, request an identity access token.\n * This token can then be used to get API specific tokens.\n * @param codeData - code and codeVerifier from the authorize endpoint\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeCodeForAccessToken(codeData: CodeAuthResult): Promise<IdentityToken> {\n const clientId = await getIdentityClientId()\n const params = {\n grant_type: 'authorization_code',\n code: codeData.code,\n redirect_uri: 'http://127.0.0.1:3456',\n client_id: clientId,\n code_verifier: codeData.codeVerifier,\n }\n\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const [partners, storefront, businessPlatform, admin] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<ApplicationToken> {\n const appId = applicationId('partners')\n const newToken = await requestAppToken('partners', token, ['https://api.shopify.com/auth/partners.app.cli.access'])\n return newToken[appId]!\n}\n\nexport type IdentityDeviceError =\n | 'authorization_pending'\n | 'access_denied'\n | 'expired_token'\n | 'slow_down'\n | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = await buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n}\n\nfunction tokenRequestErrorHandler(error: string) {\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {[key: string]: string}): Promise<Result<TokenRequestResult, string>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n return err(payload.error)\n}\n\nfunction buildIdentityToken(result: TokenRequestResult): IdentityToken {\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
|
|
@@ -28,7 +28,7 @@ interface Instance {
|
|
|
28
28
|
stdin: Stdin;
|
|
29
29
|
frames: string[];
|
|
30
30
|
lastFrame: () => string | undefined;
|
|
31
|
-
waitUntilExit: () =>
|
|
31
|
+
waitUntilExit: () => TrackedPromise<void>;
|
|
32
32
|
}
|
|
33
33
|
interface RenderOptions {
|
|
34
34
|
stdout?: EventEmitter;
|
|
@@ -75,4 +75,9 @@ export declare function sendInputAndWaitForContent(renderInstance: ReturnType<ty
|
|
|
75
75
|
* The reason this function exists is that in CI Ink will clear the last frame on unmount.
|
|
76
76
|
*/
|
|
77
77
|
export declare function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>): string | undefined;
|
|
78
|
+
type TrackedPromise<T> = Promise<T> & {
|
|
79
|
+
isFulfilled: () => boolean;
|
|
80
|
+
isPending: () => boolean;
|
|
81
|
+
isRejected: () => boolean;
|
|
82
|
+
};
|
|
78
83
|
export {};
|
|
@@ -45,7 +45,7 @@ export const render = (tree, options = {}) => {
|
|
|
45
45
|
rerender: instance.rerender,
|
|
46
46
|
unmount: instance.unmount,
|
|
47
47
|
cleanup: instance.cleanup,
|
|
48
|
-
waitUntilExit: instance.waitUntilExit,
|
|
48
|
+
waitUntilExit: () => trackPromise(instance.waitUntilExit()),
|
|
49
49
|
stdout,
|
|
50
50
|
stderr,
|
|
51
51
|
stdin,
|
|
@@ -128,4 +128,28 @@ export async function sendInputAndWaitForContent(renderInstance, content, ...inp
|
|
|
128
128
|
export function getLastFrameAfterUnmount(renderInstance) {
|
|
129
129
|
return isTruthy(process.env.CI) ? renderInstance.frames[renderInstance.frames.length - 2] : renderInstance.lastFrame();
|
|
130
130
|
}
|
|
131
|
+
function trackPromise(promise) {
|
|
132
|
+
let isPending = true;
|
|
133
|
+
let isRejected = false;
|
|
134
|
+
let isFulfilled = false;
|
|
135
|
+
const trackedPromise = promise.then(function (result) {
|
|
136
|
+
isFulfilled = true;
|
|
137
|
+
isPending = false;
|
|
138
|
+
return result;
|
|
139
|
+
}, function (error) {
|
|
140
|
+
isRejected = true;
|
|
141
|
+
isPending = false;
|
|
142
|
+
throw error;
|
|
143
|
+
});
|
|
144
|
+
trackedPromise.isFulfilled = function () {
|
|
145
|
+
return isFulfilled;
|
|
146
|
+
};
|
|
147
|
+
trackedPromise.isPending = function () {
|
|
148
|
+
return isPending;
|
|
149
|
+
};
|
|
150
|
+
trackedPromise.isRejected = function () {
|
|
151
|
+
return isRejected;
|
|
152
|
+
};
|
|
153
|
+
return trackedPromise;
|
|
154
|
+
}
|
|
131
155
|
//# sourceMappingURL=ui.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../src/private/node/testing/ui.ts"],"names":[],"mappings":"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","sourcesContent":["import {isTruthy} from '../../../public/node/context/utilities.js'\nimport {Stdout} from '../ui.js'\nimport {ReactElement} from 'react'\nimport {render as inkRender} from 'ink'\nimport {EventEmitter} from 'events'\n\nclass Stderr extends EventEmitter {\n readonly frames: string[] = []\n private _lastFrame?: string\n\n write = (frame: string) => {\n this.frames.push(frame)\n this._lastFrame = frame\n }\n\n lastFrame = () => this._lastFrame\n}\n\nexport class Stdin extends EventEmitter {\n isTTY: boolean\n\n constructor(options: {isTTY?: boolean} = {}) {\n super()\n this.isTTY = options.isTTY ?? true\n }\n\n write = (data: string) => {\n this.emit('data', data)\n }\n\n setEncoding() {}\n setRawMode() {}\n resume() {}\n pause() {}\n}\n\ninterface Instance {\n rerender: (tree: ReactElement) => void\n unmount: () => void\n cleanup: () => void\n stdout: Stdout\n stderr: Stderr\n stdin: Stdin\n frames: string[]\n lastFrame: () => string | undefined\n waitUntilExit: () => Promise<void>\n}\n\ninterface RenderOptions {\n stdout?: EventEmitter\n stderr?: EventEmitter\n stdin?: EventEmitter\n}\n\nexport const render = (tree: ReactElement, options: RenderOptions = {}): Instance => {\n const stdout = new Stdout({columns: 100})\n const stderr = new Stderr()\n const stdin = new Stdin()\n\n const instance = inkRender(tree, {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stdout: options.stdout ?? (stdout as any),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stderr: options.stderr ?? (stderr as any),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stdin: options.stdin ?? (stdin as any),\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n rerender: instance.rerender,\n unmount: instance.unmount,\n cleanup: instance.cleanup,\n waitUntilExit: instance.waitUntilExit,\n stdout,\n stderr,\n stdin,\n frames: stdout.frames,\n lastFrame: stdout.lastFrame,\n }\n}\n\n/**\n * Wait for the component to be ready to accept input.\n */\nexport function waitForInputsToBeReady() {\n return new Promise((resolve) => setTimeout(resolve, 100))\n}\n\n/**\n * Wait for the last frame to change to anything.\n */\nexport function waitForChange(func: () => void, getChangingValue: () => string | number | undefined) {\n return new Promise<void>((resolve) => {\n const initialValue = getChangingValue()\n\n func()\n\n const interval = setInterval(() => {\n if (getChangingValue() !== initialValue) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\nexport function waitFor(func: () => void, condition: () => boolean) {\n return new Promise<void>((resolve) => {\n func()\n\n const interval = setInterval(() => {\n if (condition()) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\n/**\n * Wait for the last frame to contain specific text.\n */\nexport function waitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n func: () => void = () => {},\n) {\n return waitFor(\n () => func(),\n () => renderInstance.lastFrame()!.includes(content),\n )\n}\n\n/**\n * Send input and wait for the last frame to change.\n *\n * Useful when you want to send some input and wait for anything to change in the interface.\n * If you need to wait for a specific change instead, you can use sendInputAndWaitForContent.\n */\nexport async function sendInputAndWaitForChange(renderInstance: ReturnType<typeof render>, ...inputs: string[]) {\n await waitForChange(() => inputs.forEach((input) => renderInstance.stdin.write(input)), renderInstance.lastFrame)\n // wait for another tick so we give time to react to update caches\n await new Promise((resolve) => setTimeout(resolve, 0))\n}\n\n/** Send input and wait a number of milliseconds.\n *\n * Useful if you know some what will happen after input will take a certain amount of time\n * and it will not cause any visible change so you can't use sendInputAndWaitForChange.\n * This function can also be used if you want to test that nothing changes after some input has been sent.\n */\nexport async function sendInputAndWait(\n renderInstance: ReturnType<typeof render>,\n waitTime: number,\n ...inputs: string[]\n) {\n inputs.forEach((input) => renderInstance.stdin.write(input))\n await new Promise((resolve) => setTimeout(resolve, waitTime))\n}\n\n/**\n * Send input and wait for the last frame to contain specific text.\n *\n * Useful when you want to send some input and wait for a specific change to happen.\n * If you need to wait for any change instead, you can use sendInputAndWaitForChange.\n */\nexport async function sendInputAndWaitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n ...inputs: string[]\n) {\n await waitForContent(renderInstance, content, () => inputs.forEach((input) => renderInstance.stdin.write(input)))\n}\n\n/** Function that is useful when you want to check the last frame of a component that unmounted.\n *\n * The reason this function exists is that in CI Ink will clear the last frame on unmount.\n */\nexport function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>) {\n return isTruthy(process.env.CI) ? renderInstance.frames[renderInstance.frames.length - 2] : renderInstance.lastFrame()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../src/private/node/testing/ui.ts"],"names":[],"mappings":"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","sourcesContent":["import {isTruthy} from '../../../public/node/context/utilities.js'\nimport {Stdout} from '../ui.js'\nimport {ReactElement} from 'react'\nimport {render as inkRender} from 'ink'\nimport {EventEmitter} from 'events'\n\nclass Stderr extends EventEmitter {\n readonly frames: string[] = []\n private _lastFrame?: string\n\n write = (frame: string) => {\n this.frames.push(frame)\n this._lastFrame = frame\n }\n\n lastFrame = () => this._lastFrame\n}\n\nexport class Stdin extends EventEmitter {\n isTTY: boolean\n\n constructor(options: {isTTY?: boolean} = {}) {\n super()\n this.isTTY = options.isTTY ?? true\n }\n\n write = (data: string) => {\n this.emit('data', data)\n }\n\n setEncoding() {}\n setRawMode() {}\n resume() {}\n pause() {}\n}\n\ninterface Instance {\n rerender: (tree: ReactElement) => void\n unmount: () => void\n cleanup: () => void\n stdout: Stdout\n stderr: Stderr\n stdin: Stdin\n frames: string[]\n lastFrame: () => string | undefined\n waitUntilExit: () => TrackedPromise<void>\n}\n\ninterface RenderOptions {\n stdout?: EventEmitter\n stderr?: EventEmitter\n stdin?: EventEmitter\n}\n\nexport const render = (tree: ReactElement, options: RenderOptions = {}): Instance => {\n const stdout = new Stdout({columns: 100})\n const stderr = new Stderr()\n const stdin = new Stdin()\n\n const instance = inkRender(tree, {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stdout: options.stdout ?? (stdout as any),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stderr: options.stderr ?? (stderr as any),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stdin: options.stdin ?? (stdin as any),\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n rerender: instance.rerender,\n unmount: instance.unmount,\n cleanup: instance.cleanup,\n waitUntilExit: () => trackPromise(instance.waitUntilExit()),\n stdout,\n stderr,\n stdin,\n frames: stdout.frames,\n lastFrame: stdout.lastFrame,\n }\n}\n\n/**\n * Wait for the component to be ready to accept input.\n */\nexport function waitForInputsToBeReady() {\n return new Promise((resolve) => setTimeout(resolve, 100))\n}\n\n/**\n * Wait for the last frame to change to anything.\n */\nexport function waitForChange(func: () => void, getChangingValue: () => string | number | undefined) {\n return new Promise<void>((resolve) => {\n const initialValue = getChangingValue()\n\n func()\n\n const interval = setInterval(() => {\n if (getChangingValue() !== initialValue) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\nexport function waitFor(func: () => void, condition: () => boolean) {\n return new Promise<void>((resolve) => {\n func()\n\n const interval = setInterval(() => {\n if (condition()) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\n/**\n * Wait for the last frame to contain specific text.\n */\nexport function waitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n func: () => void = () => {},\n) {\n return waitFor(\n () => func(),\n () => renderInstance.lastFrame()!.includes(content),\n )\n}\n\n/**\n * Send input and wait for the last frame to change.\n *\n * Useful when you want to send some input and wait for anything to change in the interface.\n * If you need to wait for a specific change instead, you can use sendInputAndWaitForContent.\n */\nexport async function sendInputAndWaitForChange(renderInstance: ReturnType<typeof render>, ...inputs: string[]) {\n await waitForChange(() => inputs.forEach((input) => renderInstance.stdin.write(input)), renderInstance.lastFrame)\n // wait for another tick so we give time to react to update caches\n await new Promise((resolve) => setTimeout(resolve, 0))\n}\n\n/** Send input and wait a number of milliseconds.\n *\n * Useful if you know some what will happen after input will take a certain amount of time\n * and it will not cause any visible change so you can't use sendInputAndWaitForChange.\n * This function can also be used if you want to test that nothing changes after some input has been sent.\n */\nexport async function sendInputAndWait(\n renderInstance: ReturnType<typeof render>,\n waitTime: number,\n ...inputs: string[]\n) {\n inputs.forEach((input) => renderInstance.stdin.write(input))\n await new Promise((resolve) => setTimeout(resolve, waitTime))\n}\n\n/**\n * Send input and wait for the last frame to contain specific text.\n *\n * Useful when you want to send some input and wait for a specific change to happen.\n * If you need to wait for any change instead, you can use sendInputAndWaitForChange.\n */\nexport async function sendInputAndWaitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n ...inputs: string[]\n) {\n await waitForContent(renderInstance, content, () => inputs.forEach((input) => renderInstance.stdin.write(input)))\n}\n\n/** Function that is useful when you want to check the last frame of a component that unmounted.\n *\n * The reason this function exists is that in CI Ink will clear the last frame on unmount.\n */\nexport function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>) {\n return isTruthy(process.env.CI) ? renderInstance.frames[renderInstance.frames.length - 2] : renderInstance.lastFrame()\n}\n\ntype TrackedPromise<T> = Promise<T> & {\n isFulfilled: () => boolean\n isPending: () => boolean\n isRejected: () => boolean\n}\n\nfunction trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {\n let isPending = true\n let isRejected = false\n let isFulfilled = false\n\n const trackedPromise = promise.then(\n function (result) {\n isFulfilled = true\n isPending = false\n return result\n },\n function (error) {\n isRejected = true\n isPending = false\n throw error\n },\n ) as TrackedPromise<T>\n\n trackedPromise.isFulfilled = function () {\n return isFulfilled\n }\n trackedPromise.isPending = function () {\n return isPending\n }\n trackedPromise.isRejected = function () {\n return isRejected\n }\n\n return trackedPromise\n}\n"]}
|
|
@@ -625,6 +625,8 @@ describe('AutocompletePrompt', async () => {
|
|
|
625
625
|
}), abortSignal: abortController.signal }));
|
|
626
626
|
const promise = renderInstance.waitUntilExit();
|
|
627
627
|
abortController.abort();
|
|
628
|
+
// wait for the onAbort promise to resolve
|
|
629
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
628
630
|
expect(getLastFrameAfterUnmount(renderInstance)).toEqual('');
|
|
629
631
|
await expect(promise).resolves.toEqual(undefined);
|
|
630
632
|
});
|