@shopify/cli-kit 3.53.0 → 3.54.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 (67) hide show
  1. package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/proxy.rb +14 -0
  2. package/dist/private/node/analytics.js +2 -4
  3. package/dist/private/node/analytics.js.map +1 -1
  4. package/dist/private/node/ui/components/List.d.ts +8 -1
  5. package/dist/private/node/ui/components/List.js +26 -5
  6. package/dist/private/node/ui/components/List.js.map +1 -1
  7. package/dist/private/node/ui/components/List.test.js +17 -0
  8. package/dist/private/node/ui/components/List.test.js.map +1 -1
  9. package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +3 -1
  10. package/dist/private/node/ui/components/Prompts/InfoTable.js +4 -1
  11. package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
  12. package/dist/private/node/ui/components/Prompts/InfoTable.test.js +26 -0
  13. package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
  14. package/dist/public/common/object.d.ts +7 -0
  15. package/dist/public/common/object.js +10 -0
  16. package/dist/public/common/object.js.map +1 -1
  17. package/dist/public/common/retry.d.ts +14 -0
  18. package/dist/public/common/retry.js +27 -0
  19. package/dist/public/common/retry.js.map +1 -0
  20. package/dist/public/common/version.d.ts +1 -1
  21. package/dist/public/common/version.js +1 -1
  22. package/dist/public/common/version.js.map +1 -1
  23. package/dist/public/node/analytics.js +1 -1
  24. package/dist/public/node/analytics.js.map +1 -1
  25. package/dist/public/node/api/partners.d.ts +15 -7
  26. package/dist/public/node/api/partners.js +16 -20
  27. package/dist/public/node/api/partners.js.map +1 -1
  28. package/dist/public/node/base-command.js +1 -1
  29. package/dist/public/node/base-command.js.map +1 -1
  30. package/dist/public/node/context/local.d.ts +0 -7
  31. package/dist/public/node/context/local.js +0 -9
  32. package/dist/public/node/context/local.js.map +1 -1
  33. package/dist/public/node/error-handler.js +1 -1
  34. package/dist/public/node/error-handler.js.map +1 -1
  35. package/dist/public/node/fs.d.ts +5 -1
  36. package/dist/public/node/fs.js +3 -2
  37. package/dist/public/node/fs.js.map +1 -1
  38. package/dist/public/node/monorail.js +9 -0
  39. package/dist/public/node/monorail.js.map +1 -1
  40. package/dist/public/node/schema.d.ts +8 -0
  41. package/dist/public/node/schema.js +20 -0
  42. package/dist/public/node/schema.js.map +1 -1
  43. package/dist/public/node/themes/{themes-api.d.ts → api.d.ts} +3 -1
  44. package/dist/public/node/themes/{themes-api.js → api.js} +21 -13
  45. package/dist/public/node/themes/api.js.map +1 -0
  46. package/dist/public/node/themes/factories.d.ts +18 -0
  47. package/dist/public/node/themes/factories.js +27 -0
  48. package/dist/public/node/themes/factories.js.map +1 -0
  49. package/dist/public/node/themes/theme-manager.d.ts +1 -1
  50. package/dist/public/node/themes/theme-manager.js +2 -2
  51. package/dist/public/node/themes/theme-manager.js.map +1 -1
  52. package/dist/public/node/themes/types.d.ts +68 -0
  53. package/dist/public/node/themes/types.js +2 -0
  54. package/dist/public/node/themes/types.js.map +1 -0
  55. package/dist/public/node/themes/{theme-urls.d.ts → urls.d.ts} +1 -1
  56. package/dist/public/node/themes/{theme-urls.js → urls.js} +1 -1
  57. package/dist/public/node/themes/urls.js.map +1 -0
  58. package/dist/public/node/themes/utils.d.ts +3 -0
  59. package/dist/public/node/themes/utils.js +5 -0
  60. package/dist/public/node/themes/utils.js.map +1 -0
  61. package/dist/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +2 -2
  63. package/dist/public/node/themes/models/theme.d.ts +0 -12
  64. package/dist/public/node/themes/models/theme.js +0 -30
  65. package/dist/public/node/themes/models/theme.js.map +0 -1
  66. package/dist/public/node/themes/theme-urls.js.map +0 -1
  67. package/dist/public/node/themes/themes-api.js.map +0 -1
@@ -49,6 +49,7 @@ module ShopifyCLI
49
49
  return [204, {}, []] if IGNORED_ENDPOINTS.any? { |endpoint| env["PATH_INFO"].include?(endpoint) }
50
50
 
51
51
  headers = extract_http_request_headers(env)
52
+ is_chrome = headers["User-Agent"] =~ /[Cc]hrome/
52
53
  headers["Host"] = shop
53
54
  headers["Cookie"] = add_session_cookie(headers["Cookie"])
54
55
  headers["Accept-Encoding"] = "none"
@@ -76,6 +77,7 @@ module ShopifyCLI
76
77
  end
77
78
 
78
79
  headers = get_response_headers(response, env)
80
+ headers = modify_headers(headers) unless is_chrome
79
81
 
80
82
  unless headers["x-storefront-renderer-rendered"]
81
83
  @core_endpoints << env["PATH_INFO"]
@@ -268,6 +270,18 @@ module ShopifyCLI
268
270
 
269
271
  true
270
272
  end
273
+
274
+ def modify_headers(headers)
275
+ if headers["set-cookie"]&.include?("storefront_digest")
276
+ headers["set-cookie"] = modify_set_cookie_header_for_safari(headers["set-cookie"])
277
+ end
278
+
279
+ headers
280
+ end
281
+
282
+ def modify_set_cookie_header_for_safari(set_cookie_header)
283
+ set_cookie_header.gsub("secure;", "secure: false;")
284
+ end
271
285
  end
272
286
  end
273
287
  end
@@ -47,9 +47,7 @@ export async function getSensitiveEnvironmentData(config) {
47
47
  };
48
48
  }
49
49
  function getPluginNames(config) {
50
- return config.plugins
51
- .map((plugin) => plugin.name)
52
- .sort()
53
- .filter((plugin) => !plugin.startsWith('@oclif/'));
50
+ const pluginNames = [...config.plugins.keys()];
51
+ return pluginNames.sort().filter((plugin) => !plugin.startsWith('@oclif/'));
54
52
  }
55
53
  //# sourceMappingURL=analytics.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {hashString} from '../../public/node/crypto.js'\nimport {getPackageManager, packageManagerFromUserAgent} from '../../public/node/node-package-manager.js'\nimport BaseCommand from '../../public/node/base-command.js'\nimport {CommandContent} from '../../public/node/hooks/prerun.js'\nimport * as metadata from '../../public/node/metadata.js'\nimport {platformAndArch} from '../../public/node/os.js'\nimport {Command, Interfaces} from '@oclif/core'\nimport {ciPlatform, cloudEnvironment, macAddress} from '@shopify/cli-kit/node/context/local'\nimport {cwd} from '@shopify/cli-kit/node/path'\n\ninterface StartOptions {\n commandContent: CommandContent\n args: string[]\n currentTime?: number\n commandClass?: Command.Class | typeof BaseCommand\n}\n\nexport async function startAnalytics({\n commandContent,\n args,\n currentTime = new Date().getTime(),\n commandClass,\n}: StartOptions): Promise<void> {\n let startCommand: string = commandContent.command\n if (commandClass && Object.prototype.hasOwnProperty.call(commandClass, 'analyticsNameOverride')) {\n startCommand = (commandClass as typeof BaseCommand).analyticsNameOverride() ?? commandContent.command\n }\n\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n startTime: currentTime,\n startCommand,\n startArgs: args,\n },\n }))\n\n await metadata.addPublicMetadata(() => ({\n cmd_all_launcher: packageManagerFromUserAgent(),\n cmd_all_alias_used: commandContent.alias,\n cmd_all_topic: commandContent.topic,\n cmd_all_plugin: commandClass?.plugin?.name,\n }))\n}\n\ninterface EnvironmentData {\n uname: string\n env_ci: boolean\n env_ci_platform?: string\n env_plugin_installed_any_custom: boolean\n env_plugin_installed_shopify: string\n env_shell: string\n env_web_ide: string | undefined\n env_device_id: string\n env_cloud: string\n env_package_manager: string\n}\n\nexport async function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData> {\n const ciplatform = ciPlatform()\n\n const pluginNames = getPluginNames(config)\n const shopifyPlugins = pluginNames.filter((plugin) => plugin.startsWith('@shopify/'))\n\n const {platform, arch} = platformAndArch()\n\n return {\n uname: `${platform} ${arch}`,\n env_ci: ciplatform.isCI,\n env_ci_platform: ciplatform.name,\n env_plugin_installed_any_custom: pluginNames.length !== shopifyPlugins.length,\n env_plugin_installed_shopify: JSON.stringify(shopifyPlugins),\n env_shell: config.shell,\n env_web_ide: cloudEnvironment().editor ? cloudEnvironment().platform : undefined,\n env_device_id: hashString(await macAddress()),\n env_cloud: cloudEnvironment().platform,\n env_package_manager: await getPackageManager(cwd()),\n }\n}\n\nexport async function getSensitiveEnvironmentData(config: Interfaces.Config) {\n return {\n env_plugin_installed_all: JSON.stringify(getPluginNames(config)),\n }\n}\n\nfunction getPluginNames(config: Interfaces.Config) {\n return config.plugins\n .map((plugin) => plugin.name)\n .sort()\n .filter((plugin) => !plugin.startsWith('@oclif/'))\n}\n"]}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAC,iBAAiB,EAAE,2BAA2B,EAAC,MAAM,2CAA2C,CAAA;AAGxG,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AACzD,OAAO,EAAC,eAAe,EAAC,MAAM,yBAAyB,CAAA;AAEvD,OAAO,EAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAC,MAAM,qCAAqC,CAAA;AAC5F,OAAO,EAAC,GAAG,EAAC,MAAM,4BAA4B,CAAA;AAS9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EACnC,cAAc,EACd,IAAI,EACJ,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAClC,YAAY,GACC;IACb,IAAI,YAAY,GAAW,cAAc,CAAC,OAAO,CAAA;IACjD,IAAI,YAAY,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,EAAE;QAC/F,YAAY,GAAI,YAAmC,CAAC,qBAAqB,EAAE,IAAI,cAAc,CAAC,OAAO,CAAA;KACtG;IAED,MAAM,QAAQ,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,mBAAmB,EAAE;YACnB,SAAS,EAAE,WAAW;YACtB,YAAY;YACZ,SAAS,EAAE,IAAI;SAChB;KACF,CAAC,CAAC,CAAA;IAEH,MAAM,QAAQ,CAAC,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAAC;QACtC,gBAAgB,EAAE,2BAA2B,EAAE;QAC/C,kBAAkB,EAAE,cAAc,CAAC,KAAK;QACxC,aAAa,EAAE,cAAc,CAAC,KAAK;QACnC,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI;KAC3C,CAAC,CAAC,CAAA;AACL,CAAC;AAeD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAyB;IAChE,MAAM,UAAU,GAAG,UAAU,EAAE,CAAA;IAE/B,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAA;IAErF,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAC,GAAG,eAAe,EAAE,CAAA;IAE1C,OAAO;QACL,KAAK,EAAE,GAAG,QAAQ,IAAI,IAAI,EAAE;QAC5B,MAAM,EAAE,UAAU,CAAC,IAAI;QACvB,eAAe,EAAE,UAAU,CAAC,IAAI;QAChC,+BAA+B,EAAE,WAAW,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM;QAC7E,4BAA4B,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;QAC5D,SAAS,EAAE,MAAM,CAAC,KAAK;QACvB,WAAW,EAAE,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;QAChF,aAAa,EAAE,UAAU,CAAC,MAAM,UAAU,EAAE,CAAC;QAC7C,SAAS,EAAE,gBAAgB,EAAE,CAAC,QAAQ;QACtC,mBAAmB,EAAE,MAAM,iBAAiB,CAAC,GAAG,EAAE,CAAC;KACpD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,MAAyB;IACzE,OAAO;QACL,wBAAwB,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;KACjE,CAAA;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAyB;IAC/C,MAAM,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IAC9C,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;AAC7E,CAAC","sourcesContent":["import {hashString} from '../../public/node/crypto.js'\nimport {getPackageManager, packageManagerFromUserAgent} from '../../public/node/node-package-manager.js'\nimport BaseCommand from '../../public/node/base-command.js'\nimport {CommandContent} from '../../public/node/hooks/prerun.js'\nimport * as metadata from '../../public/node/metadata.js'\nimport {platformAndArch} from '../../public/node/os.js'\nimport {Command, Interfaces} from '@oclif/core'\nimport {ciPlatform, cloudEnvironment, macAddress} from '@shopify/cli-kit/node/context/local'\nimport {cwd} from '@shopify/cli-kit/node/path'\n\ninterface StartOptions {\n commandContent: CommandContent\n args: string[]\n currentTime?: number\n commandClass?: Command.Class | typeof BaseCommand\n}\n\nexport async function startAnalytics({\n commandContent,\n args,\n currentTime = new Date().getTime(),\n commandClass,\n}: StartOptions): Promise<void> {\n let startCommand: string = commandContent.command\n if (commandClass && Object.prototype.hasOwnProperty.call(commandClass, 'analyticsNameOverride')) {\n startCommand = (commandClass as typeof BaseCommand).analyticsNameOverride() ?? commandContent.command\n }\n\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n startTime: currentTime,\n startCommand,\n startArgs: args,\n },\n }))\n\n await metadata.addPublicMetadata(() => ({\n cmd_all_launcher: packageManagerFromUserAgent(),\n cmd_all_alias_used: commandContent.alias,\n cmd_all_topic: commandContent.topic,\n cmd_all_plugin: commandClass?.plugin?.name,\n }))\n}\n\ninterface EnvironmentData {\n uname: string\n env_ci: boolean\n env_ci_platform?: string\n env_plugin_installed_any_custom: boolean\n env_plugin_installed_shopify: string\n env_shell: string\n env_web_ide: string | undefined\n env_device_id: string\n env_cloud: string\n env_package_manager: string\n}\n\nexport async function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData> {\n const ciplatform = ciPlatform()\n\n const pluginNames = getPluginNames(config)\n const shopifyPlugins = pluginNames.filter((plugin) => plugin.startsWith('@shopify/'))\n\n const {platform, arch} = platformAndArch()\n\n return {\n uname: `${platform} ${arch}`,\n env_ci: ciplatform.isCI,\n env_ci_platform: ciplatform.name,\n env_plugin_installed_any_custom: pluginNames.length !== shopifyPlugins.length,\n env_plugin_installed_shopify: JSON.stringify(shopifyPlugins),\n env_shell: config.shell,\n env_web_ide: cloudEnvironment().editor ? cloudEnvironment().platform : undefined,\n env_device_id: hashString(await macAddress()),\n env_cloud: cloudEnvironment().platform,\n env_package_manager: await getPackageManager(cwd()),\n }\n}\n\nexport async function getSensitiveEnvironmentData(config: Interfaces.Config) {\n return {\n env_plugin_installed_all: JSON.stringify(getPluginNames(config)),\n }\n}\n\nfunction getPluginNames(config: Interfaces.Config) {\n const pluginNames = [...config.plugins.keys()]\n return pluginNames.sort().filter((plugin) => !plugin.startsWith('@oclif/'))\n}\n"]}
@@ -1,9 +1,16 @@
1
1
  import { InlineToken, TokenItem } from './TokenizedText.js';
2
2
  import { TextProps } from 'ink';
3
3
  import { FunctionComponent } from 'react';
4
+ export interface CustomListItem {
5
+ type?: string;
6
+ item: TokenItem<InlineToken>;
7
+ bullet?: string;
8
+ color?: TextProps['color'];
9
+ }
10
+ type ListItem = TokenItem<InlineToken> | CustomListItem;
4
11
  interface ListProps {
5
12
  title?: TokenItem<InlineToken>;
6
- items: TokenItem<InlineToken>[];
13
+ items: ListItem[];
7
14
  ordered?: boolean;
8
15
  margin?: boolean;
9
16
  color?: TextProps['color'];
@@ -7,14 +7,35 @@ const DOT = '•';
7
7
  * and wrapped to the container width.
8
8
  */
9
9
  const List = ({ title, items, margin = true, ordered = false, color, bullet = DOT, }) => {
10
- return (React.createElement(Box, { flexDirection: "column" },
11
- title ? (React.createElement(Text, { color: color },
12
- React.createElement(TokenizedText, { item: title }))) : null,
13
- items.map((item, index) => (React.createElement(Box, { key: index, marginLeft: margin ? 2 : 0 },
10
+ function isCustomListItem(item) {
11
+ return item.item !== undefined;
12
+ }
13
+ function resolveListItem(item, index) {
14
+ const resolvedItem = {
15
+ index,
16
+ color,
17
+ bullet,
18
+ ordered,
19
+ item: item,
20
+ };
21
+ return isCustomListItem(item)
22
+ ? {
23
+ ...resolvedItem,
24
+ ...item,
25
+ }
26
+ : resolvedItem;
27
+ }
28
+ const ListItem = ({ item, color, bullet, index, ordered }) => {
29
+ return (React.createElement(Box, { key: index, marginLeft: margin ? 2 : 0 },
14
30
  React.createElement(Text, { color: color }, `${ordered ? `${index + 1}.` : bullet}`),
15
31
  React.createElement(Box, { flexGrow: 1, marginLeft: 1 },
16
32
  React.createElement(Text, { color: color },
17
- React.createElement(TokenizedText, { item: item }))))))));
33
+ React.createElement(TokenizedText, { item: item })))));
34
+ };
35
+ return (React.createElement(Box, { flexDirection: "column" },
36
+ title ? (React.createElement(Text, { color: color },
37
+ React.createElement(TokenizedText, { item: title }))) : null,
38
+ items.map(resolveListItem).map(({ index, item, color, bullet, ordered }) => (React.createElement(ListItem, { key: index, item: item, color: color, bullet: bullet, index: index, ordered: ordered })))));
18
39
  };
19
40
  export { List };
20
41
  //# sourceMappingURL=List.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"List.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,aAAa,EAAC,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;AAW9C,MAAM,GAAG,GAAG,GAAG,CAAA;AAEf;;;GAGG;AACH,MAAM,IAAI,GAAiC,CAAC,EAC1C,KAAK,EACL,KAAK,EACL,MAAM,GAAG,IAAI,EACb,OAAO,GAAG,KAAK,EACf,KAAK,EACL,MAAM,GAAG,GAAG,GACb,EAAe,EAAE;IAChB,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,CAAC,CAAC,CAAC,CACP,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;YAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,KAAK,GAAI,CACzB,CACR,CAAC,CAAC,CAAC,IAAI;QACP,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAQ;YAEpE,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC7B,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;oBAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CACxB,CACH,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text, TextProps} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\ninterface ListProps {\n title?: TokenItem<InlineToken>\n items: TokenItem<InlineToken>[]\n ordered?: boolean\n margin?: boolean\n color?: TextProps['color']\n bullet?: string\n}\n\nconst DOT = '•'\n\n/**\n * `List` displays an unordered or ordered list with text aligned with the bullet point\n * and wrapped to the container width.\n */\nconst List: FunctionComponent<ListProps> = ({\n title,\n items,\n margin = true,\n ordered = false,\n color,\n bullet = DOT,\n}): JSX.Element => {\n return (\n <Box flexDirection=\"column\">\n {title ? (\n <Text color={color}>\n <TokenizedText item={title} />\n </Text>\n ) : null}\n {items.map((item, index) => (\n <Box key={index} marginLeft={margin ? 2 : 0}>\n <Text color={color}>{`${ordered ? `${index + 1}.` : bullet}`}</Text>\n\n <Box flexGrow={1} marginLeft={1}>\n <Text color={color}>\n <TokenizedText item={item} />\n </Text>\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {List}\n"]}
1
+ {"version":3,"file":"List.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,aAAa,EAAC,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;AAoB9C,MAAM,GAAG,GAAG,GAAG,CAAA;AAEf;;;GAGG;AACH,MAAM,IAAI,GAAiC,CAAC,EAC1C,KAAK,EACL,KAAK,EACL,MAAM,GAAG,IAAI,EACb,OAAO,GAAG,KAAK,EACf,KAAK,EACL,MAAM,GAAG,GAAG,GACb,EAAe,EAAE;IAChB,SAAS,gBAAgB,CAAC,IAA6C;QACrE,OAAQ,IAAuB,CAAC,IAAI,KAAK,SAAS,CAAA;IACpD,CAAC;IAED,SAAS,eAAe,CAAC,IAAc,EAAE,KAAa;QACpD,MAAM,YAAY,GAAG;YACnB,KAAK;YACL,KAAK;YACL,MAAM;YACN,OAAO;YACP,IAAI,EAAE,IAA8B;SACrC,CAAA;QACD,OAAO,gBAAgB,CAAC,IAAI,CAAC;YAC3B,CAAC,CAAC;gBACE,GAAG,YAAY;gBACf,GAAG,IAAI;aACR;YACH,CAAC,CAAC,YAAY,CAAA;IAClB,CAAC;IAUD,MAAM,QAAQ,GAAqC,CAAC,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAC,EAAE,EAAE;QAC3F,OAAO,CACL,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAQ;YAEpE,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC7B,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;oBAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CACxB,CACH,CACF,CACP,CAAA;IACH,CAAC,CAAA;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,CAAC,CAAC,CAAC,CACP,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK;YAChB,oBAAC,aAAa,IAAC,IAAI,EAAE,KAAK,GAAI,CACzB,CACR,CAAC,CAAC,CAAC,IAAI;QACP,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAC,EAAE,EAAE,CAAC,CACzE,oBAAC,QAAQ,IAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CACnG,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import {InlineToken, TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text, TextProps} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\nexport interface CustomListItem {\n type?: string\n item: TokenItem<InlineToken>\n bullet?: string\n color?: TextProps['color']\n}\n\ntype ListItem = TokenItem<InlineToken> | CustomListItem\n\ninterface ListProps {\n title?: TokenItem<InlineToken>\n items: ListItem[]\n ordered?: boolean\n margin?: boolean\n color?: TextProps['color']\n bullet?: string\n}\n\nconst DOT = '•'\n\n/**\n * `List` displays an unordered or ordered list with text aligned with the bullet point\n * and wrapped to the container width.\n */\nconst List: FunctionComponent<ListProps> = ({\n title,\n items,\n margin = true,\n ordered = false,\n color,\n bullet = DOT,\n}): JSX.Element => {\n function isCustomListItem(item: TokenItem<InlineToken> | CustomListItem): item is CustomListItem {\n return (item as CustomListItem).item !== undefined\n }\n\n function resolveListItem(item: ListItem, index: number) {\n const resolvedItem = {\n index,\n color,\n bullet,\n ordered,\n item: item as TokenItem<InlineToken>,\n }\n return isCustomListItem(item)\n ? {\n ...resolvedItem,\n ...item,\n }\n : resolvedItem\n }\n\n interface ListItemProps {\n item: TokenItem<InlineToken>\n color: TextProps['color']\n bullet: string\n index: number\n ordered: boolean\n }\n\n const ListItem: FunctionComponent<ListItemProps> = ({item, color, bullet, index, ordered}) => {\n return (\n <Box key={index} marginLeft={margin ? 2 : 0}>\n <Text color={color}>{`${ordered ? `${index + 1}.` : bullet}`}</Text>\n\n <Box flexGrow={1} marginLeft={1}>\n <Text color={color}>\n <TokenizedText item={item} />\n </Text>\n </Box>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n {title ? (\n <Text color={color}>\n <TokenizedText item={title} />\n </Text>\n ) : null}\n {items.map(resolveListItem).map(({index, item, color, bullet, ordered}) => (\n <ListItem key={index} item={item} color={color} bullet={bullet} index={index} ordered={ordered} />\n ))}\n </Box>\n )\n}\n\nexport {List}\n"]}
@@ -81,5 +81,22 @@ describe('List', async () => {
81
81
  • Item 3"
82
82
  `);
83
83
  });
84
+ test('renders custom items', async () => {
85
+ const options = {
86
+ items: [
87
+ { bullet: '-', color: 'red', item: 'Custom Item 1' },
88
+ 'Item 1',
89
+ { bullet: '_', color: 'green', item: 'Custom Item 2' },
90
+ ],
91
+ bullet: '*',
92
+ color: 'gray',
93
+ };
94
+ const { lastFrame } = render(React.createElement(List, { ...options }));
95
+ expect(lastFrame()).toMatchInlineSnapshot(`
96
+ " - Custom Item 1
97
+ * Item 1
98
+ _ Custom Item 2"
99
+ `);
100
+ });
84
101
  });
85
102
  //# sourceMappingURL=List.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"List.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,QAAQ,EAAC,MAAM,mCAAmC,CAAA;AAC1D,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;IAC1B,IAAI,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,KAAK;SACf,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;KAKpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,MAAM,EAAE,IAAI;SACb,CAAA;QAED,MAAM,EAAC,SAAS,EAAE,eAAe,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAElE,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;KAI1D,CAAC,CAAA;QAEF,MAAM,EAAC,SAAS,EAAE,iBAAiB,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,EAAE,MAAM,EAAE,KAAK,GAAI,CAAC,CAAA;QAEnF,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;KAI5D,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,KAAK,EAAE,KAAK;SACb,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;KAKzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,IAAI;SACd,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;KAIpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,OAAO,GAAG;YACd,KAAK,EAAE;gBACL,YAAY;gBACZ;oBACE,IAAI,EAAE,SAAS;iBAChB;aACF;YACD,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,KAAK;SACf,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC;;;;;KAKzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {List} from './List.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('List', async () => {\n test('renders unordered items', async () => {\n const options = {\n title: 'List title',\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: false,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"List title\n • Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('renders items with margin or not', async () => {\n const options = {\n items: ['Item 1', 'Item 2', 'Item 3'],\n margin: true,\n }\n\n const {lastFrame: marginLastFrame} = render(<List {...options} />)\n\n expect(unstyled(marginLastFrame()!)).toMatchInlineSnapshot(`\n \" • Item 1\n • Item 2\n • Item 3\"\n `)\n\n const {lastFrame: noMarginLastFrame} = render(<List {...options} margin={false} />)\n\n expect(unstyled(noMarginLastFrame()!)).toMatchInlineSnapshot(`\n \"• Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('can give the text a color', async () => {\n const options = {\n title: 'List title',\n items: ['Item 1', 'Item 2', 'Item 3'],\n color: 'red',\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\u001b[31mList title\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 1\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 2\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 3\u001b[39m\"\n `)\n })\n\n test('renders ordered items', async () => {\n const options = {\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: true,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \" 1. Item 1\n 2. Item 2\n 3. Item 3\"\n `)\n })\n\n test('title can be made of tokens', async () => {\n const options = {\n title: [\n 'List title',\n {\n bold: ' (bold)',\n },\n ],\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: false,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"List title \u001b[1m (bold)\u001b[22m\n • Item 1\n • Item 2\n • Item 3\"\n `)\n })\n})\n"]}
1
+ {"version":3,"file":"List.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {List} from './List.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('List', async () => {\n test('renders unordered items', async () => {\n const options = {\n title: 'List title',\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: false,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"List title\n • Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('renders items with margin or not', async () => {\n const options = {\n items: ['Item 1', 'Item 2', 'Item 3'],\n margin: true,\n }\n\n const {lastFrame: marginLastFrame} = render(<List {...options} />)\n\n expect(unstyled(marginLastFrame()!)).toMatchInlineSnapshot(`\n \" • Item 1\n • Item 2\n • Item 3\"\n `)\n\n const {lastFrame: noMarginLastFrame} = render(<List {...options} margin={false} />)\n\n expect(unstyled(noMarginLastFrame()!)).toMatchInlineSnapshot(`\n \"• Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('can give the text a color', async () => {\n const options = {\n title: 'List title',\n items: ['Item 1', 'Item 2', 'Item 3'],\n color: 'red',\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\u001b[31mList title\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 1\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 2\u001b[39m\n \u001b[31m•\u001b[39m \u001b[31mItem 3\u001b[39m\"\n `)\n })\n\n test('renders ordered items', async () => {\n const options = {\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: true,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \" 1. Item 1\n 2. Item 2\n 3. Item 3\"\n `)\n })\n\n test('title can be made of tokens', async () => {\n const options = {\n title: [\n 'List title',\n {\n bold: ' (bold)',\n },\n ],\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: false,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"List title \u001b[1m (bold)\u001b[22m\n • Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('renders custom items', async () => {\n const options = {\n items: [\n {bullet: '-', color: 'red', item: 'Custom Item 1'},\n 'Item 1',\n {bullet: '_', color: 'green', item: 'Custom Item 2'},\n ],\n bullet: '*',\n color: 'gray',\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(lastFrame()!).toMatchInlineSnapshot(`\n \" \u001b[31m-\u001b[39m \u001b[31mCustom Item 1\u001b[39m\n \u001b[90m*\u001b[39m \u001b[90mItem 1\u001b[39m\n \u001b[32m_\u001b[39m \u001b[32mCustom Item 2\u001b[39m\"\n `)\n })\n})\n"]}
@@ -1,13 +1,15 @@
1
+ import { CustomListItem } from '../List.js';
1
2
  import { InlineToken, TokenItem } from '../TokenizedText.js';
2
3
  import { TextProps } from 'ink';
3
4
  import { FunctionComponent } from 'react';
4
- type Items = TokenItem<InlineToken>[];
5
+ type Items = (TokenItem<InlineToken> | CustomListItem)[];
5
6
  export interface InfoTableSection {
6
7
  color?: TextProps['color'];
7
8
  header: string;
8
9
  bullet?: string;
9
10
  helperText?: string;
10
11
  items: Items;
12
+ emptyItemsText?: string;
11
13
  }
12
14
  export interface InfoTableProps {
13
15
  table: {
@@ -1,5 +1,6 @@
1
1
  import { List } from '../List.js';
2
2
  import { capitalize } from '../../../../../public/common/string.js';
3
+ import { TokenizedText } from '../TokenizedText.js';
3
4
  import { Box, Text } from 'ink';
4
5
  import React from 'react';
5
6
  const InfoTable = ({ table }) => {
@@ -11,6 +12,7 @@ const InfoTable = ({ table }) => {
11
12
  color: undefined,
12
13
  helperText: undefined,
13
14
  bullet: undefined,
15
+ emptyItemsText: undefined,
14
16
  }));
15
17
  const headerColumnWidth = Math.max(...sections.map((section) => {
16
18
  return Math.max(...section.header.split('\n').map((line) => {
@@ -21,7 +23,8 @@ const InfoTable = ({ table }) => {
21
23
  section.header.length > 0 && (React.createElement(Box, { width: headerColumnWidth + 1 },
22
24
  React.createElement(Text, { color: section.color, bold: true }, capitalize(section.header)))),
23
25
  React.createElement(Box, { flexGrow: 1, flexDirection: "column", gap: 1 },
24
- React.createElement(List, { margin: false, items: section.items, color: section.color, bullet: section.bullet }),
26
+ section.emptyItemsText && section.items.length === 0 ? (React.createElement(Text, { color: section.color },
27
+ React.createElement(TokenizedText, { item: { subdued: section.emptyItemsText } }))) : (React.createElement(List, { margin: false, items: section.items, color: section.color, bullet: section.bullet })),
25
28
  section.helperText ? React.createElement(Text, { color: section.color }, section.helperText) : null))))));
26
29
  };
27
30
  export { InfoTable };
@@ -1 +1 @@
1
- {"version":3,"file":"InfoTable.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/B,OAAO,EAAC,UAAU,EAAC,MAAM,wCAAwC,CAAA;AAEjE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;AAoB9C,MAAM,SAAS,GAAsC,CAAC,EAAC,KAAK,EAAC,EAAE,EAAE;IAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACnC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAClC,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,MAAM,CAAE;YACrB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC,CAAA;IAEP,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAChC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC1B,OAAO,IAAI,CAAC,GAAG,CACb,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzC,OAAO,IAAI,CAAC,MAAM,CAAA;QACpB,CAAC,CAAC,CACH,CAAA;IACH,CAAC,CAAC,CACH,CAAA;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,IACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAChC,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAC,QAAQ;QACzF,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAC5B,oBAAC,GAAG,IAAC,KAAK,EAAE,iBAAiB,GAAG,CAAC;YAC/B,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,UAC7B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CACtB,CACH,CACP;QACD,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC;YAC7C,oBAAC,IAAI,IAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAI;YAC1F,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAG,OAAO,CAAC,UAAU,CAAQ,CAAC,CAAC,CAAC,IAAI,CAChF,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,SAAS,EAAC,CAAA","sourcesContent":["import {List} from '../List.js'\nimport {capitalize} from '../../../../../public/common/string.js'\nimport {InlineToken, TokenItem} from '../TokenizedText.js'\nimport {Box, Text, TextProps} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\ntype Items = TokenItem<InlineToken>[]\n\nexport interface InfoTableSection {\n color?: TextProps['color']\n header: string\n bullet?: string\n helperText?: string\n items: Items\n}\n\nexport interface InfoTableProps {\n table:\n | {\n [header: string]: Items\n }\n | InfoTableSection[]\n}\n\nconst InfoTable: FunctionComponent<InfoTableProps> = ({table}) => {\n const sections = Array.isArray(table)\n ? table\n : Object.keys(table).map((header) => ({\n header,\n items: table[header]!,\n color: undefined,\n helperText: undefined,\n bullet: undefined,\n }))\n\n const headerColumnWidth = Math.max(\n ...sections.map((section) => {\n return Math.max(\n ...section.header.split('\\n').map((line) => {\n return line.length\n }),\n )\n }),\n )\n\n return (\n <Box flexDirection=\"column\">\n {sections.map((section, index) => (\n <Box key={index} marginBottom={index === sections.length - 1 ? 0 : 1} flexDirection=\"column\">\n {section.header.length > 0 && (\n <Box width={headerColumnWidth + 1}>\n <Text color={section.color} bold>\n {capitalize(section.header)}\n </Text>\n </Box>\n )}\n <Box flexGrow={1} flexDirection=\"column\" gap={1}>\n <List margin={false} items={section.items} color={section.color} bullet={section.bullet} />\n {section.helperText ? <Text color={section.color}>{section.helperText}</Text> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {InfoTable}\n"]}
1
+ {"version":3,"file":"InfoTable.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,IAAI,EAAC,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAC,UAAU,EAAC,MAAM,wCAAwC,CAAA;AACjE,OAAO,EAAyB,aAAa,EAAC,MAAM,qBAAqB,CAAA;AACzE,OAAO,EAAC,GAAG,EAAE,IAAI,EAAY,MAAM,KAAK,CAAA;AACxC,OAAO,KAA0B,MAAM,OAAO,CAAA;AAqB9C,MAAM,SAAS,GAAsC,CAAC,EAAC,KAAK,EAAC,EAAE,EAAE;IAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACnC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAClC,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,MAAM,CAAE;YACrB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,SAAS;YACjB,cAAc,EAAE,SAAS;SAC1B,CAAC,CAAC,CAAA;IAEP,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAChC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC1B,OAAO,IAAI,CAAC,GAAG,CACb,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzC,OAAO,IAAI,CAAC,MAAM,CAAA;QACpB,CAAC,CAAC,CACH,CAAA;IACH,CAAC,CAAC,CACH,CAAA;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,IACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAChC,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAC,QAAQ;QACzF,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAC5B,oBAAC,GAAG,IAAC,KAAK,EAAE,iBAAiB,GAAG,CAAC;YAC/B,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,UAC7B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CACtB,CACH,CACP;QACD,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,EAAC,GAAG,EAAE,CAAC;YAC5C,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtD,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK;gBACxB,oBAAC,aAAa,IAAC,IAAI,EAAE,EAAC,OAAO,EAAE,OAAO,CAAC,cAAc,EAAC,GAAI,CACrD,CACR,CAAC,CAAC,CAAC,CACF,oBAAC,IAAI,IAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAI,CAC5F;YACA,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAG,OAAO,CAAC,UAAU,CAAQ,CAAC,CAAC,CAAC,IAAI,CAChF,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,SAAS,EAAC,CAAA","sourcesContent":["import {CustomListItem, List} from '../List.js'\nimport {capitalize} from '../../../../../public/common/string.js'\nimport {InlineToken, TokenItem, TokenizedText} from '../TokenizedText.js'\nimport {Box, Text, TextProps} from 'ink'\nimport React, {FunctionComponent} from 'react'\n\ntype Items = (TokenItem<InlineToken> | CustomListItem)[]\n\nexport interface InfoTableSection {\n color?: TextProps['color']\n header: string\n bullet?: string\n helperText?: string\n items: Items\n emptyItemsText?: string\n}\n\nexport interface InfoTableProps {\n table:\n | {\n [header: string]: Items\n }\n | InfoTableSection[]\n}\n\nconst InfoTable: FunctionComponent<InfoTableProps> = ({table}) => {\n const sections = Array.isArray(table)\n ? table\n : Object.keys(table).map((header) => ({\n header,\n items: table[header]!,\n color: undefined,\n helperText: undefined,\n bullet: undefined,\n emptyItemsText: undefined,\n }))\n\n const headerColumnWidth = Math.max(\n ...sections.map((section) => {\n return Math.max(\n ...section.header.split('\\n').map((line) => {\n return line.length\n }),\n )\n }),\n )\n\n return (\n <Box flexDirection=\"column\">\n {sections.map((section, index) => (\n <Box key={index} marginBottom={index === sections.length - 1 ? 0 : 1} flexDirection=\"column\">\n {section.header.length > 0 && (\n <Box width={headerColumnWidth + 1}>\n <Text color={section.color} bold>\n {capitalize(section.header)}\n </Text>\n </Box>\n )}\n <Box flexGrow={1} flexDirection=\"column\" gap={1}>\n {section.emptyItemsText && section.items.length === 0 ? (\n <Text color={section.color}>\n <TokenizedText item={{subdued: section.emptyItemsText}} />\n </Text>\n ) : (\n <List margin={false} items={section.items} color={section.color} bullet={section.bullet} />\n )}\n {section.helperText ? <Text color={section.color}>{section.helperText}</Text> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {InfoTable}\n"]}
@@ -28,5 +28,31 @@ describe('InfoTable', async () => {
28
28
  • items"
29
29
  `);
30
30
  });
31
+ test('when the list of items has elements doesnt render the empty message', async () => {
32
+ const { lastFrame } = render(React.createElement(InfoTable, { table: [
33
+ {
34
+ header: 'header',
35
+ items: ['item'],
36
+ emptyItemsText: 'empty',
37
+ },
38
+ ] }));
39
+ expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
40
+ "Header
41
+ • item"
42
+ `);
43
+ });
44
+ test('when the list of items is empty renders the empty message subdued if set', async () => {
45
+ const { lastFrame } = render(React.createElement(InfoTable, { table: [
46
+ {
47
+ header: 'header',
48
+ items: [],
49
+ emptyItemsText: 'empty',
50
+ },
51
+ ] }));
52
+ expect(lastFrame()).toMatchInlineSnapshot(`
53
+ "Header
54
+ empty"
55
+ `);
56
+ });
31
57
  });
32
58
  //# sourceMappingURL=InfoTable.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InfoTable.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,sCAAsC,CAAA;AAC7D,OAAO,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;gBAC7B,4BAA4B,EAAE,CAAC,CAAC,UAAU,EAAE,EAAC,IAAI,EAAE,EAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,qBAAqB,EAAC,EAAC,CAAC,CAAC;aACrG,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;KAQpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;aACtB,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;KAGpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {InfoTable} from './InfoTable.js'\nimport {unstyled} from '../../../../../public/node/output.js'\nimport {render} from '../../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('InfoTable', async () => {\n test('renders a horizontal table with bullet points', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n 'header 1': ['some', 'items'],\n 'header 2\\nlonger text here': [['one item', {link: {label: 'Shopify', url: 'https://shopify.com'}}]],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Header 1\n • some\n • items\n\n Header 2\n longer text here\n • one item Shopify ( https://shopify.com )\"\n `)\n })\n\n test('supports an empty header value', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n '': ['some', 'items'],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"• some\n • items\"\n `)\n })\n})\n"]}
1
+ {"version":3,"file":"InfoTable.test.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Prompts/InfoTable.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,sCAAsC,CAAA;AAC7D,OAAO,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAA;AAC7C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;gBAC7B,4BAA4B,EAAE,CAAC,CAAC,UAAU,EAAE,EAAC,IAAI,EAAE,EAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,qBAAqB,EAAC,EAAC,CAAC,CAAC;aACrG,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;KAQpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;aACtB,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;KAGpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL;oBACE,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,CAAC,MAAM,CAAC;oBACf,cAAc,EAAE,OAAO;iBACxB;aACF,GACD,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;KAGpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QAC1F,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CACxB,oBAAC,SAAS,IACR,KAAK,EAAE;gBACL;oBACE,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,EAAE;oBACT,cAAc,EAAE,OAAO;iBACxB;aACF,GACD,CACH,CAAA;QAED,MAAM,CAAC,SAAS,EAAG,CAAC,CAAC,qBAAqB,CAAC;;;KAG1C,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {InfoTable} from './InfoTable.js'\nimport {unstyled} from '../../../../../public/node/output.js'\nimport {render} from '../../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('InfoTable', async () => {\n test('renders a horizontal table with bullet points', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n 'header 1': ['some', 'items'],\n 'header 2\\nlonger text here': [['one item', {link: {label: 'Shopify', url: 'https://shopify.com'}}]],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Header 1\n • some\n • items\n\n Header 2\n longer text here\n • one item Shopify ( https://shopify.com )\"\n `)\n })\n\n test('supports an empty header value', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={{\n '': ['some', 'items'],\n }}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"• some\n • items\"\n `)\n })\n\n test('when the list of items has elements doesnt render the empty message', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={[\n {\n header: 'header',\n items: ['item'],\n emptyItemsText: 'empty',\n },\n ]}\n />,\n )\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Header\n • item\"\n `)\n })\n\n test('when the list of items is empty renders the empty message subdued if set', async () => {\n const {lastFrame} = render(\n <InfoTable\n table={[\n {\n header: 'header',\n items: [],\n emptyItemsText: 'empty',\n },\n ]}\n />,\n )\n\n expect(lastFrame()!).toMatchInlineSnapshot(`\n \"\u001b[1mHeader\u001b[22m\n \u001b[2mempty\u001b[22m\"\n `)\n })\n})\n"]}
@@ -63,3 +63,10 @@ export declare function getPathValue<T = object>(object: object, path: string):
63
63
  * @returns - Returns object.
64
64
  */
65
65
  export declare function setPathValue(object: object, path: string, value?: unknown): object;
66
+ /**
67
+ * Checks if value is an empty object, collection, map, or set.
68
+ *
69
+ * @param object - The value to check.
70
+ * @returns - Returns true if value is empty, else false.
71
+ */
72
+ export declare function isEmpty(object: object): boolean;
@@ -89,4 +89,14 @@ export function setPathValue(object, path, value) {
89
89
  const set = require('lodash/set.js');
90
90
  return set(object, path, value);
91
91
  }
92
+ /**
93
+ * Checks if value is an empty object, collection, map, or set.
94
+ *
95
+ * @param object - The value to check.
96
+ * @returns - Returns true if value is empty, else false.
97
+ */
98
+ export function isEmpty(object) {
99
+ const isEmpty = require('lodash/isEmpty.js');
100
+ return isEmpty(object);
101
+ }
92
102
  //# sourceMappingURL=object.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"object.js","sourceRoot":"","sources":["../../../src/public/common/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,+BAA+B,CAAA;AAChE,OAAO,SAAS,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AAEpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAgB,EAChB,GAAgB,EAChB,qBAAyF,kBAAkB;IAE3G,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAC,UAAU,EAAE,kBAAkB,EAAC,CAAC,CAAA;AAC9D,CAAC;AAED;;;;;;;GAOG;AACH,gEAAgE;AAChE,MAAM,UAAU,MAAM,CACpB,MAAwC,EACxC,SAA+B;IAE/B,MAAM,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAChD,OAAO,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CACvB,MAA4B,EAC5B,QAAoC;IAEpC,MAAM,eAAe,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACtD,OAAO,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,aAAa,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAClD,OAAO,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,GAAW;IACrD,MAAM,cAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAA;IAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;IACvE,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;IACxE,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAa,MAAc,EAAE,IAAY;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAEpC,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAO,CAAA;AAC/E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY,EAAE,KAAe;IACxE,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAEpC,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACjC,CAAC","sourcesContent":["import {unionArrayStrategy} from '../../private/common/array.js'\nimport deepMerge from 'deepmerge'\nimport {Dictionary, ObjectIterator, ValueKeyIteratee} from 'lodash'\nimport {createRequire} from 'module'\n\nconst require = createRequire(import.meta.url)\n\n/**\n * Deep merges the two objects and returns a new object with the merge result.\n *\n * @param lhs - One of the objects to be merged.\n * @param rhs - Another object to be merged.\n * @param arrayMergeStrategy - Strategy used to merge the array typed fields. Union strategy is used by default to avoid\n * duplicated elements.\n * @returns A Javascrip tobject with th emerged objects.\n */\nexport function deepMergeObjects<T1, T2>(\n lhs: Partial<T1>,\n rhs: Partial<T2>,\n arrayMergeStrategy: (destinationArray: unknown[], sourceArray: unknown[]) => unknown[] = unionArrayStrategy,\n): T1 & T2 {\n return deepMerge(lhs, rhs, {arrayMerge: arrayMergeStrategy})\n}\n\n/**\n * Creates an object composed of the `object` properties `predicate` returns\n * truthy for. The predicate is invoked with two arguments: (value, key).\n *\n * @param object - The source object.\n * @param predicate - The function invoked per property.\n * @returns Returns the new object.\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function pickBy<T, S extends T>(\n object: Dictionary<T> | null | undefined,\n predicate?: ValueKeyIteratee<T>,\n): Dictionary<S> {\n const lodashPickBy = require('lodash/pickBy.js')\n return lodashPickBy(object, predicate)\n}\n\n/**\n * Creates an object with the same keys as object and values generated by running each own\n * enumerable property of object through iteratee. The iteratee function is\n * invoked with three arguments: (value, key, object).\n *\n * @param source - The object to iterate over.\n * @param callback - The function invoked per iteration.\n * @returns Returns the new mapped object.\n */\nexport function mapValues<T extends object, TResult>(\n source: T | null | undefined,\n callback: ObjectIterator<T, TResult>,\n): {[P in keyof T]: TResult} {\n const lodashMapValues = require('lodash/mapValues.js')\n return lodashMapValues(source, callback)\n}\n\n/**\n * Deeply compares two objects and returns true if they are equal.\n *\n * @param one - The first object to be compared.\n * @param two - The second object to be compared.\n * @returns True if the objects are equal, false otherwise.\n */\nexport function deepCompare(one: object, two: object): boolean {\n const lodashIsEqual = require('lodash/isEqual.js')\n return lodashIsEqual(one, two)\n}\n\n/**\n * Return the difference between two nested objects.\n *\n * @param one - The first object to be compared.\n * @param two - The second object to be compared.\n * @returns Two objects containing the fields that are different, each one with the values of one object.\n */\nexport function deepDifference(one: object, two: object): [object, object] {\n const differenceWith = require('lodash/differenceWith.js')\n const fromPairs = require('lodash/fromPairs.js')\n const toPairs = require('lodash/toPairs.js')\n const changes = differenceWith(toPairs(one), toPairs(two), deepCompare)\n const changes2 = differenceWith(toPairs(two), toPairs(one), deepCompare)\n return [fromPairs(changes), fromPairs(changes2)]\n}\n\n/**\n * Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns - Returns the resolved value.\n */\nexport function getPathValue<T = object>(object: object, path: string): T | undefined {\n const get = require('lodash/get.js')\n\n return get(object, path) === undefined ? undefined : (get(object, path) as T)\n}\n\n/**\n * Sets the value at path of object. If a portion of path doesn't exist, it's create.\n *\n * @param object - The object to modify.\n * @param path - The path of the property to set.\n * @param value - The value to set.\n * @returns - Returns object.\n */\nexport function setPathValue(object: object, path: string, value?: unknown): object {\n const set = require('lodash/set.js')\n\n return set(object, path, value)\n}\n"]}
1
+ {"version":3,"file":"object.js","sourceRoot":"","sources":["../../../src/public/common/object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,+BAA+B,CAAA;AAChE,OAAO,SAAS,MAAM,WAAW,CAAA;AAEjC,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AAEpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAgB,EAChB,GAAgB,EAChB,qBAAyF,kBAAkB;IAE3G,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAC,UAAU,EAAE,kBAAkB,EAAC,CAAC,CAAA;AAC9D,CAAC;AAED;;;;;;;GAOG;AACH,gEAAgE;AAChE,MAAM,UAAU,MAAM,CACpB,MAAwC,EACxC,SAA+B;IAE/B,MAAM,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAChD,OAAO,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CACvB,MAA4B,EAC5B,QAAoC;IAEpC,MAAM,eAAe,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACtD,OAAO,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,aAAa,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAClD,OAAO,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,GAAW;IACrD,MAAM,cAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAA;IAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;IACvE,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;IACxE,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAa,MAAc,EAAE,IAAY;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAEpC,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAO,CAAA;AAC/E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY,EAAE,KAAe;IACxE,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAEpC,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAE5C,OAAO,OAAO,CAAC,MAAM,CAAC,CAAA;AACxB,CAAC","sourcesContent":["import {unionArrayStrategy} from '../../private/common/array.js'\nimport deepMerge from 'deepmerge'\nimport {Dictionary, ObjectIterator, ValueKeyIteratee} from 'lodash'\nimport {createRequire} from 'module'\n\nconst require = createRequire(import.meta.url)\n\n/**\n * Deep merges the two objects and returns a new object with the merge result.\n *\n * @param lhs - One of the objects to be merged.\n * @param rhs - Another object to be merged.\n * @param arrayMergeStrategy - Strategy used to merge the array typed fields. Union strategy is used by default to avoid\n * duplicated elements.\n * @returns A Javascrip tobject with th emerged objects.\n */\nexport function deepMergeObjects<T1, T2>(\n lhs: Partial<T1>,\n rhs: Partial<T2>,\n arrayMergeStrategy: (destinationArray: unknown[], sourceArray: unknown[]) => unknown[] = unionArrayStrategy,\n): T1 & T2 {\n return deepMerge(lhs, rhs, {arrayMerge: arrayMergeStrategy})\n}\n\n/**\n * Creates an object composed of the `object` properties `predicate` returns\n * truthy for. The predicate is invoked with two arguments: (value, key).\n *\n * @param object - The source object.\n * @param predicate - The function invoked per property.\n * @returns Returns the new object.\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function pickBy<T, S extends T>(\n object: Dictionary<T> | null | undefined,\n predicate?: ValueKeyIteratee<T>,\n): Dictionary<S> {\n const lodashPickBy = require('lodash/pickBy.js')\n return lodashPickBy(object, predicate)\n}\n\n/**\n * Creates an object with the same keys as object and values generated by running each own\n * enumerable property of object through iteratee. The iteratee function is\n * invoked with three arguments: (value, key, object).\n *\n * @param source - The object to iterate over.\n * @param callback - The function invoked per iteration.\n * @returns Returns the new mapped object.\n */\nexport function mapValues<T extends object, TResult>(\n source: T | null | undefined,\n callback: ObjectIterator<T, TResult>,\n): {[P in keyof T]: TResult} {\n const lodashMapValues = require('lodash/mapValues.js')\n return lodashMapValues(source, callback)\n}\n\n/**\n * Deeply compares two objects and returns true if they are equal.\n *\n * @param one - The first object to be compared.\n * @param two - The second object to be compared.\n * @returns True if the objects are equal, false otherwise.\n */\nexport function deepCompare(one: object, two: object): boolean {\n const lodashIsEqual = require('lodash/isEqual.js')\n return lodashIsEqual(one, two)\n}\n\n/**\n * Return the difference between two nested objects.\n *\n * @param one - The first object to be compared.\n * @param two - The second object to be compared.\n * @returns Two objects containing the fields that are different, each one with the values of one object.\n */\nexport function deepDifference(one: object, two: object): [object, object] {\n const differenceWith = require('lodash/differenceWith.js')\n const fromPairs = require('lodash/fromPairs.js')\n const toPairs = require('lodash/toPairs.js')\n const changes = differenceWith(toPairs(one), toPairs(two), deepCompare)\n const changes2 = differenceWith(toPairs(two), toPairs(one), deepCompare)\n return [fromPairs(changes), fromPairs(changes2)]\n}\n\n/**\n * Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns - Returns the resolved value.\n */\nexport function getPathValue<T = object>(object: object, path: string): T | undefined {\n const get = require('lodash/get.js')\n\n return get(object, path) === undefined ? undefined : (get(object, path) as T)\n}\n\n/**\n * Sets the value at path of object. If a portion of path doesn't exist, it's create.\n *\n * @param object - The object to modify.\n * @param path - The path of the property to set.\n * @param value - The value to set.\n * @returns - Returns object.\n */\nexport function setPathValue(object: object, path: string, value?: unknown): object {\n const set = require('lodash/set.js')\n\n return set(object, path, value)\n}\n\n/**\n * Checks if value is an empty object, collection, map, or set.\n *\n * @param object - The value to check.\n * @returns - Returns true if value is empty, else false.\n */\nexport function isEmpty(object: object): boolean {\n const isEmpty = require('lodash/isEmpty.js')\n\n return isEmpty(object)\n}\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Perform an action optimistically. If it fails the first time, first initiate
3
+ * a provided recovery procedure, then retry the action. If it fails again,
4
+ * throw the error.
5
+ *
6
+ * This is useful for actions that may fail due to recoverable errors, such as
7
+ * an expired token that can be refreshed. In this case, the recovery procedure
8
+ * would refresh the token.
9
+ *
10
+ * @param performAction - The action to perform.
11
+ * @param recoveryProcedure - The recovery procedure to perform if the action
12
+ * fails the first time.
13
+ */
14
+ export declare function performActionWithRetryAfterRecovery<T>(performAction: () => Promise<T>, recoveryProcedure: () => Promise<unknown>): Promise<T>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Perform an action optimistically. If it fails the first time, first initiate
3
+ * a provided recovery procedure, then retry the action. If it fails again,
4
+ * throw the error.
5
+ *
6
+ * This is useful for actions that may fail due to recoverable errors, such as
7
+ * an expired token that can be refreshed. In this case, the recovery procedure
8
+ * would refresh the token.
9
+ *
10
+ * @param performAction - The action to perform.
11
+ * @param recoveryProcedure - The recovery procedure to perform if the action
12
+ * fails the first time.
13
+ */
14
+ export async function performActionWithRetryAfterRecovery(performAction, recoveryProcedure) {
15
+ let returnVal;
16
+ try {
17
+ returnVal = await performAction();
18
+ return returnVal;
19
+ // eslint-disable-next-line no-catch-all/no-catch-all
20
+ }
21
+ catch (err) {
22
+ // Run the provided recovery procedure, then retry the action
23
+ await recoveryProcedure();
24
+ return performAction();
25
+ }
26
+ }
27
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/public/common/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,aAA+B,EAC/B,iBAAyC;IAEzC,IAAI,SAAwB,CAAA;IAC5B,IAAI;QACF,SAAS,GAAG,MAAM,aAAa,EAAE,CAAA;QACjC,OAAO,SAAS,CAAA;QAChB,qDAAqD;KACtD;IAAC,OAAO,GAAG,EAAE;QACZ,6DAA6D;QAC7D,MAAM,iBAAiB,EAAE,CAAA;QACzB,OAAO,aAAa,EAAE,CAAA;KACvB;AACH,CAAC","sourcesContent":["/**\n * Perform an action optimistically. If it fails the first time, first initiate\n * a provided recovery procedure, then retry the action. If it fails again,\n * throw the error.\n *\n * This is useful for actions that may fail due to recoverable errors, such as\n * an expired token that can be refreshed. In this case, the recovery procedure\n * would refresh the token.\n *\n * @param performAction - The action to perform.\n * @param recoveryProcedure - The recovery procedure to perform if the action\n * fails the first time.\n */\nexport async function performActionWithRetryAfterRecovery<T>(\n performAction: () => Promise<T>,\n recoveryProcedure: () => Promise<unknown>,\n): Promise<T> {\n let returnVal: T | undefined\n try {\n returnVal = await performAction()\n return returnVal\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (err) {\n // Run the provided recovery procedure, then retry the action\n await recoveryProcedure()\n return performAction()\n }\n}\n"]}
@@ -1 +1 @@
1
- export declare const CLI_KIT_VERSION = "3.53.0";
1
+ export declare const CLI_KIT_VERSION = "3.54.0";
@@ -1,2 +1,2 @@
1
- export const CLI_KIT_VERSION = '3.53.0';
1
+ export const CLI_KIT_VERSION = '3.54.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,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.53.0'\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.54.0'\n"]}
@@ -91,7 +91,7 @@ async function buildPayload({ config, errorMessage, exitMode }) {
91
91
  time_start: startTime,
92
92
  time_end: currentTime,
93
93
  total_time: wallClockElapsed,
94
- success: errorMessage === undefined,
94
+ success: exitMode === 'ok' && errorMessage === undefined,
95
95
  cli_version: CLI_KIT_VERSION,
96
96
  ruby_version: (await rubyVersion()) || '',
97
97
  node_version: process.version.replace('v', ''),
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/public/node/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {version as rubyVersion} from './ruby.js'\nimport {alwaysLogAnalytics, alwaysLogMetrics, analyticsDisabled, isShopify} from './context/local.js'\nimport * as metadata from './metadata.js'\nimport {publishMonorailEvent, MONORAIL_COMMAND_TOPIC} from './monorail.js'\nimport {fanoutHooks} from './plugins.js'\n\nimport {outputContent, outputDebug, outputToken} from '../../public/node/output.js'\nimport {getEnvironmentData, getSensitiveEnvironmentData} from '../../private/node/analytics.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {recordMetrics} from '../../private/node/otel-metrics.js'\nimport {Interfaces} from '@oclif/core'\n\nexport type CommandExitMode =\n // The command completed successfully\n | 'ok'\n // The command exited for some unexpected reason -- i.e. a bug\n | 'unexpected_error'\n // The command exited with an error, but its one we expect and doesn't point to a bug -- i.e. malformed config files\n | 'expected_error'\n\ninterface ReportAnalyticsEventOptions {\n config: Interfaces.Config\n errorMessage?: string\n exitMode: CommandExitMode\n}\n\n/**\n * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.\n *\n * The payload for an event includes both generic data, and data gathered from installed plug-ins.\n *\n */\nexport async function reportAnalyticsEvent(options: ReportAnalyticsEventOptions): Promise<void> {\n try {\n const payload = await buildPayload(options)\n if (payload === undefined) {\n // Nothing to log\n return\n }\n\n const skipMonorailAnalytics = !alwaysLogAnalytics() && analyticsDisabled()\n const skipMetricAnalytics = !alwaysLogMetrics() && analyticsDisabled()\n if (skipMonorailAnalytics || skipMetricAnalytics) {\n outputDebug(outputContent`Skipping command analytics, payload: ${outputToken.json(payload)}`)\n }\n\n const doMonorail = async () => {\n if (skipMonorailAnalytics) {\n return\n }\n const response = await publishMonorailEvent(MONORAIL_COMMAND_TOPIC, payload.public, payload.sensitive)\n if (response.type === 'error') {\n outputDebug(response.message)\n }\n }\n const doOpenTelemetry = async () => {\n const active = payload.public.cmd_all_timing_active_ms || 0\n const network = payload.public.cmd_all_timing_network_ms || 0\n const prompt = payload.public.cmd_all_timing_prompts_ms || 0\n\n return recordMetrics(\n {\n skipMetricAnalytics,\n cliVersion: payload.public.cli_version,\n owningPlugin: payload.public.cmd_all_plugin || '@shopify/cli',\n command: payload.public.command,\n exitMode: options.exitMode,\n },\n {\n active,\n network,\n prompt,\n },\n )\n }\n await Promise.all([doMonorail(), doOpenTelemetry()])\n\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n outputDebug(message)\n }\n}\n\nasync function buildPayload({config, errorMessage, exitMode}: ReportAnalyticsEventOptions) {\n const {commandStartOptions, environmentFlags, ...sensitiveMetadata} = metadata.getAllSensitiveMetadata()\n if (commandStartOptions === undefined) {\n outputDebug('Unable to log analytics event - no information on executed command')\n return\n }\n const {startCommand, startArgs, startTime} = commandStartOptions\n const currentTime = new Date().getTime()\n\n const {'@shopify/app': appPublic, ...otherPluginsPublic} = await fanoutHooks(config, 'public_command_metadata', {})\n const {'@shopify/app': appSensitive, ...otherPluginsSensitive} = await fanoutHooks(\n config,\n 'sensitive_command_metadata',\n {},\n )\n\n const environmentData = await getEnvironmentData(config)\n const sensitiveEnvironmentData = await getSensitiveEnvironmentData(config)\n const publicMetadata = metadata.getAllPublicMetadata()\n\n // Automatically calculate the total time spent in the command, excluding time spent in subtimers.\n const subTimers = ['cmd_all_timing_network_ms', 'cmd_all_timing_prompts_ms'] as const\n const totalTimeFromSubtimers = subTimers.reduce((total, timer) => {\n const value = publicMetadata[timer]\n if (value !== undefined) {\n return total + value\n }\n return total\n }, 0)\n const wallClockElapsed = currentTime - startTime\n const totalTimeWithoutSubtimers = wallClockElapsed - totalTimeFromSubtimers\n\n let payload = {\n public: {\n command: startCommand,\n time_start: startTime,\n time_end: currentTime,\n total_time: wallClockElapsed,\n success: errorMessage === undefined,\n cli_version: CLI_KIT_VERSION,\n ruby_version: (await rubyVersion()) || '',\n node_version: process.version.replace('v', ''),\n is_employee: await isShopify(),\n ...environmentData,\n ...appPublic,\n ...publicMetadata,\n cmd_all_timing_active_ms: totalTimeWithoutSubtimers,\n cmd_all_exit: exitMode,\n },\n sensitive: {\n args: startArgs.join(' '),\n cmd_all_environment_flags: environmentFlags,\n error_message: errorMessage,\n ...appSensitive,\n ...sensitiveEnvironmentData,\n metadata: JSON.stringify({\n ...sensitiveMetadata,\n extraPublic: {\n ...otherPluginsPublic,\n },\n extraSensitive: {...otherPluginsSensitive},\n }),\n },\n }\n\n // round down timing metrics\n const timingMetrics = ['cmd_all_timing_active_ms', 'cmd_all_timing_network_ms', 'cmd_all_timing_prompts_ms'] as const\n timingMetrics.forEach((metric) => {\n const current = payload.public[metric]\n if (current !== undefined) {\n payload.public[metric] = Math.floor(current)\n }\n })\n\n // strip undefined fields -- they make up the majority of payloads due to wide metadata structure.\n payload = JSON.parse(JSON.stringify(payload))\n\n return sanitizePayload(payload)\n}\n\nfunction sanitizePayload<T>(payload: T): T {\n const payloadString = JSON.stringify(payload)\n // Remove Theme Access passwords from the payload\n const sanitizedPayloadString = payloadString.replace(/shptka_\\w*/g, '*****')\n return JSON.parse(sanitizedPayloadString)\n}\n"]}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/public/node/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {version as rubyVersion} from './ruby.js'\nimport {alwaysLogAnalytics, alwaysLogMetrics, analyticsDisabled, isShopify} from './context/local.js'\nimport * as metadata from './metadata.js'\nimport {publishMonorailEvent, MONORAIL_COMMAND_TOPIC} from './monorail.js'\nimport {fanoutHooks} from './plugins.js'\n\nimport {outputContent, outputDebug, outputToken} from '../../public/node/output.js'\nimport {getEnvironmentData, getSensitiveEnvironmentData} from '../../private/node/analytics.js'\nimport {CLI_KIT_VERSION} from '../common/version.js'\nimport {recordMetrics} from '../../private/node/otel-metrics.js'\nimport {Interfaces} from '@oclif/core'\n\nexport type CommandExitMode =\n // The command completed successfully\n | 'ok'\n // The command exited for some unexpected reason -- i.e. a bug\n | 'unexpected_error'\n // The command exited with an error, but its one we expect and doesn't point to a bug -- i.e. malformed config files\n | 'expected_error'\n\ninterface ReportAnalyticsEventOptions {\n config: Interfaces.Config\n errorMessage?: string\n exitMode: CommandExitMode\n}\n\n/**\n * Report an analytics event, sending it off to Monorail -- Shopify's internal analytics service.\n *\n * The payload for an event includes both generic data, and data gathered from installed plug-ins.\n *\n */\nexport async function reportAnalyticsEvent(options: ReportAnalyticsEventOptions): Promise<void> {\n try {\n const payload = await buildPayload(options)\n if (payload === undefined) {\n // Nothing to log\n return\n }\n\n const skipMonorailAnalytics = !alwaysLogAnalytics() && analyticsDisabled()\n const skipMetricAnalytics = !alwaysLogMetrics() && analyticsDisabled()\n if (skipMonorailAnalytics || skipMetricAnalytics) {\n outputDebug(outputContent`Skipping command analytics, payload: ${outputToken.json(payload)}`)\n }\n\n const doMonorail = async () => {\n if (skipMonorailAnalytics) {\n return\n }\n const response = await publishMonorailEvent(MONORAIL_COMMAND_TOPIC, payload.public, payload.sensitive)\n if (response.type === 'error') {\n outputDebug(response.message)\n }\n }\n const doOpenTelemetry = async () => {\n const active = payload.public.cmd_all_timing_active_ms || 0\n const network = payload.public.cmd_all_timing_network_ms || 0\n const prompt = payload.public.cmd_all_timing_prompts_ms || 0\n\n return recordMetrics(\n {\n skipMetricAnalytics,\n cliVersion: payload.public.cli_version,\n owningPlugin: payload.public.cmd_all_plugin || '@shopify/cli',\n command: payload.public.command,\n exitMode: options.exitMode,\n },\n {\n active,\n network,\n prompt,\n },\n )\n }\n await Promise.all([doMonorail(), doOpenTelemetry()])\n\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n let message = 'Failed to report usage analytics'\n if (error instanceof Error) {\n message = message.concat(`: ${error.message}`)\n }\n outputDebug(message)\n }\n}\n\nasync function buildPayload({config, errorMessage, exitMode}: ReportAnalyticsEventOptions) {\n const {commandStartOptions, environmentFlags, ...sensitiveMetadata} = metadata.getAllSensitiveMetadata()\n if (commandStartOptions === undefined) {\n outputDebug('Unable to log analytics event - no information on executed command')\n return\n }\n const {startCommand, startArgs, startTime} = commandStartOptions\n const currentTime = new Date().getTime()\n\n const {'@shopify/app': appPublic, ...otherPluginsPublic} = await fanoutHooks(config, 'public_command_metadata', {})\n const {'@shopify/app': appSensitive, ...otherPluginsSensitive} = await fanoutHooks(\n config,\n 'sensitive_command_metadata',\n {},\n )\n\n const environmentData = await getEnvironmentData(config)\n const sensitiveEnvironmentData = await getSensitiveEnvironmentData(config)\n const publicMetadata = metadata.getAllPublicMetadata()\n\n // Automatically calculate the total time spent in the command, excluding time spent in subtimers.\n const subTimers = ['cmd_all_timing_network_ms', 'cmd_all_timing_prompts_ms'] as const\n const totalTimeFromSubtimers = subTimers.reduce((total, timer) => {\n const value = publicMetadata[timer]\n if (value !== undefined) {\n return total + value\n }\n return total\n }, 0)\n const wallClockElapsed = currentTime - startTime\n const totalTimeWithoutSubtimers = wallClockElapsed - totalTimeFromSubtimers\n\n let payload = {\n public: {\n command: startCommand,\n time_start: startTime,\n time_end: currentTime,\n total_time: wallClockElapsed,\n success: exitMode === 'ok' && errorMessage === undefined,\n cli_version: CLI_KIT_VERSION,\n ruby_version: (await rubyVersion()) || '',\n node_version: process.version.replace('v', ''),\n is_employee: await isShopify(),\n ...environmentData,\n ...appPublic,\n ...publicMetadata,\n cmd_all_timing_active_ms: totalTimeWithoutSubtimers,\n cmd_all_exit: exitMode,\n },\n sensitive: {\n args: startArgs.join(' '),\n cmd_all_environment_flags: environmentFlags,\n error_message: errorMessage,\n ...appSensitive,\n ...sensitiveEnvironmentData,\n metadata: JSON.stringify({\n ...sensitiveMetadata,\n extraPublic: {\n ...otherPluginsPublic,\n },\n extraSensitive: {...otherPluginsSensitive},\n }),\n },\n }\n\n // round down timing metrics\n const timingMetrics = ['cmd_all_timing_active_ms', 'cmd_all_timing_network_ms', 'cmd_all_timing_prompts_ms'] as const\n timingMetrics.forEach((metric) => {\n const current = payload.public[metric]\n if (current !== undefined) {\n payload.public[metric] = Math.floor(current)\n }\n })\n\n // strip undefined fields -- they make up the majority of payloads due to wide metadata structure.\n payload = JSON.parse(JSON.stringify(payload))\n\n return sanitizePayload(payload)\n}\n\nfunction sanitizePayload<T>(payload: T): T {\n const payloadString = JSON.stringify(payload)\n // Remove Theme Access passwords from the payload\n const sanitizedPayloadString = payloadString.replace(/shptka_\\w*/g, '*****')\n return JSON.parse(sanitizedPayloadString)\n}\n"]}
@@ -8,18 +8,26 @@ import { GraphQLVariables, GraphQLResponse } from './graphql.js';
8
8
  * @returns The response of the query of generic type <T>.
9
9
  */
10
10
  export declare function partnersRequest<T>(query: string, token: string, variables?: GraphQLVariables): Promise<T>;
11
+ export interface FunctionUploadUrlGenerateResponse {
12
+ functionUploadUrlGenerate: {
13
+ generatedUrlDetails: {
14
+ url: string;
15
+ moduleId: string;
16
+ headers: {
17
+ [key: string]: string;
18
+ };
19
+ maxBytes: number;
20
+ maxSize: string;
21
+ };
22
+ };
23
+ }
11
24
  /**
12
- * Function queries are proxied through the script service proxy.
13
- * To execute a query, we encapsulate it inside another query (including the variables)
14
- * This is done automatically, you just need to provide the query and the variables.
25
+ * Request a URL from partners to which we will upload our function.
15
26
  *
16
- * @param apiKey - APIKey of the app where the query will be executed.
17
- * @param query - GraphQL query to execute.
18
27
  * @param token - Partners token.
19
- * @param variables - GraphQL variables to pass to the query.
20
28
  * @returns The response of the query.
21
29
  */
22
- export declare function functionProxyRequest<T>(apiKey: string, query: unknown, token: string, variables?: unknown): Promise<T>;
30
+ export declare function getFunctionUploadUrl(token: string): Promise<FunctionUploadUrlGenerateResponse>;
23
31
  /**
24
32
  * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)
25
33
  * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).
@@ -33,31 +33,27 @@ export async function partnersRequest(query, token, variables) {
33
33
  return result;
34
34
  }
35
35
  /**
36
- * Function queries are proxied through the script service proxy.
37
- * To execute a query, we encapsulate it inside another query (including the variables)
38
- * This is done automatically, you just need to provide the query and the variables.
36
+ * Request a URL from partners to which we will upload our function.
39
37
  *
40
- * @param apiKey - APIKey of the app where the query will be executed.
41
- * @param query - GraphQL query to execute.
42
38
  * @param token - Partners token.
43
- * @param variables - GraphQL variables to pass to the query.
44
39
  * @returns The response of the query.
45
40
  */
46
- export async function functionProxyRequest(apiKey, query, token, variables) {
47
- const proxyVariables = {
48
- api_key: apiKey,
49
- query,
50
- variables: JSON.stringify(variables) || '{}',
51
- };
52
- const proxyQuery = ScriptServiceProxyQuery;
53
- const res = await partnersRequest(proxyQuery, token, proxyVariables);
54
- const json = JSON.parse(res.scriptServiceProxy);
55
- handleDeprecations(json);
56
- return json;
41
+ export async function getFunctionUploadUrl(token) {
42
+ const functionUploadUrlGenerateMutation = FunctionUploadUrlGenerateMutation;
43
+ const res = await partnersRequest(FunctionUploadUrlGenerateMutation, token);
44
+ return res;
57
45
  }
58
- const ScriptServiceProxyQuery = gql `
59
- query ProxyRequest($api_key: String, $query: String!, $variables: String) {
60
- scriptServiceProxy(apiKey: $api_key, query: $query, variables: $variables)
46
+ const FunctionUploadUrlGenerateMutation = gql `
47
+ mutation functionUploadUrlGenerateMutation {
48
+ functionUploadUrlGenerate {
49
+ generatedUrlDetails {
50
+ url
51
+ moduleId
52
+ headers
53
+ maxBytes
54
+ maxSize
55
+ }
56
+ }
61
57
  }
62
58
  `;
63
59
  /**