@shopify/cli-kit 4.9.5 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.d.ts +5 -0
  2. package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js +22 -0
  3. package/dist/cli/api/graphql/admin/generated/metafield_definitions_by_owner_type.js.map +1 -1
  4. package/dist/private/node/api/graphql.d.ts +2 -1
  5. package/dist/private/node/api/graphql.js +12 -1
  6. package/dist/private/node/api/graphql.js.map +1 -1
  7. package/dist/private/node/api.d.ts +2 -0
  8. package/dist/private/node/api.js +49 -22
  9. package/dist/private/node/api.js.map +1 -1
  10. package/dist/private/node/command-json-schema.js +1 -0
  11. package/dist/private/node/command-json-schema.js.map +1 -1
  12. package/dist/private/node/constants.d.ts +1 -0
  13. package/dist/private/node/constants.js +1 -0
  14. package/dist/private/node/constants.js.map +1 -1
  15. package/dist/private/node/dev-instance-output.d.ts +47 -0
  16. package/dist/private/node/dev-instance-output.js +143 -0
  17. package/dist/private/node/dev-instance-output.js.map +1 -0
  18. package/dist/private/node/json-error.d.ts +1 -15
  19. package/dist/private/node/json-error.js +4 -98
  20. package/dist/private/node/json-error.js.map +1 -1
  21. package/dist/private/node/output-context.d.ts +8 -0
  22. package/dist/private/node/output-context.js +10 -0
  23. package/dist/private/node/output-context.js.map +1 -0
  24. package/dist/private/node/output.test.js +4 -4
  25. package/dist/private/node/output.test.js.map +1 -1
  26. package/dist/private/node/session/automation-token.d.ts +50 -0
  27. package/dist/private/node/session/automation-token.js +77 -0
  28. package/dist/private/node/session/automation-token.js.map +1 -0
  29. package/dist/private/node/session/exchange.d.ts +5 -1
  30. package/dist/private/node/session/exchange.js +97 -7
  31. package/dist/private/node/session/exchange.js.map +1 -1
  32. package/dist/private/node/session/permanent-store-domain.d.ts +21 -0
  33. package/dist/private/node/session/permanent-store-domain.js +72 -0
  34. package/dist/private/node/session/permanent-store-domain.js.map +1 -0
  35. package/dist/private/node/session.d.ts +3 -2
  36. package/dist/private/node/session.js +12 -3
  37. package/dist/private/node/session.js.map +1 -1
  38. package/dist/private/node/themes/trust-challenge.d.ts +31 -0
  39. package/dist/private/node/themes/trust-challenge.js +143 -0
  40. package/dist/private/node/themes/trust-challenge.js.map +1 -0
  41. package/dist/private/node/ui/alert.js +1 -1
  42. package/dist/private/node/ui/alert.js.map +1 -1
  43. package/dist/private/node/ui/components/ConcurrentOutput.d.ts +2 -7
  44. package/dist/private/node/ui/components/ConcurrentOutput.js +4 -8
  45. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  46. package/dist/private/node/ui/components/LoadingBar.js +9 -15
  47. package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
  48. package/dist/private/node/ui/components/LoadingBar.test.js +45 -107
  49. package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
  50. package/dist/private/node/ui/components/LoadingIndicator.d.ts +7 -0
  51. package/dist/private/node/ui/components/LoadingIndicator.js +22 -0
  52. package/dist/private/node/ui/components/LoadingIndicator.js.map +1 -0
  53. package/dist/private/node/ui/components/Table/Table.d.ts +8 -0
  54. package/dist/private/node/ui/components/Table/Table.js +18 -2
  55. package/dist/private/node/ui/components/Table/Table.js.map +1 -1
  56. package/dist/public/common/version.d.ts +1 -1
  57. package/dist/public/common/version.js +1 -1
  58. package/dist/public/common/version.js.map +1 -1
  59. package/dist/public/node/api/admin.js +13 -0
  60. package/dist/public/node/api/admin.js.map +1 -1
  61. package/dist/public/node/api/graphql.js +38 -7
  62. package/dist/public/node/api/graphql.js.map +1 -1
  63. package/dist/public/node/archiver.js +13 -6
  64. package/dist/public/node/archiver.js.map +1 -1
  65. package/dist/public/node/base-command.d.ts +6 -0
  66. package/dist/public/node/base-command.js +97 -16
  67. package/dist/public/node/base-command.js.map +1 -1
  68. package/dist/public/node/dev-instance.d.ts +138 -0
  69. package/dist/public/node/dev-instance.js +365 -0
  70. package/dist/public/node/dev-instance.js.map +1 -0
  71. package/dist/public/node/environment.d.ts +6 -3
  72. package/dist/public/node/environment.js +11 -4
  73. package/dist/public/node/environment.js.map +1 -1
  74. package/dist/public/node/error/index.js +2 -1
  75. package/dist/public/node/error/index.js.map +1 -1
  76. package/dist/public/node/error/schema.d.ts +24 -24
  77. package/dist/public/node/error/serialization.d.ts +8 -0
  78. package/dist/public/node/error/serialization.js +103 -0
  79. package/dist/public/node/error/serialization.js.map +1 -0
  80. package/dist/public/node/graphiql/server.js +18 -2
  81. package/dist/public/node/graphiql/server.js.map +1 -1
  82. package/dist/public/node/is-global.js +2 -1
  83. package/dist/public/node/is-global.js.map +1 -1
  84. package/dist/public/node/notifications-system.d.ts +6 -6
  85. package/dist/public/node/path.d.ts +19 -3
  86. package/dist/public/node/path.js +21 -3
  87. package/dist/public/node/path.js.map +1 -1
  88. package/dist/public/node/session.d.ts +38 -3
  89. package/dist/public/node/session.js +56 -9
  90. package/dist/public/node/session.js.map +1 -1
  91. package/dist/public/node/system.d.ts +4 -0
  92. package/dist/public/node/system.js +39 -9
  93. package/dist/public/node/system.js.map +1 -1
  94. package/dist/public/node/themes/api.d.ts +9 -0
  95. package/dist/public/node/themes/api.js +50 -22
  96. package/dist/public/node/themes/api.js.map +1 -1
  97. package/dist/public/node/themes/theme-manager.d.ts +8 -1
  98. package/dist/public/node/themes/theme-manager.js +1 -1
  99. package/dist/public/node/themes/theme-manager.js.map +1 -1
  100. package/dist/public/node/tree-kill.js +12 -2
  101. package/dist/public/node/tree-kill.js.map +1 -1
  102. package/dist/public/node/ui/components.d.ts +1 -0
  103. package/dist/public/node/ui/components.js +1 -0
  104. package/dist/public/node/ui/components.js.map +1 -1
  105. package/dist/public/node/ui.d.ts +24 -4
  106. package/dist/public/node/ui.js +54 -21
  107. package/dist/public/node/ui.js.map +1 -1
  108. package/dist/public/node/upgrade/output.d.ts +17 -0
  109. package/dist/public/node/upgrade/output.js +51 -0
  110. package/dist/public/node/upgrade/output.js.map +1 -0
  111. package/dist/public/node/upgrade/result.d.ts +8 -0
  112. package/dist/public/node/upgrade/result.js +21 -0
  113. package/dist/public/node/upgrade/result.js.map +1 -0
  114. package/dist/public/node/upgrade/types.d.ts +61 -0
  115. package/dist/public/node/upgrade/types.js +46 -0
  116. package/dist/public/node/upgrade/types.js.map +1 -0
  117. package/dist/public/node/upgrade.d.ts +8 -0
  118. package/dist/public/node/upgrade.js +57 -22
  119. package/dist/public/node/upgrade.js.map +1 -1
  120. package/dist/tsconfig.tsbuildinfo +1 -1
  121. package/package.json +3 -3
  122. package/dist/private/node/ui/components/TextAnimation.d.ts +0 -10
  123. package/dist/private/node/ui/components/TextAnimation.js +0 -56
  124. package/dist/private/node/ui/components/TextAnimation.js.map +0 -1
  125. package/dist/private/node/ui/components/TextAnimation.test.d.ts +0 -1
  126. package/dist/private/node/ui/components/TextAnimation.test.js +0 -73
  127. package/dist/private/node/ui/components/TextAnimation.test.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ import { getConcurrentOutputContext, useConcurrentOutputContext } from './output-context.js';
2
+ import { unstyled } from '../../public/node/output.js';
3
+ import { defineJsonOutputSchema, formatJsonOutputTimestamp, jsonOutputTimestampSchema, } from '../../public/node/json-output-schema.js';
4
+ import { zod } from '../../public/node/schema.js';
5
+ import { createWriteStream } from 'fs';
6
+ import { Writable } from 'stream';
7
+ import { finished } from 'stream/promises';
8
+ import { StringDecoder } from 'string_decoder';
9
+ import { once } from 'events';
10
+ export const devInstanceLogOutputSchema = defineJsonOutputSchema({
11
+ name: 'DevInstanceLogEntry',
12
+ schema: zod
13
+ .object({
14
+ timestamp: jsonOutputTimestampSchema,
15
+ source: zod.string().describe('What produced the line, for example a process prefix like web or extensions.'),
16
+ level: zod.enum(['debug', 'info', 'warning', 'error']).optional(),
17
+ message: zod.string(),
18
+ })
19
+ .strict(),
20
+ });
21
+ export function createDevInstanceOutput({ logFile, logOutput, isActive, onError }) {
22
+ // Each run starts a fresh log.
23
+ const logStream = createWriteStream(logFile, { flags: 'w', mode: 0o600 });
24
+ logStream.on('error', onError);
25
+ logOutput?.on('error', onError);
26
+ const opened = once(logStream, 'open');
27
+ const outputs = new Set();
28
+ const writeLogEntry = async (entry) => {
29
+ if (!isActive())
30
+ return;
31
+ const record = devInstanceLogOutputSchema.validate({
32
+ ...entry,
33
+ timestamp: entry.timestamp ?? formatJsonOutputTimestamp(new Date()),
34
+ });
35
+ const line = `${JSON.stringify(record)}\n`;
36
+ try {
37
+ await writeToStream(logStream, line);
38
+ if (logOutput)
39
+ await writeToStream(logOutput, line);
40
+ }
41
+ catch (error) {
42
+ onError(error);
43
+ throw error;
44
+ }
45
+ };
46
+ return {
47
+ opened,
48
+ log: writeLogEntry,
49
+ tee: (target, { source, stringWritesAreMessages = false }) => {
50
+ const decoder = new StringDecoder('utf8');
51
+ let pending = '';
52
+ let currentSource = source;
53
+ const flushLines = async (text) => {
54
+ const lines = text.split(/\r?\n/);
55
+ pending = lines.pop() ?? '';
56
+ await Promise.all(lines.map(async (line) => {
57
+ const message = unstyled(line).trimEnd();
58
+ if (message.length > 0)
59
+ await writeLogEntry({ source: currentSource, message });
60
+ }));
61
+ };
62
+ const flush = () => flushLines(`${pending}${decoder.end()}\n`);
63
+ const output = new DevInstanceOutput({
64
+ decodeStrings: !stringWritesAreMessages,
65
+ write(chunk, encoding, callback) {
66
+ const nextSource = getConcurrentOutputContext()?.outputPrefix ?? source;
67
+ const completeMessage = stringWritesAreMessages && typeof chunk === 'string';
68
+ const previous = nextSource !== currentSource || completeMessage ? flush() : Promise.resolve();
69
+ currentSource = nextSource;
70
+ Promise.all([
71
+ previous,
72
+ writeToStream(target, chunk, encoding),
73
+ flushLines(pending +
74
+ decoder.write(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk) +
75
+ (completeMessage ? '\n' : '')),
76
+ ])
77
+ .then(() => callback())
78
+ .catch(callback);
79
+ },
80
+ final(callback) {
81
+ flush()
82
+ .then(() => callback())
83
+ .catch(callback);
84
+ },
85
+ });
86
+ const onTargetError = (error) => output.destroy(error);
87
+ target.on('error', onTargetError);
88
+ output.on('error', (error) => onError(error));
89
+ output.once('close', () => {
90
+ target.off('error', onTargetError);
91
+ });
92
+ outputs.add(output);
93
+ return output;
94
+ },
95
+ flush: () => Promise.allSettled([...outputs].map((output) => endStream(output))),
96
+ close: async () => {
97
+ try {
98
+ await endStream(logStream);
99
+ if (logOutput && !logOutput.destroyed)
100
+ await writeToStream(logOutput, '');
101
+ }
102
+ finally {
103
+ logOutput?.off('error', onError);
104
+ }
105
+ },
106
+ };
107
+ }
108
+ // Writable processes queued chunks in an earlier write's context. Capture context when each chunk is submitted.
109
+ class DevInstanceOutput extends Writable {
110
+ contexts = [];
111
+ constructor(options) {
112
+ super({
113
+ ...options,
114
+ write: (chunk, encoding, callback) => {
115
+ useConcurrentOutputContext(this.contexts.shift() ?? {}, () => options.write.call(this, chunk, encoding, callback));
116
+ },
117
+ });
118
+ }
119
+ write(chunk, encoding, callback) {
120
+ this.contexts.push(getConcurrentOutputContext());
121
+ return typeof encoding === 'string'
122
+ ? super.write(chunk, encoding, callback)
123
+ : super.write(chunk, encoding ?? callback);
124
+ }
125
+ end(chunk, encoding, callback) {
126
+ if (chunk !== undefined && chunk !== null && typeof chunk !== 'function')
127
+ this.contexts.push(getConcurrentOutputContext());
128
+ if (typeof chunk === 'function')
129
+ return super.end(chunk);
130
+ return typeof encoding === 'string' ? super.end(chunk, encoding, callback) : super.end(chunk, encoding ?? callback);
131
+ }
132
+ }
133
+ async function writeToStream(stream, chunk, encoding = 'utf8') {
134
+ await new Promise((resolve, reject) => {
135
+ stream.write(chunk, encoding, (error) => (error ? reject(error) : resolve()));
136
+ });
137
+ }
138
+ async function endStream(stream) {
139
+ const completed = finished(stream, { cleanup: true });
140
+ stream.end();
141
+ await completed;
142
+ }
143
+ //# sourceMappingURL=dev-instance-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-instance-output.js","sourceRoot":"","sources":["../../../src/private/node/dev-instance-output.ts"],"names":[],"mappings":"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","sourcesContent":["import {ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext} from './output-context.js'\nimport {unstyled} from '../../public/node/output.js'\nimport {\n defineJsonOutputSchema,\n formatJsonOutputTimestamp,\n jsonOutputTimestampSchema,\n} from '../../public/node/json-output-schema.js'\nimport {zod} from '../../public/node/schema.js'\nimport {createWriteStream} from 'fs'\nimport {Writable, type WritableOptions} from 'stream'\nimport {finished} from 'stream/promises'\nimport {StringDecoder} from 'string_decoder'\nimport {once} from 'events'\n\nexport const devInstanceLogOutputSchema = defineJsonOutputSchema({\n name: 'DevInstanceLogEntry',\n schema: zod\n .object({\n timestamp: jsonOutputTimestampSchema,\n source: zod.string().describe('What produced the line, for example a process prefix like web or extensions.'),\n level: zod.enum(['debug', 'info', 'warning', 'error']).optional(),\n message: zod.string(),\n })\n .strict(),\n})\n\n/** One line of a dev instance's JSON Lines log. */\nexport type DevInstanceLogEntry = zod.infer<typeof devInstanceLogOutputSchema.schema>\n\ninterface DevInstanceOutputOptions {\n logFile: string\n logOutput?: Writable\n isActive: () => boolean\n onError: (error: unknown) => void\n}\n\nexport function createDevInstanceOutput({logFile, logOutput, isActive, onError}: DevInstanceOutputOptions) {\n // Each run starts a fresh log.\n const logStream = createWriteStream(logFile, {flags: 'w', mode: 0o600})\n logStream.on('error', onError)\n logOutput?.on('error', onError)\n const opened = once(logStream, 'open')\n const outputs = new Set<Writable>()\n\n const writeLogEntry = async (entry: Omit<DevInstanceLogEntry, 'timestamp'> & {timestamp?: string}) => {\n if (!isActive()) return\n const record = devInstanceLogOutputSchema.validate({\n ...entry,\n timestamp: entry.timestamp ?? formatJsonOutputTimestamp(new Date()),\n })\n const line = `${JSON.stringify(record)}\\n`\n try {\n await writeToStream(logStream, line)\n if (logOutput) await writeToStream(logOutput, line)\n } catch (error) {\n onError(error)\n throw error\n }\n }\n\n return {\n opened,\n log: writeLogEntry,\n tee: (\n target: Writable,\n {source, stringWritesAreMessages = false}: {source: string; stringWritesAreMessages?: boolean},\n ) => {\n const decoder = new StringDecoder('utf8')\n let pending = ''\n let currentSource = source\n const flushLines = async (text: string) => {\n const lines = text.split(/\\r?\\n/)\n pending = lines.pop() ?? ''\n await Promise.all(\n lines.map(async (line) => {\n const message = unstyled(line).trimEnd()\n if (message.length > 0) await writeLogEntry({source: currentSource, message})\n }),\n )\n }\n const flush = () => flushLines(`${pending}${decoder.end()}\\n`)\n const output = new DevInstanceOutput({\n decodeStrings: !stringWritesAreMessages,\n write(chunk: Buffer | string, encoding, callback) {\n const nextSource = getConcurrentOutputContext()?.outputPrefix ?? source\n const completeMessage = stringWritesAreMessages && typeof chunk === 'string'\n const previous = nextSource !== currentSource || completeMessage ? flush() : Promise.resolve()\n currentSource = nextSource\n Promise.all([\n previous,\n writeToStream(target, chunk, encoding),\n flushLines(\n pending +\n decoder.write(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk) +\n (completeMessage ? '\\n' : ''),\n ),\n ])\n .then(() => callback())\n .catch(callback)\n },\n final(callback) {\n flush()\n .then(() => callback())\n .catch(callback)\n },\n })\n const onTargetError = (error: Error) => output.destroy(error)\n target.on('error', onTargetError)\n output.on('error', (error) => onError(error))\n output.once('close', () => {\n target.off('error', onTargetError)\n })\n outputs.add(output)\n return output\n },\n flush: () => Promise.allSettled([...outputs].map((output) => endStream(output))),\n close: async () => {\n try {\n await endStream(logStream)\n if (logOutput && !logOutput.destroyed) await writeToStream(logOutput, '')\n } finally {\n logOutput?.off('error', onError)\n }\n },\n }\n}\n\n// Writable processes queued chunks in an earlier write's context. Capture context when each chunk is submitted.\nclass DevInstanceOutput extends Writable {\n private readonly contexts: (ConcurrentOutputContext | undefined)[] = []\n\n constructor(options: WritableOptions & {write: NonNullable<WritableOptions['write']>}) {\n super({\n ...options,\n write: (chunk, encoding, callback) => {\n useConcurrentOutputContext(this.contexts.shift() ?? {}, () =>\n options.write.call(this, chunk, encoding, callback),\n )\n },\n })\n }\n\n write(\n chunk: string | Uint8Array,\n encoding?: BufferEncoding | ((error?: Error | null) => void),\n callback?: (error?: Error | null) => void,\n ): boolean {\n this.contexts.push(getConcurrentOutputContext())\n return typeof encoding === 'string'\n ? super.write(chunk, encoding, callback)\n : super.write(chunk, encoding ?? callback)\n }\n\n end(\n chunk?: string | Uint8Array | null | (() => void),\n encoding?: BufferEncoding | (() => void),\n callback?: () => void,\n ): this {\n if (chunk !== undefined && chunk !== null && typeof chunk !== 'function')\n this.contexts.push(getConcurrentOutputContext())\n if (typeof chunk === 'function') return super.end(chunk)\n return typeof encoding === 'string' ? super.end(chunk, encoding, callback) : super.end(chunk, encoding ?? callback)\n }\n}\n\nasync function writeToStream(stream: Writable, chunk: Buffer | string, encoding: BufferEncoding = 'utf8') {\n await new Promise<void>((resolve, reject) => {\n stream.write(chunk, encoding, (error) => (error ? reject(error) : resolve()))\n })\n}\n\nasync function endStream(stream: Writable) {\n const completed = finished(stream, {cleanup: true})\n stream.end()\n await completed\n}\n"]}
@@ -1,16 +1,3 @@
1
- interface FatalErrorLike {
2
- type?: number;
3
- message?: unknown;
4
- formattedMessage?: unknown;
5
- tryMessage?: unknown;
6
- nextSteps?: unknown;
7
- customSections?: unknown;
8
- stack?: unknown;
9
- command?: unknown;
10
- args?: unknown;
11
- details?: unknown;
12
- code?: unknown;
13
- }
14
1
  /**
15
2
  * Writes the public JSON representation of a fatal error to stdout.
16
3
  *
@@ -19,5 +6,4 @@ interface FatalErrorLike {
19
6
  *
20
7
  * @param error - Fatal error to serialize.
21
8
  */
22
- export declare function renderFatalErrorAsJson(error: FatalErrorLike): void;
23
- export {};
9
+ export declare function renderFatalErrorAsJson(error: unknown): void;
@@ -1,101 +1,7 @@
1
- import { tokenItemToJsonString } from './ui/components/token-item.js';
2
1
  import { FatalErrorType } from '../../public/node/error.js';
3
2
  import { jsonErrorOutputSchema } from '../../public/node/error/schema.js';
4
- import { outputResult, unstyled } from '../../public/node/output.js';
5
- function externalCommand(error) {
6
- if (typeof error.command !== 'string' || !Array.isArray(error.args))
7
- return;
8
- if (!error.args.every((arg) => typeof arg === 'string'))
9
- return;
10
- return { command: error.command, args: error.args };
11
- }
12
- function jsonErrorType(error, external) {
13
- if (error.type === FatalErrorType.Abort) {
14
- return external ? 'external' : 'abort';
15
- }
16
- return 'bug';
17
- }
18
- function jsonTokenItem(token) {
19
- if (token === null || token === undefined)
20
- return;
21
- try {
22
- const message = tokenItemToJsonString(token);
23
- return typeof message === 'string' ? unstyled(message) : undefined;
24
- }
25
- catch (error) {
26
- if (error instanceof TypeError)
27
- return undefined;
28
- throw error;
29
- }
30
- }
31
- function jsonTokenItems(items) {
32
- if (!Array.isArray(items))
33
- return;
34
- const renderedItems = items.map(jsonTokenItem).filter((item) => item !== undefined);
35
- return renderedItems.length > 0 ? renderedItems : undefined;
36
- }
37
- function jsonTable(data) {
38
- if (!Array.isArray(data))
39
- return;
40
- return data
41
- .filter((row) => Array.isArray(row))
42
- .map((row) => row.map((cell) => jsonTokenItem(cell) ?? ''));
43
- }
44
- function jsonCustomSection(section) {
45
- if (typeof section !== 'object' || section === null || !('body' in section))
46
- return;
47
- const title = 'title' in section && typeof section.title === 'string' ? unstyled(section.title) : undefined;
48
- const sectionBody = section.body;
49
- const body = typeof sectionBody === 'object' && sectionBody !== null && 'tabularData' in sectionBody
50
- ? jsonTable(sectionBody.tabularData)
51
- : jsonTokenItem(sectionBody);
52
- if (body === undefined)
53
- return;
54
- return { ...(title ? { title } : {}), body };
55
- }
56
- function jsonCustomSections(sections) {
57
- if (!Array.isArray(sections))
58
- return;
59
- const renderedSections = sections
60
- .map(jsonCustomSection)
61
- .filter((section) => section !== undefined);
62
- return renderedSections.length > 0 ? renderedSections : undefined;
63
- }
64
- function jsonErrorDocument(error) {
65
- if (error.type === FatalErrorType.AbortSilent)
66
- return;
67
- const external = externalCommand(error);
68
- const type = jsonErrorType(error, external);
69
- const formattedMessage = jsonTokenItem(error.formattedMessage);
70
- const message = formattedMessage ?? (typeof error.message === 'string' ? unstyled(error.message) : 'Unknown error');
71
- const tryMessage = jsonTokenItem(error.tryMessage);
72
- const nextSteps = jsonTokenItems(error.nextSteps);
73
- const customSections = jsonCustomSections(error.customSections);
74
- const details = error.details;
75
- const commonFields = {
76
- message,
77
- ...(typeof error.code === 'string' && error.code.length > 0 ? { code: error.code } : {}),
78
- ...(tryMessage === undefined ? {} : { tryMessage }),
79
- ...(nextSteps === undefined ? {} : { nextSteps }),
80
- ...(customSections === undefined ? {} : { customSections }),
81
- ...(details === undefined ? {} : { details }),
82
- };
83
- let jsonError;
84
- if (type === 'bug') {
85
- jsonError = {
86
- type,
87
- ...commonFields,
88
- ...(typeof error.stack === 'string' ? { stack: unstyled(error.stack) } : {}),
89
- };
90
- }
91
- else if (type === 'external' && external) {
92
- jsonError = { type, ...commonFields, ...external };
93
- }
94
- else {
95
- jsonError = { type: 'abort', ...commonFields };
96
- }
97
- return { error: jsonError };
98
- }
3
+ import { errorToJson } from '../../public/node/error/serialization.js';
4
+ import { outputResult } from '../../public/node/output.js';
99
5
  /**
100
6
  * Writes the public JSON representation of a fatal error to stdout.
101
7
  *
@@ -107,9 +13,9 @@ function jsonErrorDocument(error) {
107
13
  export function renderFatalErrorAsJson(error) {
108
14
  let serializedDocument;
109
15
  try {
110
- const document = jsonErrorDocument(error);
111
- if (!document)
16
+ if (typeof error === 'object' && error !== null && 'type' in error && error.type === FatalErrorType.AbortSilent)
112
17
  return;
18
+ const document = { error: errorToJson(error) };
113
19
  serializedDocument = JSON.stringify(jsonErrorOutputSchema.validate(document));
114
20
  // Serialization must not replace the JSON contract with a text banner.
115
21
  // eslint-disable-next-line no-catch-all/no-catch-all
@@ -1 +1 @@
1
- {"version":3,"file":"json-error.js","sourceRoot":"","sources":["../../../src/private/node/json-error.ts"],"names":[],"mappings":"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","sourcesContent":["import {tokenItemToJsonString, type TokenItem} from './ui/components/token-item.js'\nimport {FatalErrorType} from '../../public/node/error.js'\nimport {jsonErrorOutputSchema} from '../../public/node/error/schema.js'\nimport {outputResult, unstyled} from '../../public/node/output.js'\nimport type {\n JsonError,\n JsonErrorCustomSection,\n JsonErrorDocument,\n JsonErrorType,\n} from '../../public/node/error/types.js'\n\ninterface FatalErrorLike {\n type?: number\n message?: unknown\n formattedMessage?: unknown\n tryMessage?: unknown\n nextSteps?: unknown\n customSections?: unknown\n stack?: unknown\n command?: unknown\n args?: unknown\n details?: unknown\n code?: unknown\n}\n\ninterface ExternalCommand {\n command: string\n args: string[]\n}\n\nfunction externalCommand(error: FatalErrorLike): ExternalCommand | undefined {\n if (typeof error.command !== 'string' || !Array.isArray(error.args)) return\n if (!error.args.every((arg) => typeof arg === 'string')) return\n\n return {command: error.command, args: error.args}\n}\n\nfunction jsonErrorType(error: FatalErrorLike, external: ExternalCommand | undefined): JsonErrorType {\n if (error.type === FatalErrorType.Abort) {\n return external ? 'external' : 'abort'\n }\n return 'bug'\n}\n\nfunction jsonTokenItem(token: unknown): string | undefined {\n if (token === null || token === undefined) return\n\n try {\n const message = tokenItemToJsonString(token as TokenItem)\n return typeof message === 'string' ? unstyled(message) : undefined\n } catch (error) {\n if (error instanceof TypeError) return undefined\n throw error\n }\n}\n\nfunction jsonTokenItems(items: unknown): string[] | undefined {\n if (!Array.isArray(items)) return\n\n const renderedItems = items.map(jsonTokenItem).filter((item): item is string => item !== undefined)\n return renderedItems.length > 0 ? renderedItems : undefined\n}\n\nfunction jsonTable(data: unknown): string[][] | undefined {\n if (!Array.isArray(data)) return\n\n return data\n .filter((row): row is unknown[] => Array.isArray(row))\n .map((row) => row.map((cell) => jsonTokenItem(cell) ?? ''))\n}\n\nfunction jsonCustomSection(section: unknown): JsonErrorCustomSection | undefined {\n if (typeof section !== 'object' || section === null || !('body' in section)) return\n\n const title = 'title' in section && typeof section.title === 'string' ? unstyled(section.title) : undefined\n const sectionBody = section.body\n const body =\n typeof sectionBody === 'object' && sectionBody !== null && 'tabularData' in sectionBody\n ? jsonTable(sectionBody.tabularData)\n : jsonTokenItem(sectionBody)\n\n if (body === undefined) return\n return {...(title ? {title} : {}), body}\n}\n\nfunction jsonCustomSections(sections: unknown): JsonErrorCustomSection[] | undefined {\n if (!Array.isArray(sections)) return\n\n const renderedSections = sections\n .map(jsonCustomSection)\n .filter((section): section is JsonErrorCustomSection => section !== undefined)\n return renderedSections.length > 0 ? renderedSections : undefined\n}\n\nfunction jsonErrorDocument(error: FatalErrorLike): JsonErrorDocument | undefined {\n if (error.type === FatalErrorType.AbortSilent) return\n\n const external = externalCommand(error)\n const type = jsonErrorType(error, external)\n const formattedMessage = jsonTokenItem(error.formattedMessage)\n const message = formattedMessage ?? (typeof error.message === 'string' ? unstyled(error.message) : 'Unknown error')\n const tryMessage = jsonTokenItem(error.tryMessage)\n const nextSteps = jsonTokenItems(error.nextSteps)\n const customSections = jsonCustomSections(error.customSections)\n const details = error.details\n\n const commonFields = {\n message,\n ...(typeof error.code === 'string' && error.code.length > 0 ? {code: error.code} : {}),\n ...(tryMessage === undefined ? {} : {tryMessage}),\n ...(nextSteps === undefined ? {} : {nextSteps}),\n ...(customSections === undefined ? {} : {customSections}),\n ...(details === undefined ? {} : {details}),\n }\n\n let jsonError: JsonError\n if (type === 'bug') {\n jsonError = {\n type,\n ...commonFields,\n ...(typeof error.stack === 'string' ? {stack: unstyled(error.stack)} : {}),\n }\n } else if (type === 'external' && external) {\n jsonError = {type, ...commonFields, ...external}\n } else {\n jsonError = {type: 'abort', ...commonFields}\n }\n\n return {error: jsonError}\n}\n\n/**\n * Writes the public JSON representation of a fatal error to stdout.\n *\n * The allow-list mirrors the meaningful content of the regular fatal-error renderer.\n * Arbitrary error properties remain private and are never copied to stdout.\n *\n * @param error - Fatal error to serialize.\n */\nexport function renderFatalErrorAsJson(error: FatalErrorLike): void {\n let serializedDocument: string\n try {\n const document = jsonErrorDocument(error)\n if (!document) return\n serializedDocument = JSON.stringify(jsonErrorOutputSchema.validate(document))\n // Serialization must not replace the JSON contract with a text banner.\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n serializedDocument = JSON.stringify({error: {type: 'bug', message: 'Failed to serialize the error as JSON.'}})\n }\n\n // Keep write failures separate: retrying after a partial write could corrupt stdout.\n outputResult(serializedDocument)\n}\n"]}
1
+ {"version":3,"file":"json-error.js","sourceRoot":"","sources":["../../../src/private/node/json-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAC,qBAAqB,EAAC,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAC,WAAW,EAAC,MAAM,0CAA0C,CAAA;AACpE,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAA;AAExD;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,kBAA0B,CAAA;IAC9B,IAAI,CAAC;QACH,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,WAAW;YAC7G,OAAM;QACR,MAAM,QAAQ,GAAG,EAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAC,CAAA;QAC5C,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC7E,uEAAuE;QACvE,qDAAqD;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAC,KAAK,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,wCAAwC,EAAC,EAAC,CAAC,CAAA;IAChH,CAAC;IAED,qFAAqF;IACrF,YAAY,CAAC,kBAAkB,CAAC,CAAA;AAClC,CAAC","sourcesContent":["import {FatalErrorType} from '../../public/node/error.js'\nimport {jsonErrorOutputSchema} from '../../public/node/error/schema.js'\nimport {errorToJson} from '../../public/node/error/serialization.js'\nimport {outputResult} from '../../public/node/output.js'\n\n/**\n * Writes the public JSON representation of a fatal error to stdout.\n *\n * The allow-list mirrors the meaningful content of the regular fatal-error renderer.\n * Arbitrary error properties remain private and are never copied to stdout.\n *\n * @param error - Fatal error to serialize.\n */\nexport function renderFatalErrorAsJson(error: unknown): void {\n let serializedDocument: string\n try {\n if (typeof error === 'object' && error !== null && 'type' in error && error.type === FatalErrorType.AbortSilent)\n return\n const document = {error: errorToJson(error)}\n serializedDocument = JSON.stringify(jsonErrorOutputSchema.validate(document))\n // Serialization must not replace the JSON contract with a text banner.\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n serializedDocument = JSON.stringify({error: {type: 'bug', message: 'Failed to serialize the error as JSON.'}})\n }\n\n // Keep write failures separate: retrying after a partial write could corrupt stdout.\n outputResult(serializedDocument)\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export interface ConcurrentOutputContext {
2
+ outputPrefix?: string;
3
+ /** Controls ANSI stripping for terminal output. JSON diagnostics are always unstyled. */
4
+ stripAnsi?: boolean;
5
+ }
6
+ export declare function useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T;
7
+ /** Returns the source and styling context for the current output write. */
8
+ export declare function getConcurrentOutputContext(): ConcurrentOutputContext | undefined;
@@ -0,0 +1,10 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ const outputContextStore = new AsyncLocalStorage();
3
+ export function useConcurrentOutputContext(context, callback) {
4
+ return outputContextStore.run(context, callback);
5
+ }
6
+ /** Returns the source and styling context for the current output write. */
7
+ export function getConcurrentOutputContext() {
8
+ return outputContextStore.getStore();
9
+ }
10
+ //# sourceMappingURL=output-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-context.js","sourceRoot":"","sources":["../../../src/private/node/output-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAA;AAQlD,MAAM,kBAAkB,GAAG,IAAI,iBAAiB,EAA2B,CAAA;AAE3E,MAAM,UAAU,0BAA0B,CAAI,OAAgC,EAAE,QAAiB;IAC/F,OAAO,kBAAkB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AAClD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,0BAA0B;IACxC,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAA;AACtC,CAAC","sourcesContent":["import {AsyncLocalStorage} from 'node:async_hooks'\n\nexport interface ConcurrentOutputContext {\n outputPrefix?: string\n /** Controls ANSI stripping for terminal output. JSON diagnostics are always unstyled. */\n stripAnsi?: boolean\n}\n\nconst outputContextStore = new AsyncLocalStorage<ConcurrentOutputContext>()\n\nexport function useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T {\n return outputContextStore.run(context, callback)\n}\n\n/** Returns the source and styling context for the current output write. */\nexport function getConcurrentOutputContext(): ConcurrentOutputContext | undefined {\n return outputContextStore.getStore()\n}\n"]}
@@ -39,14 +39,14 @@ describe('logging during an Ink task', () => {
39
39
  });
40
40
  try {
41
41
  await vi.waitFor(() => expect(writes.join('')).toContain('Preparing the result'));
42
- expect(writes.join('')).toContain('▀');
42
+ expect(unstyled(writes.join(''))).toContain('S>');
43
43
  const beforeLog = writes.length;
44
44
  log('Prepared an item');
45
- // Clear both UI lines and their trailing newline before writing the log.
45
+ // Clear the UI line and its trailing newline before writing the log.
46
46
  const logWrites = writes.slice(beforeLog);
47
47
  const messageIndex = logWrites.findIndex((write) => write.includes('Prepared an item'));
48
48
  expect(messageIndex).toBeGreaterThan(0);
49
- expect(logWrites[messageIndex - 1]).toBe(ansiEscapes.eraseLines(3));
49
+ expect(logWrites[messageIndex - 1]).toBe(ansiEscapes.eraseLines(2));
50
50
  expect(unstyled(logWrites[messageIndex])).toBe('Prepared an item\n');
51
51
  expect(logWrites[messageIndex + 1]).toContain('Preparing the result');
52
52
  outputResult('{"items":1}');
@@ -56,7 +56,7 @@ describe('logging during an Ink task', () => {
56
56
  finishTask();
57
57
  await instance.waitUntilExit();
58
58
  const cleanup = writes.slice(afterLog).join('');
59
- expect(cleanup).toContain(ansiEscapes.eraseLines(3));
59
+ expect(cleanup).toContain(ansiEscapes.eraseLines(2));
60
60
  expect(unstyled(cleanup).trim()).toBe('');
61
61
  }
62
62
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../../src/private/node/output.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {InkLifecycleRoot} from './ui.js'\nimport {SingleTask} from './ui/components/SingleTask.js'\nimport {outputInfo, outputWarn, outputResult, TokenizedString, unstyled} from '../../public/node/output.js'\nimport React from 'react'\nimport {render} from 'ink'\nimport ansiEscapes from 'ansi-escapes'\nimport {describe, expect, test, vi} from 'vitest'\nimport {PassThrough} from 'stream'\n// Vitest's console omits the constructor used by Ink's console patch.\n// eslint-disable-next-line n/prefer-global/console\nimport {Console} from 'console'\n\n// Ink detects CI when imported; exercise terminal rendering on CI runners too.\nvi.hoisted(() => {\n vi.stubEnv('CI', 'false')\n vi.stubEnv('CONTINUOUS_INTEGRATION', 'false')\n})\nvi.mock('../../public/node/context/local.js', async (importOriginal) => ({\n ...(await importOriginal<typeof import('../../public/node/context/local.js')>()),\n isUnitTest: () => false,\n}))\n\ndescribe('logging during an Ink task', () => {\n test.each([outputInfo, outputWarn])('clears and redraws the task around %o', async (log) => {\n vi.stubGlobal('console', {...console, Console})\n const writes: string[] = []\n const terminal = Object.assign(new PassThrough(), {isTTY: true, columns: 80, rows: 24})\n terminal.on('data', (data: Buffer) => writes.push(data.toString()))\n let finishTask!: () => void\n const taskResult = new Promise<void>((resolve) => {\n finishTask = resolve\n })\n const stdoutWrite = vi.spyOn(process.stdout, 'write').mockReturnValue(true)\n const stderrWrite = vi.spyOn(process.stderr, 'write').mockReturnValue(true)\n const instance = render(\n <InkLifecycleRoot>\n <SingleTask title={new TokenizedString('Preparing the result')} task={() => taskResult} />\n </InkLifecycleRoot>,\n {\n stdout: terminal as unknown as NodeJS.WriteStream,\n stderr: terminal as unknown as NodeJS.WriteStream,\n patchConsole: true,\n exitOnCtrlC: false,\n },\n )\n\n try {\n await vi.waitFor(() => expect(writes.join('')).toContain('Preparing the result'))\n expect(writes.join('')).toContain('▀')\n const beforeLog = writes.length\n\n log('Prepared an item')\n\n // Clear both UI lines and their trailing newline before writing the log.\n const logWrites = writes.slice(beforeLog)\n const messageIndex = logWrites.findIndex((write) => write.includes('Prepared an item'))\n expect(messageIndex).toBeGreaterThan(0)\n expect(logWrites[messageIndex - 1]).toBe(ansiEscapes.eraseLines(3))\n expect(unstyled(logWrites[messageIndex]!)).toBe('Prepared an item\\n')\n expect(logWrites[messageIndex + 1]).toContain('Preparing the result')\n\n outputResult('{\"items\":1}')\n expect(stdoutWrite).toHaveBeenCalledWith('{\"items\":1}\\n')\n expect(stderrWrite).not.toHaveBeenCalled()\n\n const afterLog = writes.length\n finishTask()\n await instance.waitUntilExit()\n\n const cleanup = writes.slice(afterLog).join('')\n expect(cleanup).toContain(ansiEscapes.eraseLines(3))\n expect(unstyled(cleanup).trim()).toBe('')\n } finally {\n finishTask()\n instance.unmount()\n instance.cleanup()\n stdoutWrite.mockRestore()\n stderrWrite.mockRestore()\n vi.unstubAllGlobals()\n vi.unstubAllEnvs()\n terminal.destroy()\n }\n })\n})\n"]}
1
+ {"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../../src/private/node/output.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {InkLifecycleRoot} from './ui.js'\nimport {SingleTask} from './ui/components/SingleTask.js'\nimport {outputInfo, outputWarn, outputResult, TokenizedString, unstyled} from '../../public/node/output.js'\nimport React from 'react'\nimport {render} from 'ink'\nimport ansiEscapes from 'ansi-escapes'\nimport {describe, expect, test, vi} from 'vitest'\nimport {PassThrough} from 'stream'\n// Vitest's console omits the constructor used by Ink's console patch.\n// eslint-disable-next-line n/prefer-global/console\nimport {Console} from 'console'\n\n// Ink detects CI when imported; exercise terminal rendering on CI runners too.\nvi.hoisted(() => {\n vi.stubEnv('CI', 'false')\n vi.stubEnv('CONTINUOUS_INTEGRATION', 'false')\n})\nvi.mock('../../public/node/context/local.js', async (importOriginal) => ({\n ...(await importOriginal<typeof import('../../public/node/context/local.js')>()),\n isUnitTest: () => false,\n}))\n\ndescribe('logging during an Ink task', () => {\n test.each([outputInfo, outputWarn])('clears and redraws the task around %o', async (log) => {\n vi.stubGlobal('console', {...console, Console})\n const writes: string[] = []\n const terminal = Object.assign(new PassThrough(), {isTTY: true, columns: 80, rows: 24})\n terminal.on('data', (data: Buffer) => writes.push(data.toString()))\n let finishTask!: () => void\n const taskResult = new Promise<void>((resolve) => {\n finishTask = resolve\n })\n const stdoutWrite = vi.spyOn(process.stdout, 'write').mockReturnValue(true)\n const stderrWrite = vi.spyOn(process.stderr, 'write').mockReturnValue(true)\n const instance = render(\n <InkLifecycleRoot>\n <SingleTask title={new TokenizedString('Preparing the result')} task={() => taskResult} />\n </InkLifecycleRoot>,\n {\n stdout: terminal as unknown as NodeJS.WriteStream,\n stderr: terminal as unknown as NodeJS.WriteStream,\n patchConsole: true,\n exitOnCtrlC: false,\n },\n )\n\n try {\n await vi.waitFor(() => expect(writes.join('')).toContain('Preparing the result'))\n expect(unstyled(writes.join(''))).toContain('S>')\n const beforeLog = writes.length\n\n log('Prepared an item')\n\n // Clear the UI line and its trailing newline before writing the log.\n const logWrites = writes.slice(beforeLog)\n const messageIndex = logWrites.findIndex((write) => write.includes('Prepared an item'))\n expect(messageIndex).toBeGreaterThan(0)\n expect(logWrites[messageIndex - 1]).toBe(ansiEscapes.eraseLines(2))\n expect(unstyled(logWrites[messageIndex]!)).toBe('Prepared an item\\n')\n expect(logWrites[messageIndex + 1]).toContain('Preparing the result')\n\n outputResult('{\"items\":1}')\n expect(stdoutWrite).toHaveBeenCalledWith('{\"items\":1}\\n')\n expect(stderrWrite).not.toHaveBeenCalled()\n\n const afterLog = writes.length\n finishTask()\n await instance.waitUntilExit()\n\n const cleanup = writes.slice(afterLog).join('')\n expect(cleanup).toContain(ansiEscapes.eraseLines(2))\n expect(unstyled(cleanup).trim()).toBe('')\n } finally {\n finishTask()\n instance.unmount()\n instance.cleanup()\n stdoutWrite.mockRestore()\n stderrWrite.mockRestore()\n vi.unstubAllGlobals()\n vi.unstubAllEnvs()\n terminal.destroy()\n }\n })\n})\n"]}
@@ -0,0 +1,50 @@
1
+ interface AutomationTokenVariablesProblem {
2
+ message: string;
3
+ tryMessage: string;
4
+ }
5
+ /**
6
+ * Returns the name of the automation token variable the CLI authenticates with: the first one that is set, in
7
+ * the order SHOPIFY_SERVICE_ACCOUNT_TOKEN, SHOPIFY_APP_AUTOMATION_TOKEN, SHOPIFY_CLI_PARTNERS_TOKEN.
8
+ *
9
+ * A variable set to an empty string still counts as set, so `automationTokenVariablesProblem` can report it.
10
+ *
11
+ * @param env - Environment variables to read.
12
+ * @returns The variable name, or undefined when none of them is set.
13
+ */
14
+ export declare function automationTokenVariable(env?: NodeJS.ProcessEnv): string | undefined;
15
+ /**
16
+ * Returns the `env_auth_method` analytics value for the automation token variable the CLI authenticates with:
17
+ * `service_account_token` for SHOPIFY_SERVICE_ACCOUNT_TOKEN, and `partners_token` for SHOPIFY_APP_AUTOMATION_TOKEN and
18
+ * SHOPIFY_CLI_PARTNERS_TOKEN, which existing dashboards already expect.
19
+ *
20
+ * The value tells which variable held the token, not which kind of token it is: the CLI can't tell tokens apart, and
21
+ * any of them works in any of the variables. It shows how much usage has moved to SHOPIFY_SERVICE_ACCOUNT_TOKEN.
22
+ *
23
+ * @param env - Environment variables to read.
24
+ * @returns The auth method to report.
25
+ */
26
+ export declare function automationTokenAuthMethod(env?: NodeJS.ProcessEnv): 'service_account_token' | 'partners_token';
27
+ /**
28
+ * Returns the deprecated automation token variable the CLI authenticates with: SHOPIFY_APP_AUTOMATION_TOKEN or
29
+ * SHOPIFY_CLI_PARTNERS_TOKEN. Both are deprecated in favor of SHOPIFY_SERVICE_ACCOUNT_TOKEN, which takes the same
30
+ * tokens.
31
+ *
32
+ * Returns undefined when the variables can't be used, since the CLI reports that problem instead.
33
+ *
34
+ * @param env - Environment variables to read.
35
+ * @returns The deprecated variable in use, or undefined.
36
+ */
37
+ export declare function deprecatedAutomationTokenVariable(env?: NodeJS.ProcessEnv): string | undefined;
38
+ /**
39
+ * Explains why the automation token variables can't be used, so a misconfigured environment fails instead of
40
+ * falling back to the logged-in user.
41
+ *
42
+ * - SHOPIFY_SERVICE_ACCOUNT_TOKEN can't be set together with SHOPIFY_APP_AUTOMATION_TOKEN or
43
+ * SHOPIFY_CLI_PARTNERS_TOKEN.
44
+ * - The selected variable can't be empty.
45
+ *
46
+ * @param env - Environment variables to check.
47
+ * @returns The problem to report, or undefined when the variables can be used.
48
+ */
49
+ export declare function automationTokenVariablesProblem(env?: NodeJS.ProcessEnv): AutomationTokenVariablesProblem | undefined;
50
+ export {};
@@ -0,0 +1,77 @@
1
+ import { environmentVariables } from '../constants.js';
2
+ const SERVICE_ACCOUNT_TOKEN = environmentVariables.serviceAccountToken;
3
+ const APP_TOKEN = environmentVariables.appAutomationToken;
4
+ const PARTNERS_TOKEN = environmentVariables.partnersToken;
5
+ /**
6
+ * Returns the name of the automation token variable the CLI authenticates with: the first one that is set, in
7
+ * the order SHOPIFY_SERVICE_ACCOUNT_TOKEN, SHOPIFY_APP_AUTOMATION_TOKEN, SHOPIFY_CLI_PARTNERS_TOKEN.
8
+ *
9
+ * A variable set to an empty string still counts as set, so `automationTokenVariablesProblem` can report it.
10
+ *
11
+ * @param env - Environment variables to read.
12
+ * @returns The variable name, or undefined when none of them is set.
13
+ */
14
+ export function automationTokenVariable(env = process.env) {
15
+ return [SERVICE_ACCOUNT_TOKEN, APP_TOKEN, PARTNERS_TOKEN].find((name) => env[name] !== undefined);
16
+ }
17
+ /**
18
+ * Returns the `env_auth_method` analytics value for the automation token variable the CLI authenticates with:
19
+ * `service_account_token` for SHOPIFY_SERVICE_ACCOUNT_TOKEN, and `partners_token` for SHOPIFY_APP_AUTOMATION_TOKEN and
20
+ * SHOPIFY_CLI_PARTNERS_TOKEN, which existing dashboards already expect.
21
+ *
22
+ * The value tells which variable held the token, not which kind of token it is: the CLI can't tell tokens apart, and
23
+ * any of them works in any of the variables. It shows how much usage has moved to SHOPIFY_SERVICE_ACCOUNT_TOKEN.
24
+ *
25
+ * @param env - Environment variables to read.
26
+ * @returns The auth method to report.
27
+ */
28
+ export function automationTokenAuthMethod(env = process.env) {
29
+ return automationTokenVariable(env) === SERVICE_ACCOUNT_TOKEN ? 'service_account_token' : 'partners_token';
30
+ }
31
+ /**
32
+ * Returns the deprecated automation token variable the CLI authenticates with: SHOPIFY_APP_AUTOMATION_TOKEN or
33
+ * SHOPIFY_CLI_PARTNERS_TOKEN. Both are deprecated in favor of SHOPIFY_SERVICE_ACCOUNT_TOKEN, which takes the same
34
+ * tokens.
35
+ *
36
+ * Returns undefined when the variables can't be used, since the CLI reports that problem instead.
37
+ *
38
+ * @param env - Environment variables to read.
39
+ * @returns The deprecated variable in use, or undefined.
40
+ */
41
+ export function deprecatedAutomationTokenVariable(env = process.env) {
42
+ if (automationTokenVariablesProblem(env))
43
+ return undefined;
44
+ const variable = automationTokenVariable(env);
45
+ return variable === APP_TOKEN || variable === PARTNERS_TOKEN ? variable : undefined;
46
+ }
47
+ /**
48
+ * Explains why the automation token variables can't be used, so a misconfigured environment fails instead of
49
+ * falling back to the logged-in user.
50
+ *
51
+ * - SHOPIFY_SERVICE_ACCOUNT_TOKEN can't be set together with SHOPIFY_APP_AUTOMATION_TOKEN or
52
+ * SHOPIFY_CLI_PARTNERS_TOKEN.
53
+ * - The selected variable can't be empty.
54
+ *
55
+ * @param env - Environment variables to check.
56
+ * @returns The problem to report, or undefined when the variables can be used.
57
+ */
58
+ export function automationTokenVariablesProblem(env = process.env) {
59
+ if (env[SERVICE_ACCOUNT_TOKEN] !== undefined) {
60
+ const conflictingVariables = [APP_TOKEN, PARTNERS_TOKEN].filter((name) => env[name] !== undefined);
61
+ if (conflictingVariables.length > 0) {
62
+ return {
63
+ message: `${SERVICE_ACCOUNT_TOKEN} can't be set together with ${conflictingVariables.join(' or ')}.`,
64
+ tryMessage: `Unset ${conflictingVariables.join(' and ')}, or unset ${SERVICE_ACCOUNT_TOKEN}.`,
65
+ };
66
+ }
67
+ }
68
+ const variable = automationTokenVariable(env);
69
+ if (variable && env[variable] === '') {
70
+ return {
71
+ message: `${variable} is set but empty.`,
72
+ tryMessage: 'Set it to an automation token, or unset it to log in with your Shopify account.',
73
+ };
74
+ }
75
+ return undefined;
76
+ }
77
+ //# sourceMappingURL=automation-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation-token.js","sourceRoot":"","sources":["../../../../src/private/node/session/automation-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,iBAAiB,CAAA;AAEpD,MAAM,qBAAqB,GAAG,oBAAoB,CAAC,mBAAmB,CAAA;AACtE,MAAM,SAAS,GAAG,oBAAoB,CAAC,kBAAkB,CAAA;AACzD,MAAM,cAAc,GAAG,oBAAoB,CAAC,aAAa,CAAA;AAOzD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC1E,OAAO,CAAC,qBAAqB,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAA;AACnG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,uBAAuB,CAAC,GAAG,CAAC,KAAK,qBAAqB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,CAAA;AAC5G,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iCAAiC,CAAC,MAAyB,OAAO,CAAC,GAAG;IACpF,IAAI,+BAA+B,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IAC1D,MAAM,QAAQ,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAA;IAC7C,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;AACrF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,+BAA+B,CAC7C,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,GAAG,CAAC,qBAAqB,CAAC,KAAK,SAAS,EAAE,CAAC;QAC7C,MAAM,oBAAoB,GAAG,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAA;QAClG,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,OAAO;gBACL,OAAO,EAAE,GAAG,qBAAqB,+BAA+B,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG;gBACpG,UAAU,EAAE,SAAS,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,qBAAqB,GAAG;aAC9F,CAAA;QACH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAA;IAC7C,IAAI,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;QACrC,OAAO;YACL,OAAO,EAAE,GAAG,QAAQ,oBAAoB;YACxC,UAAU,EAAE,iFAAiF;SAC9F,CAAA;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC","sourcesContent":["import {environmentVariables} from '../constants.js'\n\nconst SERVICE_ACCOUNT_TOKEN = environmentVariables.serviceAccountToken\nconst APP_TOKEN = environmentVariables.appAutomationToken\nconst PARTNERS_TOKEN = environmentVariables.partnersToken\n\ninterface AutomationTokenVariablesProblem {\n message: string\n tryMessage: string\n}\n\n/**\n * Returns the name of the automation token variable the CLI authenticates with: the first one that is set, in\n * the order SHOPIFY_SERVICE_ACCOUNT_TOKEN, SHOPIFY_APP_AUTOMATION_TOKEN, SHOPIFY_CLI_PARTNERS_TOKEN.\n *\n * A variable set to an empty string still counts as set, so `automationTokenVariablesProblem` can report it.\n *\n * @param env - Environment variables to read.\n * @returns The variable name, or undefined when none of them is set.\n */\nexport function automationTokenVariable(env: NodeJS.ProcessEnv = process.env): string | undefined {\n return [SERVICE_ACCOUNT_TOKEN, APP_TOKEN, PARTNERS_TOKEN].find((name) => env[name] !== undefined)\n}\n\n/**\n * Returns the `env_auth_method` analytics value for the automation token variable the CLI authenticates with:\n * `service_account_token` for SHOPIFY_SERVICE_ACCOUNT_TOKEN, and `partners_token` for SHOPIFY_APP_AUTOMATION_TOKEN and\n * SHOPIFY_CLI_PARTNERS_TOKEN, which existing dashboards already expect.\n *\n * The value tells which variable held the token, not which kind of token it is: the CLI can't tell tokens apart, and\n * any of them works in any of the variables. It shows how much usage has moved to SHOPIFY_SERVICE_ACCOUNT_TOKEN.\n *\n * @param env - Environment variables to read.\n * @returns The auth method to report.\n */\nexport function automationTokenAuthMethod(\n env: NodeJS.ProcessEnv = process.env,\n): 'service_account_token' | 'partners_token' {\n return automationTokenVariable(env) === SERVICE_ACCOUNT_TOKEN ? 'service_account_token' : 'partners_token'\n}\n\n/**\n * Returns the deprecated automation token variable the CLI authenticates with: SHOPIFY_APP_AUTOMATION_TOKEN or\n * SHOPIFY_CLI_PARTNERS_TOKEN. Both are deprecated in favor of SHOPIFY_SERVICE_ACCOUNT_TOKEN, which takes the same\n * tokens.\n *\n * Returns undefined when the variables can't be used, since the CLI reports that problem instead.\n *\n * @param env - Environment variables to read.\n * @returns The deprecated variable in use, or undefined.\n */\nexport function deprecatedAutomationTokenVariable(env: NodeJS.ProcessEnv = process.env): string | undefined {\n if (automationTokenVariablesProblem(env)) return undefined\n const variable = automationTokenVariable(env)\n return variable === APP_TOKEN || variable === PARTNERS_TOKEN ? variable : undefined\n}\n\n/**\n * Explains why the automation token variables can't be used, so a misconfigured environment fails instead of\n * falling back to the logged-in user.\n *\n * - SHOPIFY_SERVICE_ACCOUNT_TOKEN can't be set together with SHOPIFY_APP_AUTOMATION_TOKEN or\n * SHOPIFY_CLI_PARTNERS_TOKEN.\n * - The selected variable can't be empty.\n *\n * @param env - Environment variables to check.\n * @returns The problem to report, or undefined when the variables can be used.\n */\nexport function automationTokenVariablesProblem(\n env: NodeJS.ProcessEnv = process.env,\n): AutomationTokenVariablesProblem | undefined {\n if (env[SERVICE_ACCOUNT_TOKEN] !== undefined) {\n const conflictingVariables = [APP_TOKEN, PARTNERS_TOKEN].filter((name) => env[name] !== undefined)\n if (conflictingVariables.length > 0) {\n return {\n message: `${SERVICE_ACCOUNT_TOKEN} can't be set together with ${conflictingVariables.join(' or ')}.`,\n tryMessage: `Unset ${conflictingVariables.join(' and ')}, or unset ${SERVICE_ACCOUNT_TOKEN}.`,\n }\n }\n }\n\n const variable = automationTokenVariable(env)\n if (variable && env[variable] === '') {\n return {\n message: `${variable} is set but empty.`,\n tryMessage: 'Set it to an automation token, or unset it to log in with your Shopify account.',\n }\n }\n return undefined\n}\n"]}
@@ -4,6 +4,9 @@ import { Result } from '../../../public/node/result.js';
4
4
  export declare class InvalidGrantError extends Error {
5
5
  }
6
6
  export declare class InvalidRequestError extends Error {
7
+ /** Identity's `error_description`, when it sent one. Says what about the request was invalid. */
8
+ readonly description: string;
9
+ constructor(description?: string);
7
10
  }
8
11
  export interface ExchangeScopes {
9
12
  admin: string[];
@@ -45,9 +48,10 @@ export declare function exchangeAppAutomationTokenForAppManagementAccessToken(to
45
48
  /**
46
49
  * Given a custom app automation token passed as ENV variable, request a valid Business Platform API token.
47
50
  * @param token - The app automation token passed as ENV variable `SHOPIFY_APP_AUTOMATION_TOKEN`
51
+ * @param scopes - The scopes to request. An empty list makes Identity issue every Business Platform scope the token holds.
48
52
  * @returns An instance with the application access tokens.
49
53
  */
50
- export declare function exchangeAppAutomationTokenForBusinessPlatformAccessToken(token: string): Promise<{
54
+ export declare function exchangeAppAutomationTokenForBusinessPlatformAccessToken(token: string, scopes?: string[]): Promise<{
51
55
  accessToken: string;
52
56
  userId: string;
53
57
  }>;