@shopify/cli-kit 4.9.5 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) 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 +2 -1
  30. package/dist/private/node/session/exchange.js +5 -3
  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/public/common/version.d.ts +1 -1
  54. package/dist/public/common/version.js +1 -1
  55. package/dist/public/common/version.js.map +1 -1
  56. package/dist/public/node/api/admin.js +13 -0
  57. package/dist/public/node/api/admin.js.map +1 -1
  58. package/dist/public/node/api/graphql.js +38 -7
  59. package/dist/public/node/api/graphql.js.map +1 -1
  60. package/dist/public/node/archiver.js +13 -6
  61. package/dist/public/node/archiver.js.map +1 -1
  62. package/dist/public/node/base-command.d.ts +6 -0
  63. package/dist/public/node/base-command.js +97 -16
  64. package/dist/public/node/base-command.js.map +1 -1
  65. package/dist/public/node/dev-instance.d.ts +138 -0
  66. package/dist/public/node/dev-instance.js +365 -0
  67. package/dist/public/node/dev-instance.js.map +1 -0
  68. package/dist/public/node/environment.d.ts +6 -3
  69. package/dist/public/node/environment.js +11 -4
  70. package/dist/public/node/environment.js.map +1 -1
  71. package/dist/public/node/error/index.js +2 -1
  72. package/dist/public/node/error/index.js.map +1 -1
  73. package/dist/public/node/error/schema.d.ts +24 -24
  74. package/dist/public/node/error/serialization.d.ts +8 -0
  75. package/dist/public/node/error/serialization.js +103 -0
  76. package/dist/public/node/error/serialization.js.map +1 -0
  77. package/dist/public/node/graphiql/server.js +18 -2
  78. package/dist/public/node/graphiql/server.js.map +1 -1
  79. package/dist/public/node/is-global.js +2 -1
  80. package/dist/public/node/is-global.js.map +1 -1
  81. package/dist/public/node/notifications-system.d.ts +6 -6
  82. package/dist/public/node/path.d.ts +19 -3
  83. package/dist/public/node/path.js +21 -3
  84. package/dist/public/node/path.js.map +1 -1
  85. package/dist/public/node/session.d.ts +36 -2
  86. package/dist/public/node/session.js +48 -4
  87. package/dist/public/node/session.js.map +1 -1
  88. package/dist/public/node/system.d.ts +4 -0
  89. package/dist/public/node/system.js +39 -9
  90. package/dist/public/node/system.js.map +1 -1
  91. package/dist/public/node/themes/api.d.ts +9 -0
  92. package/dist/public/node/themes/api.js +50 -22
  93. package/dist/public/node/themes/api.js.map +1 -1
  94. package/dist/public/node/themes/theme-manager.d.ts +8 -1
  95. package/dist/public/node/themes/theme-manager.js +1 -1
  96. package/dist/public/node/themes/theme-manager.js.map +1 -1
  97. package/dist/public/node/tree-kill.js +12 -2
  98. package/dist/public/node/tree-kill.js.map +1 -1
  99. package/dist/public/node/ui/components.d.ts +1 -0
  100. package/dist/public/node/ui/components.js +1 -0
  101. package/dist/public/node/ui/components.js.map +1 -1
  102. package/dist/public/node/ui.d.ts +24 -4
  103. package/dist/public/node/ui.js +41 -18
  104. package/dist/public/node/ui.js.map +1 -1
  105. package/dist/public/node/upgrade/output.d.ts +17 -0
  106. package/dist/public/node/upgrade/output.js +51 -0
  107. package/dist/public/node/upgrade/output.js.map +1 -0
  108. package/dist/public/node/upgrade/result.d.ts +8 -0
  109. package/dist/public/node/upgrade/result.js +21 -0
  110. package/dist/public/node/upgrade/result.js.map +1 -0
  111. package/dist/public/node/upgrade/types.d.ts +61 -0
  112. package/dist/public/node/upgrade/types.js +46 -0
  113. package/dist/public/node/upgrade/types.js.map +1 -0
  114. package/dist/public/node/upgrade.d.ts +8 -0
  115. package/dist/public/node/upgrade.js +57 -22
  116. package/dist/public/node/upgrade.js.map +1 -1
  117. package/dist/tsconfig.tsbuildinfo +1 -1
  118. package/package.json +3 -3
  119. package/dist/private/node/ui/components/TextAnimation.d.ts +0 -10
  120. package/dist/private/node/ui/components/TextAnimation.js +0 -56
  121. package/dist/private/node/ui/components/TextAnimation.js.map +0 -1
  122. package/dist/private/node/ui/components/TextAnimation.test.d.ts +0 -1
  123. package/dist/private/node/ui/components/TextAnimation.test.js +0 -73
  124. package/dist/private/node/ui/components/TextAnimation.test.js.map +0 -1
@@ -12,7 +12,7 @@ const typeToLogLevel = {
12
12
  };
13
13
  export function alert(options) {
14
14
  const { type, headline, body, nextSteps, reference, link, customSections, orderedNextSteps = false, renderOptions, } = options;
15
- if ((type === 'info' || type === 'warning') && commandEventOutputMode() === 'json') {
15
+ if ((type === 'info' || type === 'warning' || type === 'success') && commandEventOutputMode() === 'json') {
16
16
  const message = alertMessage(options);
17
17
  if (type === 'warning')
18
18
  outputWarn(message);
@@ -1 +1 @@
1
- {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Alert, AlertProps} from './components/Alert.js'\nimport {tokenItemToJsonString} from './components/token-item.js'\nimport {renderOnce} from '../ui.js'\nimport {commandEventOutputMode} from '../command-event-context.js'\nimport {LogLevel, outputInfo, outputWarn} from '../../../public/node/output.js'\nimport React from 'react'\n\nimport {RenderOptions} from 'ink'\n\nconst typeToLogLevel: Record<AlertProps['type'], LogLevel> = {\n info: 'info',\n warning: 'warn',\n success: 'info',\n error: 'error',\n}\n\nexport interface AlertOptions extends AlertProps {\n renderOptions?: RenderOptions\n}\n\nexport function alert(options: AlertOptions) {\n const {\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n renderOptions,\n } = options\n\n if ((type === 'info' || type === 'warning') && commandEventOutputMode() === 'json') {\n const message = alertMessage(options)\n if (type === 'warning') outputWarn(message)\n else outputInfo(message)\n return message\n }\n\n return renderOnce(\n <Alert\n type={type}\n headline={headline}\n body={body}\n nextSteps={nextSteps}\n reference={reference}\n link={link}\n orderedNextSteps={orderedNextSteps}\n customSections={customSections}\n />,\n {logLevel: typeToLogLevel[type], renderOptions},\n )\n}\n\nfunction alertMessage({headline, body, nextSteps, reference, link, customSections}: AlertProps): string {\n const sections = [\n headline ? tokenItemToJsonString(headline) : undefined,\n body ? tokenItemToJsonString(body) : undefined,\n nextSteps?.length ? `Next steps:\\n${nextSteps.map(tokenItemToJsonString).join('\\n')}` : undefined,\n reference?.length ? `Reference:\\n${reference.map(tokenItemToJsonString).join('\\n')}` : undefined,\n link ? tokenItemToJsonString({link}) : undefined,\n ...(customSections ?? []).map((section) => {\n const content =\n typeof section.body === 'object' && 'tabularData' in section.body\n ? section.body.tabularData.map((row) => row.map(tokenItemToJsonString).join('\\t')).join('\\n')\n : tokenItemToJsonString(section.body)\n return section.title ? `${section.title}:\\n${content}` : content\n }),\n ]\n return sections.filter((section): section is string => section !== undefined).join('\\n\\n')\n}\n"]}
1
+ {"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Alert, AlertProps} from './components/Alert.js'\nimport {tokenItemToJsonString} from './components/token-item.js'\nimport {renderOnce} from '../ui.js'\nimport {commandEventOutputMode} from '../command-event-context.js'\nimport {LogLevel, outputInfo, outputWarn} from '../../../public/node/output.js'\nimport React from 'react'\n\nimport {RenderOptions} from 'ink'\n\nconst typeToLogLevel: Record<AlertProps['type'], LogLevel> = {\n info: 'info',\n warning: 'warn',\n success: 'info',\n error: 'error',\n}\n\nexport interface AlertOptions extends AlertProps {\n renderOptions?: RenderOptions\n}\n\nexport function alert(options: AlertOptions) {\n const {\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n renderOptions,\n } = options\n\n if ((type === 'info' || type === 'warning' || type === 'success') && commandEventOutputMode() === 'json') {\n const message = alertMessage(options)\n if (type === 'warning') outputWarn(message)\n else outputInfo(message)\n return message\n }\n\n return renderOnce(\n <Alert\n type={type}\n headline={headline}\n body={body}\n nextSteps={nextSteps}\n reference={reference}\n link={link}\n orderedNextSteps={orderedNextSteps}\n customSections={customSections}\n />,\n {logLevel: typeToLogLevel[type], renderOptions},\n )\n}\n\nfunction alertMessage({headline, body, nextSteps, reference, link, customSections}: AlertProps): string {\n const sections = [\n headline ? tokenItemToJsonString(headline) : undefined,\n body ? tokenItemToJsonString(body) : undefined,\n nextSteps?.length ? `Next steps:\\n${nextSteps.map(tokenItemToJsonString).join('\\n')}` : undefined,\n reference?.length ? `Reference:\\n${reference.map(tokenItemToJsonString).join('\\n')}` : undefined,\n link ? tokenItemToJsonString({link}) : undefined,\n ...(customSections ?? []).map((section) => {\n const content =\n typeof section.body === 'object' && 'tabularData' in section.body\n ? section.body.tabularData.map((row) => row.map(tokenItemToJsonString).join('\\t')).join('\\n')\n : tokenItemToJsonString(section.body)\n return section.title ? `${section.title}:\\n${content}` : content\n }),\n ]\n return sections.filter((section): section is string => section !== undefined).join('\\n\\n')\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext } from '../../output-context.js';
1
2
  import { type OutputProcess } from '../../../../public/node/output.js';
2
3
  import { AbortSignal } from '../../../../public/node/abort.js';
3
4
  import { FunctionComponent } from 'react';
@@ -13,12 +14,6 @@ export interface ConcurrentOutputProps {
13
14
  keepRunningAfterProcessesResolve?: boolean;
14
15
  useAlternativeColorPalette?: boolean;
15
16
  }
16
- interface ConcurrentOutputContext {
17
- outputPrefix?: string;
18
- /** Controls ANSI stripping for terminal output. JSON diagnostics are always unstyled. */
19
- stripAnsi?: boolean;
20
- }
21
- declare function useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T;
22
17
  /** Runs finite processes concurrently and routes their output through the shared diagnostic context. */
23
18
  export declare function runConcurrentProcessesForJson({ processes, abortSignal, }: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void>;
24
19
  /**
@@ -55,4 +50,4 @@ export declare function runConcurrentProcessesForJson({ processes, abortSignal,
55
50
  * ```
56
51
  */
57
52
  declare const ConcurrentOutput: FunctionComponent<ConcurrentOutputProps>;
58
- export { ConcurrentOutput, ConcurrentOutputContext, useConcurrentOutputContext };
53
+ export { ConcurrentOutput, ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext };
@@ -1,3 +1,4 @@
1
+ import { getConcurrentOutputContext, useConcurrentOutputContext } from '../../output-context.js';
1
2
  import { outputInfo } from '../../../../public/node/output.js';
2
3
  import { useComplete } from '../../ui.js';
3
4
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
@@ -5,7 +6,6 @@ import { Box, Static, Text } from 'ink';
5
6
  import figures from 'figures';
6
7
  import stripAnsi from 'strip-ansi';
7
8
  import { Writable } from 'stream';
8
- import { AsyncLocalStorage } from 'node:async_hooks';
9
9
  import { StringDecoder } from 'node:string_decoder';
10
10
  function addLeadingZero(number) {
11
11
  if (number < 10) {
@@ -22,10 +22,6 @@ function currentTime() {
22
22
  const seconds = addLeadingZero(currentDateTime.getSeconds());
23
23
  return `${hours}:${minutes}:${seconds}`;
24
24
  }
25
- const outputContextStore = new AsyncLocalStorage();
26
- function useConcurrentOutputContext(context, callback) {
27
- return outputContextStore.run(context, callback);
28
- }
29
25
  /** Runs finite processes concurrently and routes their output through the shared diagnostic context. */
30
26
  export async function runConcurrentProcessesForJson({ processes, abortSignal, }) {
31
27
  await Promise.all(processes.map(async (process) => {
@@ -45,7 +41,7 @@ export async function runConcurrentProcessesForJson({ processes, abortSignal, })
45
41
  next();
46
42
  return;
47
43
  }
48
- const currentPrefix = outputContextStore.getStore()?.outputPrefix ?? process.prefix;
44
+ const currentPrefix = getConcurrentOutputContext()?.outputPrefix ?? process.prefix;
49
45
  if (!hasPendingLine)
50
46
  prefix = currentPrefix;
51
47
  const lines = (pending + decoder.write(chunk)).split(/\r?\n/);
@@ -141,7 +137,7 @@ const ConcurrentOutput = ({ processes, prefixColumnSize, abortSignal, showTimest
141
137
  const writableStream = useCallback((process, prefixes) => {
142
138
  return new Writable({
143
139
  write(chunk, _encoding, next) {
144
- const context = outputContextStore.getStore();
140
+ const context = getConcurrentOutputContext();
145
141
  const prefix = context?.outputPrefix ?? process.prefix;
146
142
  const shouldStripAnsi = context?.stripAnsi ?? true;
147
143
  const log = chunk.toString('utf8').replace(/(\n)$/, '');
@@ -211,5 +207,5 @@ const ConcurrentOutput = ({ processes, prefixColumnSize, abortSignal, showTimest
211
207
  line)))))));
212
208
  }));
213
209
  };
214
- export { ConcurrentOutput, useConcurrentOutputContext };
210
+ export { ConcurrentOutput, getConcurrentOutputContext, useConcurrentOutputContext };
215
211
  //# sourceMappingURL=ConcurrentOutput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {outputInfo, type OutputProcess} from '../../../../public/node/output.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Static, Text, TextProps} from 'ink'\nimport figures from 'figures'\nimport stripAnsi from 'strip-ansi'\n\nimport {Writable} from 'stream'\nimport {AsyncLocalStorage} from 'node:async_hooks'\nimport {StringDecoder} from 'node:string_decoder'\n\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n prefixColumnSize?: number\n abortSignal: AbortSignal\n showTimestamps?: boolean\n /**\n * Keeps terminal UI running after all processes finish. Defaults to false.\n * In JSON mode, false uses finite progress/diagnostic events; true retains streaming terminal UI.\n */\n keepRunningAfterProcessesResolve?: boolean\n useAlternativeColorPalette?: boolean\n}\n\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\n\nfunction currentTime() {\n const currentDateTime = new Date()\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n return `${hours}:${minutes}:${seconds}`\n}\n\ninterface 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\nfunction useConcurrentOutputContext<T>(context: ConcurrentOutputContext, callback: () => T): T {\n return outputContextStore.run(context, callback)\n}\n\n/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */\nexport async function runConcurrentProcessesForJson({\n processes,\n abortSignal,\n}: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void> {\n await Promise.all(\n processes.map(async (process) => {\n const createStream = () => {\n const decoder = new StringDecoder('utf8')\n let pending = ''\n let hasPendingLine = false\n let prefix = process.prefix\n const emitLine = (line: string) => {\n const message = stripAnsi(line)\n if (message.trim().length > 0) outputInfo(`${prefix}: ${message}`)\n }\n const stream = new Writable({\n write(chunk, _encoding, next) {\n if (chunk.length === 0) {\n next()\n return\n }\n const currentPrefix = outputContextStore.getStore()?.outputPrefix ?? process.prefix\n if (!hasPendingLine) prefix = currentPrefix\n const lines = (pending + decoder.write(chunk)).split(/\\r?\\n/)\n pending = lines.pop() ?? ''\n for (const line of lines) {\n emitLine(line)\n prefix = currentPrefix\n }\n hasPendingLine = chunk[chunk.length - 1] !== 10\n next()\n },\n })\n return {\n stream,\n flush: () => {\n emitLine((pending + decoder.end()).replace(/\\r$/, ''))\n pending = ''\n hasPendingLine = false\n },\n }\n }\n const stdout = createStream()\n const stderr = createStream()\n try {\n await process.action(stdout.stream, stderr.stream, abortSignal)\n } finally {\n stdout.flush()\n stderr.flush()\n }\n }),\n )\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n prefixColumnSize,\n abortSignal,\n showTimestamps = true,\n keepRunningAfterProcessesResolve = false,\n useAlternativeColorPalette = false,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const [completionResult, setCompletionResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const concurrentColors: TextProps['color'][] = useMemo(\n () =>\n useAlternativeColorPalette\n ? ['#b994c3', '#e69e19', '#d17a73', 'cyan', 'magenta', 'blue']\n : ['yellow', 'cyan', 'magenta', 'green', 'blue'],\n [useAlternativeColorPalette],\n )\n\n const calculatedPrefixColumnSize = useMemo(() => {\n const maxColumnSize = 25\n\n // If the prefixColumnSize is not provided, we calculate it based on the longest process prefix\n const columnSize =\n prefixColumnSize ??\n processes.reduce((maxPrefixLength, process) => Math.max(maxPrefixLength, process.prefix.length), 0)\n\n // Apply overall limit to the prefix column size\n return Math.min(columnSize, maxColumnSize)\n }, [processes, prefixColumnSize])\n\n const addPrefix = (prefix: string, prefixes: string[]) => {\n const index = prefixes.indexOf(prefix)\n if (index !== -1) {\n return index\n }\n prefixes.push(prefix)\n return prefixes.length - 1\n }\n\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index % concurrentColors.length\n return concurrentColors[colorIndex]\n },\n [concurrentColors],\n )\n\n const writableStream = useCallback(\n (process: OutputProcess, prefixes: string[]) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const context = outputContextStore.getStore()\n const prefix = context?.outputPrefix ?? process.prefix\n const shouldStripAnsi = context?.stripAnsi ?? true\n const log = chunk.toString('utf8').replace(/(\\n)$/, '')\n\n const index = addPrefix(prefix, prefixes)\n\n const lines = shouldStripAnsi ? stripAnsi(log).split(/\\n/) : log.split(/\\n/)\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix,\n lines,\n },\n ])\n next()\n },\n })\n },\n [lineColor],\n )\n\n const formatPrefix = (prefix: string) => {\n // Truncate prefix if needed\n if (prefix.length > calculatedPrefixColumnSize) {\n return prefix.substring(0, calculatedPrefixColumnSize)\n }\n\n return `${' '.repeat(calculatedPrefixColumnSize - prefix.length)}${prefix}`\n }\n\n useEffect(() => {\n const runProcesses = async () => {\n const prefixes: string[] = []\n\n try {\n await Promise.all(\n processes.map(async (process) => {\n const stdout = writableStream(process, prefixes)\n const stderr = writableStream(process, prefixes)\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({})\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error: unknown) {\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({error: error as Error})\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n runProcesses()\n }, [abortSignal, processes, writableStream, keepRunningAfterProcessesResolve])\n\n useEffect(() => {\n if (completionResult !== null) {\n complete(completionResult.error)\n }\n }, [completionResult, complete])\n\n const {lineVertical} = figures\n\n return (\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n <Text color={chunk.color}>{formatPrefix(chunk.prefix)}</Text>\n <Text>\n {' '}\n {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n )\n}\nexport {ConcurrentOutput, ConcurrentOutputContext, useConcurrentOutputContext}\n"]}
1
+ {"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext} from '../../output-context.js'\nimport {outputInfo, type OutputProcess} from '../../../../public/node/output.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Static, Text, TextProps} from 'ink'\nimport figures from 'figures'\nimport stripAnsi from 'strip-ansi'\n\nimport {Writable} from 'stream'\nimport {StringDecoder} from 'node:string_decoder'\n\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n prefixColumnSize?: number\n abortSignal: AbortSignal\n showTimestamps?: boolean\n /**\n * Keeps terminal UI running after all processes finish. Defaults to false.\n * In JSON mode, false uses finite progress/diagnostic events; true retains streaming terminal UI.\n */\n keepRunningAfterProcessesResolve?: boolean\n useAlternativeColorPalette?: boolean\n}\n\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\n\nfunction currentTime() {\n const currentDateTime = new Date()\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n return `${hours}:${minutes}:${seconds}`\n}\n\n/** Runs finite processes concurrently and routes their output through the shared diagnostic context. */\nexport async function runConcurrentProcessesForJson({\n processes,\n abortSignal,\n}: Pick<ConcurrentOutputProps, 'processes' | 'abortSignal'>): Promise<void> {\n await Promise.all(\n processes.map(async (process) => {\n const createStream = () => {\n const decoder = new StringDecoder('utf8')\n let pending = ''\n let hasPendingLine = false\n let prefix = process.prefix\n const emitLine = (line: string) => {\n const message = stripAnsi(line)\n if (message.trim().length > 0) outputInfo(`${prefix}: ${message}`)\n }\n const stream = new Writable({\n write(chunk, _encoding, next) {\n if (chunk.length === 0) {\n next()\n return\n }\n const currentPrefix = getConcurrentOutputContext()?.outputPrefix ?? process.prefix\n if (!hasPendingLine) prefix = currentPrefix\n const lines = (pending + decoder.write(chunk)).split(/\\r?\\n/)\n pending = lines.pop() ?? ''\n for (const line of lines) {\n emitLine(line)\n prefix = currentPrefix\n }\n hasPendingLine = chunk[chunk.length - 1] !== 10\n next()\n },\n })\n return {\n stream,\n flush: () => {\n emitLine((pending + decoder.end()).replace(/\\r$/, ''))\n pending = ''\n hasPendingLine = false\n },\n }\n }\n const stdout = createStream()\n const stderr = createStream()\n try {\n await process.action(stdout.stream, stderr.stream, abortSignal)\n } finally {\n stdout.flush()\n stderr.flush()\n }\n }),\n )\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n prefixColumnSize,\n abortSignal,\n showTimestamps = true,\n keepRunningAfterProcessesResolve = false,\n useAlternativeColorPalette = false,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const [completionResult, setCompletionResult] = useState<{error?: Error} | null>(null)\n const complete = useComplete()\n const concurrentColors: TextProps['color'][] = useMemo(\n () =>\n useAlternativeColorPalette\n ? ['#b994c3', '#e69e19', '#d17a73', 'cyan', 'magenta', 'blue']\n : ['yellow', 'cyan', 'magenta', 'green', 'blue'],\n [useAlternativeColorPalette],\n )\n\n const calculatedPrefixColumnSize = useMemo(() => {\n const maxColumnSize = 25\n\n // If the prefixColumnSize is not provided, we calculate it based on the longest process prefix\n const columnSize =\n prefixColumnSize ??\n processes.reduce((maxPrefixLength, process) => Math.max(maxPrefixLength, process.prefix.length), 0)\n\n // Apply overall limit to the prefix column size\n return Math.min(columnSize, maxColumnSize)\n }, [processes, prefixColumnSize])\n\n const addPrefix = (prefix: string, prefixes: string[]) => {\n const index = prefixes.indexOf(prefix)\n if (index !== -1) {\n return index\n }\n prefixes.push(prefix)\n return prefixes.length - 1\n }\n\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index % concurrentColors.length\n return concurrentColors[colorIndex]\n },\n [concurrentColors],\n )\n\n const writableStream = useCallback(\n (process: OutputProcess, prefixes: string[]) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const context = getConcurrentOutputContext()\n const prefix = context?.outputPrefix ?? process.prefix\n const shouldStripAnsi = context?.stripAnsi ?? true\n const log = chunk.toString('utf8').replace(/(\\n)$/, '')\n\n const index = addPrefix(prefix, prefixes)\n\n const lines = shouldStripAnsi ? stripAnsi(log).split(/\\n/) : log.split(/\\n/)\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix,\n lines,\n },\n ])\n next()\n },\n })\n },\n [lineColor],\n )\n\n const formatPrefix = (prefix: string) => {\n // Truncate prefix if needed\n if (prefix.length > calculatedPrefixColumnSize) {\n return prefix.substring(0, calculatedPrefixColumnSize)\n }\n\n return `${' '.repeat(calculatedPrefixColumnSize - prefix.length)}${prefix}`\n }\n\n useEffect(() => {\n const runProcesses = async () => {\n const prefixes: string[] = []\n\n try {\n await Promise.all(\n processes.map(async (process) => {\n const stdout = writableStream(process, prefixes)\n const stderr = writableStream(process, prefixes)\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({})\n }\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error: unknown) {\n if (!keepRunningAfterProcessesResolve) {\n setCompletionResult({error: error as Error})\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n runProcesses()\n }, [abortSignal, processes, writableStream, keepRunningAfterProcessesResolve])\n\n useEffect(() => {\n if (completionResult !== null) {\n complete(completionResult.error)\n }\n }, [completionResult, complete])\n\n const {lineVertical} = figures\n\n return (\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n <Text color={chunk.color}>{formatPrefix(chunk.prefix)}</Text>\n <Text>\n {' '}\n {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n )\n}\nexport {ConcurrentOutput, ConcurrentOutputContext, getConcurrentOutputContext, useConcurrentOutputContext}\n"]}
@@ -1,28 +1,22 @@
1
- import { TextAnimation } from './TextAnimation.js';
2
- import useLayout from '../hooks/use-layout.js';
1
+ import { LoadingIndicator } from './LoadingIndicator.js';
3
2
  import { shouldDisplayColors } from '../../../../public/node/output.js';
4
3
  import React from 'react';
5
- import { Box, Text, useStdout } from 'ink';
6
- const loadingBarChar = '▀';
7
- const hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁';
4
+ import { Text, useStdout } from 'ink';
8
5
  const LoadingBar = ({ title, noColor, noProgressBar }) => {
9
- const { twoThirds } = useLayout();
10
6
  const { stdout } = useStdout();
11
7
  // On real Node streams, isTTY is only present as an own property when the
12
8
  // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents
13
- // capturing stderr via 2>&1), the animated progress bar can't overwrite
9
+ // capturing stderr via 2>&1), the animated loading indicator can't overwrite
14
10
  // previous frames and would flood the output. Show only the static title
15
11
  // in that case.
16
12
  const isTTY = Boolean(stdout.isTTY);
17
- let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('');
18
- if (noColor ?? !shouldDisplayColors()) {
19
- loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length));
20
- }
21
- return (React.createElement(Box, { flexDirection: "column" },
22
- isTTY && !noProgressBar && React.createElement(TextAnimation, { text: loadingBar, maxWidth: twoThirds }),
23
- React.createElement(Text, null,
13
+ const colorsDisabled = noColor ?? !shouldDisplayColors();
14
+ if (!isTTY || noProgressBar) {
15
+ return React.createElement(Text, null,
24
16
  title,
25
- " ...")));
17
+ " ...");
18
+ }
19
+ return React.createElement(LoadingIndicator, { title: title, noColor: colorsDisabled });
26
20
  };
27
21
  export { LoadingBar };
28
22
  //# sourceMappingURL=LoadingBar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,SAAS,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAExC,MAAM,cAAc,GAAG,GAAG,CAAA;AAC1B,MAAM,UAAU,GAAG,gCAAgC,CAAA;AAQnD,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,SAAS,EAAC,GAAG,SAAS,EAAE,CAAA;IAC/B,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAE5B,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,gBAAgB;IAChB,MAAM,KAAK,GAAG,OAAO,CAAE,MAA6C,CAAC,KAAK,CAAC,CAAA;IAE3E,IAAI,UAAU,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnE,IAAI,OAAO,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QACtC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,IAAI,CAAC,aAAa,IAAI,oBAAC,aAAa,IAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,GAAI;QACpF,oBAAC,IAAI;YAAE,KAAK;mBAAY,CACpB,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport useLayout from '../hooks/use-layout.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Box, Text, useStdout} from 'ink'\n\nconst loadingBarChar = '▀'\nconst hillString = '▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {twoThirds} = useLayout()\n const {stdout} = useStdout()\n\n // On real Node streams, isTTY is only present as an own property when the\n // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents\n // capturing stderr via 2>&1), the animated progress bar can't overwrite\n // previous frames and would flood the output. Show only the static title\n // in that case.\n const isTTY = Boolean((stdout as unknown as Record<string, unknown>).isTTY)\n\n let loadingBar = new Array(twoThirds).fill(loadingBarChar).join('')\n if (noColor ?? !shouldDisplayColors()) {\n loadingBar = hillString.repeat(Math.ceil(twoThirds / hillString.length))\n }\n\n return (\n <Box flexDirection=\"column\">\n {isTTY && !noProgressBar && <TextAnimation text={loadingBar} maxWidth={twoThirds} />}\n <Text>{title} ...</Text>\n </Box>\n )\n}\n\nexport {LoadingBar}\n"]}
1
+ {"version":3,"file":"LoadingBar.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAC,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAQnC,MAAM,UAAU,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAA2C,EAAE,EAAE;IAC/F,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAE5B,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,0EAA0E;IAC1E,gBAAgB;IAChB,MAAM,KAAK,GAAG,OAAO,CAAE,MAA6C,CAAC,KAAK,CAAC,CAAA;IAC3E,MAAM,cAAc,GAAG,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAA;IAExD,IAAI,CAAC,KAAK,IAAI,aAAa,EAAE,CAAC;QAC5B,OAAO,oBAAC,IAAI;YAAE,KAAK;mBAAY,CAAA;IACjC,CAAC;IAED,OAAO,oBAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,GAAI,CAAA;AACpE,CAAC,CAAA;AAED,OAAO,EAAC,UAAU,EAAC,CAAA","sourcesContent":["import {LoadingIndicator} from './LoadingIndicator.js'\nimport {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React from 'react'\n\nimport {Text, useStdout} from 'ink'\n\ninterface LoadingBarProps {\n title: string\n noColor?: boolean\n noProgressBar?: boolean\n}\n\nconst LoadingBar = ({title, noColor, noProgressBar}: React.PropsWithChildren<LoadingBarProps>) => {\n const {stdout} = useStdout()\n\n // On real Node streams, isTTY is only present as an own property when the\n // stream IS a TTY. When Ink's output stream is not a TTY (e.g. AI agents\n // capturing stderr via 2>&1), the animated loading indicator can't overwrite\n // previous frames and would flood the output. Show only the static title\n // in that case.\n const isTTY = Boolean((stdout as unknown as Record<string, unknown>).isTTY)\n const colorsDisabled = noColor ?? !shouldDisplayColors()\n\n if (!isTTY || noProgressBar) {\n return <Text>{title} ...</Text>\n }\n\n return <LoadingIndicator title={title} noColor={colorsDisabled} />\n}\n\nexport {LoadingBar}\n"]}
@@ -2,10 +2,9 @@ import { LoadingBar } from './LoadingBar.js';
2
2
  import { Stdout } from '../../ui.js';
3
3
  import { render } from '../../testing/ui.js';
4
4
  import { shouldDisplayColors, unstyled } from '../../../../public/node/output.js';
5
- import useLayout from '../hooks/use-layout.js';
6
- import React from 'react';
5
+ import React, { act } from 'react';
6
+ import chalk from 'chalk';
7
7
  import { beforeEach, describe, expect, test, vi } from 'vitest';
8
- vi.mock('../hooks/use-layout.js');
9
8
  vi.mock('../../../../public/node/output.js', async () => {
10
9
  const original = await vi.importActual('../../../../public/node/output.js');
11
10
  return {
@@ -14,130 +13,69 @@ vi.mock('../../../../public/node/output.js', async () => {
14
13
  };
15
14
  });
16
15
  beforeEach(() => {
17
- vi.mocked(useLayout).mockReturnValue({
18
- twoThirds: 53,
19
- oneThird: 27,
20
- fullWidth: 80,
21
- });
22
16
  vi.mocked(shouldDisplayColors).mockReturnValue(true);
23
17
  });
24
- /**
25
- * Creates a Stdout test double simulating a TTY stream.
26
- * On real Node streams, isTTY is only present as an own property when the
27
- * stream IS a TTY.
28
- */
29
- function createTTYStdout(columns = 100) {
30
- const stdout = new Stdout({ columns });
18
+ function createTTYStdout() {
19
+ const stdout = new Stdout({ columns: 100 });
31
20
  stdout.isTTY = true;
32
21
  return stdout;
33
22
  }
34
- /**
35
- * Renders LoadingBar with a TTY stdout so the animated progress bar renders.
36
- */
37
23
  function renderWithTTY(element) {
38
24
  const stdout = createTTYStdout();
39
25
  const instance = render(element, { stdout });
40
26
  return { lastFrame: stdout.lastFrame, unmount: instance.unmount };
41
27
  }
42
28
  describe('LoadingBar', () => {
43
- test('renders loading bar with default colored characters', async () => {
44
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
45
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
46
- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
47
- Loading content ..."
48
- `);
49
- });
50
- test('renders loading bar with hill pattern when noColor prop is true', async () => {
51
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
52
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
53
- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
54
- Processing files ..."
55
- `);
56
- });
57
- test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {
58
- vi.mocked(shouldDisplayColors).mockReturnValue(false);
59
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
60
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
61
- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
62
- Downloading packages ..."
63
- `);
64
- });
65
- test('handles narrow terminal width correctly', async () => {
66
- vi.mocked(useLayout).mockReturnValue({ twoThirds: 20, oneThird: 10, fullWidth: 30 });
67
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Building app" }));
68
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
69
- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
70
- Building app ..."
71
- `);
29
+ test('renders the Shopify loading indicator', async () => {
30
+ const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Loading content" }));
31
+ const frame = lastFrame();
32
+ expect(unstyled(frame)).toBe('S> Loading content ...');
33
+ expect(frame).toContain('\u001B[1m');
34
+ expect(frame).toContain('\u001B[3m');
35
+ expect(frame).toContain(chalk.hex('#96BF48')('>'));
36
+ unmount();
72
37
  });
73
- test('handles narrow terminal width correctly in no-color mode', async () => {
74
- vi.mocked(useLayout).mockReturnValue({ twoThirds: 15, oneThird: 8, fullWidth: 23 });
75
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Installing", noColor: true }));
76
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
77
- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇
78
- Installing ..."
79
- `);
38
+ test('blinks the chevron without shifting the title', async () => {
39
+ vi.useFakeTimers();
40
+ const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Uploading theme" }));
41
+ try {
42
+ await act(async () => {
43
+ await vi.advanceTimersByTimeAsync(350);
44
+ });
45
+ expect(unstyled(lastFrame())).toBe('S Uploading theme ...');
46
+ }
47
+ finally {
48
+ unmount();
49
+ vi.useRealTimers();
50
+ }
80
51
  });
81
- test('handles very narrow terminal width in no-color mode', async () => {
82
- vi.mocked(useLayout).mockReturnValue({ twoThirds: 5, oneThird: 3, fullWidth: 8 });
83
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Wait", noColor: true }));
84
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
85
- "▁▁▁▂▂
86
- Wait ..."
87
- `);
52
+ test('renders the chevron without color when noColor is true', async () => {
53
+ const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Processing files", noColor: true }));
54
+ const frame = lastFrame();
55
+ expect(unstyled(frame)).toBe('S> Processing files ...');
56
+ expect(frame).not.toContain(chalk.hex('#96BF48')('>'));
57
+ unmount();
88
58
  });
89
- test('handles wide terminal width correctly', async () => {
90
- vi.mocked(useLayout).mockReturnValue({ twoThirds: 100, oneThird: 50, fullWidth: 150 });
91
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Synchronizing data" }));
92
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
93
- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
94
- Synchronizing data ..."
95
- `);
96
- });
97
- test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {
98
- vi.mocked(useLayout).mockReturnValue({ twoThirds: 90, oneThird: 45, fullWidth: 135 });
99
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Analyzing dependencies", noColor: true }));
100
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
101
- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁
102
- Analyzing dependencies ..."
103
- `);
104
- });
105
- test('renders correctly with empty title', async () => {
106
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
107
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
108
- "▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
109
- ..."
110
- `);
111
- });
112
- test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {
113
- vi.mocked(shouldDisplayColors).mockReturnValue(true);
114
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Testing override", noColor: true }));
115
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
116
- "▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅
117
- Testing override ..."
118
- `);
59
+ test('renders the chevron without color when colors are disabled', async () => {
60
+ vi.mocked(shouldDisplayColors).mockReturnValue(false);
61
+ const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "Downloading packages" }));
62
+ const frame = lastFrame();
63
+ expect(unstyled(frame)).toBe('S> Downloading packages ...');
64
+ expect(frame).not.toContain(chalk.hex('#96BF48')('>'));
65
+ unmount();
119
66
  });
120
- test('renders consistently with same props', async () => {
121
- const props = { title: 'Consistent test', noColor: false };
122
- const { lastFrame: frame1 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
123
- const { lastFrame: frame2 } = renderWithTTY(React.createElement(LoadingBar, { ...props }));
124
- expect(frame1()).toBe(frame2());
67
+ test('renders correctly with an empty title', async () => {
68
+ const { lastFrame, unmount } = renderWithTTY(React.createElement(LoadingBar, { title: "" }));
69
+ expect(unstyled(lastFrame())).toBe('S> ...');
70
+ unmount();
125
71
  });
126
- test('hides progress bar when noProgressBar is true', async () => {
127
- vi.mocked(shouldDisplayColors).mockReturnValue(true);
72
+ test('hides the loading indicator when noProgressBar is true', async () => {
128
73
  const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "task 1", noProgressBar: true }));
129
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"task 1 ..."`);
74
+ expect(unstyled(lastFrame())).toBe('task 1 ...');
130
75
  });
131
76
  test('shows only static title text when output stream is not a TTY', async () => {
132
- // Default test Stdout has no isTTY property, simulating a non-TTY stream
133
77
  const { lastFrame } = render(React.createElement(LoadingBar, { title: "Installing dependencies" }));
134
- expect(unstyled(lastFrame())).toMatchInlineSnapshot(`"Installing dependencies ..."`);
135
- });
136
- test('shows animated progress bar when output stream is a TTY', async () => {
137
- const { lastFrame } = renderWithTTY(React.createElement(LoadingBar, { title: "Uploading theme" }));
138
- const frame = unstyled(lastFrame());
139
- expect(frame).toContain('▀');
140
- expect(frame).toContain('Uploading theme ...');
78
+ expect(unstyled(lastFrame())).toBe('Installing dependencies ...');
141
79
  });
142
80
  });
143
81
  //# sourceMappingURL=LoadingBar.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {Stdout} from '../../ui.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport useLayout from '../hooks/use-layout.js'\nimport React from 'react'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../hooks/use-layout.js')\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n vi.mocked(useLayout).mockReturnValue({\n twoThirds: 53,\n oneThird: 27,\n fullWidth: 80,\n })\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\n/**\n * Creates a Stdout test double simulating a TTY stream.\n * On real Node streams, isTTY is only present as an own property when the\n * stream IS a TTY.\n */\nfunction createTTYStdout(columns = 100) {\n const stdout = new Stdout({columns}) as Stdout & {isTTY: boolean}\n stdout.isTTY = true\n return stdout\n}\n\n/**\n * Renders LoadingBar with a TTY stdout so the animated progress bar renders.\n */\nfunction renderWithTTY(element: React.ReactElement) {\n const stdout = createTTYStdout()\n const instance = render(element, {stdout})\n return {lastFrame: stdout.lastFrame, unmount: instance.unmount}\n}\n\ndescribe('LoadingBar', () => {\n test('renders loading bar with default colored characters', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Loading content\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Loading content ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when noColor prop is true', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Processing files\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Processing files ...\"\n `)\n })\n\n test('renders loading bar with hill pattern when shouldDisplayColors returns false', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Downloading packages\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Downloading packages ...\"\n `)\n })\n\n test('handles narrow terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 20, oneThird: 10, fullWidth: 30})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Building app\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Building app ...\"\n `)\n })\n\n test('handles narrow terminal width correctly in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 15, oneThird: 8, fullWidth: 23})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Installing\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇\n Installing ...\"\n `)\n })\n\n test('handles very narrow terminal width in no-color mode', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 5, oneThird: 3, fullWidth: 8})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Wait\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂\n Wait ...\"\n `)\n })\n\n test('handles wide terminal width correctly', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 100, oneThird: 50, fullWidth: 150})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Synchronizing data\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n Synchronizing data ...\"\n `)\n })\n\n test('handles wide terminal width correctly in no-color mode with pattern repetition', async () => {\n vi.mocked(useLayout).mockReturnValue({twoThirds: 90, oneThird: 45, fullWidth: 135})\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Analyzing dependencies\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁\n Analyzing dependencies ...\"\n `)\n })\n\n test('renders correctly with empty title', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\n ...\"\n `)\n })\n\n test('noColor prop overrides shouldDisplayColors when both would show colors', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Testing override\" noColor />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅▄▄▃▃▂▂▁▁▁▁▂▂▃▃▄▄▅▅▆▆▇▇██▇▇▆▆▅▅\n Testing override ...\"\n `)\n })\n\n test('renders consistently with same props', async () => {\n const props = {title: 'Consistent test', noColor: false}\n const {lastFrame: frame1} = renderWithTTY(<LoadingBar {...props} />)\n const {lastFrame: frame2} = renderWithTTY(<LoadingBar {...props} />)\n\n expect(frame1()).toBe(frame2())\n })\n\n test('hides progress bar when noProgressBar is true', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"task 1\" noProgressBar />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"task 1 ...\"`)\n })\n\n test('shows only static title text when output stream is not a TTY', async () => {\n // Default test Stdout has no isTTY property, simulating a non-TTY stream\n const {lastFrame} = render(<LoadingBar title=\"Installing dependencies\" />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\"Installing dependencies ...\"`)\n })\n\n test('shows animated progress bar when output stream is a TTY', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"Uploading theme\" />)\n\n const frame = unstyled(lastFrame()!)\n expect(frame).toContain('▀')\n expect(frame).toContain('Uploading theme ...')\n })\n})\n"]}
1
+ {"version":3,"file":"LoadingBar.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingBar.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {LoadingBar} from './LoadingBar.js'\nimport {Stdout} from '../../ui.js'\nimport {render} from '../../testing/ui.js'\nimport {shouldDisplayColors, unstyled} from '../../../../public/node/output.js'\nimport React, {act} from 'react'\nimport chalk from 'chalk'\n\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\n\nvi.mock('../../../../public/node/output.js', async () => {\n const original: any = await vi.importActual('../../../../public/node/output.js')\n return {\n ...original,\n shouldDisplayColors: vi.fn(),\n }\n})\n\nbeforeEach(() => {\n vi.mocked(shouldDisplayColors).mockReturnValue(true)\n})\n\nfunction createTTYStdout() {\n const stdout = new Stdout({columns: 100}) as Stdout & {isTTY: boolean}\n stdout.isTTY = true\n return stdout\n}\n\nfunction renderWithTTY(element: React.ReactElement) {\n const stdout = createTTYStdout()\n const instance = render(element, {stdout})\n return {lastFrame: stdout.lastFrame, unmount: instance.unmount}\n}\n\ndescribe('LoadingBar', () => {\n test('renders the Shopify loading indicator', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Loading content\" />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Loading content ...')\n expect(frame).toContain('\\u001B[1m')\n expect(frame).toContain('\\u001B[3m')\n expect(frame).toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('blinks the chevron without shifting the title', async () => {\n vi.useFakeTimers()\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Uploading theme\" />)\n\n try {\n await act(async () => {\n await vi.advanceTimersByTimeAsync(350)\n })\n\n expect(unstyled(lastFrame()!)).toBe('S Uploading theme ...')\n } finally {\n unmount()\n vi.useRealTimers()\n }\n })\n\n test('renders the chevron without color when noColor is true', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Processing files\" noColor />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Processing files ...')\n expect(frame).not.toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('renders the chevron without color when colors are disabled', async () => {\n vi.mocked(shouldDisplayColors).mockReturnValue(false)\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"Downloading packages\" />)\n const frame = lastFrame()!\n\n expect(unstyled(frame)).toBe('S> Downloading packages ...')\n expect(frame).not.toContain(chalk.hex('#96BF48')('>'))\n\n unmount()\n })\n\n test('renders correctly with an empty title', async () => {\n const {lastFrame, unmount} = renderWithTTY(<LoadingBar title=\"\" />)\n\n expect(unstyled(lastFrame()!)).toBe('S> ...')\n\n unmount()\n })\n\n test('hides the loading indicator when noProgressBar is true', async () => {\n const {lastFrame} = renderWithTTY(<LoadingBar title=\"task 1\" noProgressBar />)\n\n expect(unstyled(lastFrame()!)).toBe('task 1 ...')\n })\n\n test('shows only static title text when output stream is not a TTY', async () => {\n const {lastFrame} = render(<LoadingBar title=\"Installing dependencies\" />)\n\n expect(unstyled(lastFrame()!)).toBe('Installing dependencies ...')\n })\n})\n"]}
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface LoadingIndicatorProps {
3
+ title: string;
4
+ noColor?: boolean;
5
+ }
6
+ declare const LoadingIndicator: ({ title, noColor }: LoadingIndicatorProps) => React.JSX.Element;
7
+ export { LoadingIndicator };
@@ -0,0 +1,22 @@
1
+ import { shouldDisplayColors } from '../../../../public/node/output.js';
2
+ import React, { useLayoutEffect, useState } from 'react';
3
+ import { Text } from 'ink';
4
+ const SHOPIFY_GREEN = '#96BF48';
5
+ const CHEVRON_BLINK_INTERVAL_MS = 350;
6
+ const LoadingIndicator = ({ title, noColor = !shouldDisplayColors() }) => {
7
+ const [isChevronVisible, setIsChevronVisible] = useState(true);
8
+ useLayoutEffect(() => {
9
+ const interval = setInterval(() => {
10
+ setIsChevronVisible((isVisible) => !isVisible);
11
+ }, CHEVRON_BLINK_INTERVAL_MS);
12
+ return () => {
13
+ clearInterval(interval);
14
+ };
15
+ }, []);
16
+ return (React.createElement(Text, null,
17
+ React.createElement(Text, { bold: true, italic: true }, "S"),
18
+ React.createElement(Text, { bold: true, color: noColor ? undefined : SHOPIFY_GREEN }, isChevronVisible ? '>' : ' '),
19
+ ` ${title} ...`));
20
+ };
21
+ export { LoadingIndicator };
22
+ //# sourceMappingURL=LoadingIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingIndicator.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/LoadingIndicator.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAC,MAAM,mCAAmC,CAAA;AACrE,OAAO,KAAK,EAAE,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtD,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AAExB,MAAM,aAAa,GAAG,SAAS,CAAA;AAC/B,MAAM,yBAAyB,GAAG,GAAG,CAAA;AAOrC,MAAM,gBAAgB,GAAG,CAAC,EAAC,KAAK,EAAE,OAAO,GAAG,CAAC,mBAAmB,EAAE,EAAwB,EAAE,EAAE;IAC5F,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAE9D,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,mBAAmB,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAA;QAChD,CAAC,EAAE,yBAAyB,CAAC,CAAA;QAE7B,OAAO,GAAG,EAAE;YACV,aAAa,CAAC,QAAQ,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,oBAAC,IAAI;QACH,oBAAC,IAAI,IAAC,IAAI,QAAC,MAAM,cAEV;QACP,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,IAClD,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CACxB;QACN,IAAI,KAAK,MAAM,CACX,CACR,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,gBAAgB,EAAC,CAAA","sourcesContent":["import {shouldDisplayColors} from '../../../../public/node/output.js'\nimport React, {useLayoutEffect, useState} from 'react'\nimport {Text} from 'ink'\n\nconst SHOPIFY_GREEN = '#96BF48'\nconst CHEVRON_BLINK_INTERVAL_MS = 350\n\ninterface LoadingIndicatorProps {\n title: string\n noColor?: boolean\n}\n\nconst LoadingIndicator = ({title, noColor = !shouldDisplayColors()}: LoadingIndicatorProps) => {\n const [isChevronVisible, setIsChevronVisible] = useState(true)\n\n useLayoutEffect(() => {\n const interval = setInterval(() => {\n setIsChevronVisible((isVisible) => !isVisible)\n }, CHEVRON_BLINK_INTERVAL_MS)\n\n return () => {\n clearInterval(interval)\n }\n }, [])\n\n return (\n <Text>\n <Text bold italic>\n S\n </Text>\n <Text bold color={noColor ? undefined : SHOPIFY_GREEN}>\n {isChevronVisible ? '>' : ' '}\n </Text>\n {` ${title} ...`}\n </Text>\n )\n}\n\nexport {LoadingIndicator}\n"]}
@@ -1 +1 @@
1
- export declare const CLI_KIT_VERSION = "4.9.5";
1
+ export declare const CLI_KIT_VERSION = "5.0.0";
@@ -1,2 +1,2 @@
1
- export const CLI_KIT_VERSION = '4.9.5';
1
+ export const CLI_KIT_VERSION = '5.0.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '4.9.5'\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '5.0.0'\n"]}
@@ -123,6 +123,19 @@ export async function fetchApiVersions(session, preferredBehaviour) {
123
123
  const storeName = session.storeFqdn.replace('.myshopify.com', '');
124
124
  throw new AbortError(outputContent `Looks like you don't have access to this dev store: (${outputToken.link(storeName, `https://${session.storeFqdn}`)})`, outputContent `If you're not the owner, create a dev store staff account for yourself`);
125
125
  }
126
+ if (error instanceof ClientError && error.response.status === 401 && isThemeAccessSession(session)) {
127
+ throw new AbortError(`The Theme Access password was rejected for the store ${session.storeFqdn}.`, 'Theme Access passwords only work on the store they were generated for, and only with its permanent .myshopify.com domain.', [
128
+ 'Check that the password was created in the Theme Access app on this store and has not been deleted.',
129
+ [
130
+ 'Pass the permanent domain to',
131
+ { command: '--store' },
132
+ { char: '.' },
133
+ 'It is the .myshopify.com domain listed in the Shopify admin under',
134
+ { subdued: 'Settings > Domains' },
135
+ { char: '.' },
136
+ ],
137
+ ]);
138
+ }
126
139
  if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {
127
140
  throw new AbortError(`Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`);
128
141
  }