@shopify/cli-kit 3.70.0 → 3.71.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 (85) hide show
  1. package/dist/cli/api/graphql/admin/generated/theme_files_upsert.d.ts +21 -0
  2. package/dist/cli/api/graphql/admin/generated/theme_files_upsert.js +82 -0
  3. package/dist/cli/api/graphql/admin/generated/theme_files_upsert.js.map +1 -0
  4. package/dist/private/node/api.d.ts +1 -1
  5. package/dist/private/node/api.js +30 -2
  6. package/dist/private/node/api.js.map +1 -1
  7. package/dist/private/node/constants.d.ts +2 -0
  8. package/dist/private/node/constants.js +2 -0
  9. package/dist/private/node/constants.js.map +1 -1
  10. package/dist/private/node/session/exchange.js +2 -2
  11. package/dist/private/node/session/exchange.js.map +1 -1
  12. package/dist/private/node/session/scopes.js +3 -5
  13. package/dist/private/node/session/scopes.js.map +1 -1
  14. package/dist/private/node/session.js +2 -3
  15. package/dist/private/node/session.js.map +1 -1
  16. package/dist/private/node/ui/alert.js +1 -3
  17. package/dist/private/node/ui/alert.js.map +1 -1
  18. package/dist/private/node/ui/components/ConcurrentOutput.js +0 -2
  19. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  20. package/dist/private/node/ui/components/Link.js +3 -0
  21. package/dist/private/node/ui/components/Link.js.map +1 -1
  22. package/dist/private/node/ui/components/Link.test.js +23 -0
  23. package/dist/private/node/ui/components/Link.test.js.map +1 -1
  24. package/dist/private/node/ui.js +1 -1
  25. package/dist/private/node/ui.js.map +1 -1
  26. package/dist/public/common/version.d.ts +1 -1
  27. package/dist/public/common/version.js +1 -1
  28. package/dist/public/common/version.js.map +1 -1
  29. package/dist/public/node/api/admin.js +11 -1
  30. package/dist/public/node/api/admin.js.map +1 -1
  31. package/dist/public/node/api/graphql.d.ts +2 -0
  32. package/dist/public/node/api/graphql.js +2 -2
  33. package/dist/public/node/api/graphql.js.map +1 -1
  34. package/dist/public/node/api/webhooks.d.ts +13 -0
  35. package/dist/public/node/api/webhooks.js +34 -0
  36. package/dist/public/node/api/webhooks.js.map +1 -0
  37. package/dist/public/node/cli-launcher.d.ts +12 -0
  38. package/dist/public/node/cli-launcher.js +29 -0
  39. package/dist/public/node/cli-launcher.js.map +1 -0
  40. package/dist/public/node/cli.d.ts +12 -10
  41. package/dist/public/node/cli.js +38 -100
  42. package/dist/public/node/cli.js.map +1 -1
  43. package/dist/public/node/context/fqdn.js +11 -7
  44. package/dist/public/node/context/fqdn.js.map +1 -1
  45. package/dist/public/node/context/local.d.ts +7 -0
  46. package/dist/public/node/context/local.js +9 -0
  47. package/dist/public/node/context/local.js.map +1 -1
  48. package/dist/public/node/environment.d.ts +7 -0
  49. package/dist/public/node/environment.js +11 -0
  50. package/dist/public/node/environment.js.map +1 -1
  51. package/dist/public/node/error-handler.js +1 -3
  52. package/dist/public/node/error-handler.js.map +1 -1
  53. package/dist/public/node/hooks/prerun.js +0 -2
  54. package/dist/public/node/hooks/prerun.js.map +1 -1
  55. package/dist/public/node/json-schema.d.ts +2 -1
  56. package/dist/public/node/json-schema.js +8 -3
  57. package/dist/public/node/json-schema.js.map +1 -1
  58. package/dist/public/node/notifications-system.d.ts +3 -1
  59. package/dist/public/node/notifications-system.js +9 -1
  60. package/dist/public/node/notifications-system.js.map +1 -1
  61. package/dist/public/node/output.d.ts +1 -6
  62. package/dist/public/node/output.js +1 -5
  63. package/dist/public/node/output.js.map +1 -1
  64. package/dist/public/node/path.d.ts +3 -3
  65. package/dist/public/node/path.js +4 -5
  66. package/dist/public/node/path.js.map +1 -1
  67. package/dist/public/node/system.js +14 -2
  68. package/dist/public/node/system.js.map +1 -1
  69. package/dist/public/node/themes/api.js +67 -8
  70. package/dist/public/node/themes/api.js.map +1 -1
  71. package/dist/public/node/themes/factories.d.ts +1 -3
  72. package/dist/public/node/themes/factories.js +0 -16
  73. package/dist/public/node/themes/factories.js.map +1 -1
  74. package/dist/public/node/tree-kill.js +0 -2
  75. package/dist/public/node/tree-kill.js.map +1 -1
  76. package/dist/public/node/ui.js +30 -80
  77. package/dist/public/node/ui.js.map +1 -1
  78. package/dist/public/node/vendor/dev_server/DevServer.d.ts +19 -0
  79. package/dist/public/node/vendor/dev_server/DevServer.js +170 -0
  80. package/dist/public/node/vendor/dev_server/DevServer.js.map +1 -0
  81. package/dist/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +7 -4
  83. package/dist/private/node/demo-recorder.d.ts +0 -17
  84. package/dist/private/node/demo-recorder.js +0 -121
  85. package/dist/private/node/demo-recorder.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopify/cli-kit",
3
- "version": "3.70.0",
3
+ "version": "3.71.0",
4
4
  "private": false,
5
5
  "description": "A set of utilities, interfaces, and models that are common across all the platform features",
6
6
  "keywords": [
@@ -48,7 +48,8 @@
48
48
  "../../.eslintrc.cjs"
49
49
  ],
50
50
  "ignorePatterns": [
51
- "**/vendor/otel-js/**/*.ts"
51
+ "**/vendor/otel-js/**/*.ts",
52
+ "**/vendor/dev_server/**/*.ts"
52
53
  ],
53
54
  "overrides": [
54
55
  {
@@ -66,7 +67,6 @@
66
67
  "./context/local.js",
67
68
  "./custom-oclif-loader.js",
68
69
  "@oclif/core",
69
- "../../private/node/constants.js",
70
70
  "./path.js",
71
71
  "./system.js",
72
72
  "./ui.js"
@@ -74,8 +74,8 @@
74
74
  "static": [
75
75
  "@oclif/core",
76
76
  "./context/utilities.js",
77
- "../../private/node/demo-recorder.js",
78
77
  "../../private/node/conf-store.js",
78
+ "../../private/node/constants.js",
79
79
  "url"
80
80
  ]
81
81
  }
@@ -129,6 +129,7 @@
129
129
  "macaddress": "0.5.3",
130
130
  "minimatch": "9.0.3",
131
131
  "mrmime": "1.0.1",
132
+ "network-interfaces": "1.1.0",
132
133
  "node-abort-controller": "3.1.1",
133
134
  "node-fetch": "3.3.2",
134
135
  "open": "8.4.2",
@@ -142,6 +143,7 @@
142
143
  "tempy": "3.0.0",
143
144
  "terminal-link": "3.0.0",
144
145
  "ts-error": "1.0.6",
146
+ "which": "4.0.0",
145
147
  "zod": "3.22.3"
146
148
  },
147
149
  "devDependencies": {
@@ -153,6 +155,7 @@
153
155
  "@types/node": "18.19.3",
154
156
  "@types/react": "18.2.0",
155
157
  "@types/semver": "^7.5.2",
158
+ "@types/which": "3.0.4",
156
159
  "@vitest/coverage-istanbul": "^1.6.0",
157
160
  "node-stream-zip": "^1.15.0",
158
161
  "ts-morph": "^17.0.1",
@@ -1,17 +0,0 @@
1
- interface Event {
2
- type: string;
3
- properties: {
4
- [key: string]: unknown;
5
- };
6
- concurrencyStart?: number;
7
- }
8
- export declare function initDemoRecorder(): void;
9
- export declare function recordUIEvent(event: Event): void;
10
- export declare function resetRecordedSleep(): void;
11
- export declare function printEventsJson(): void;
12
- export declare function addOrUpdateConcurrentUIEventOutput(data: {
13
- prefix: string;
14
- index: number;
15
- output: string;
16
- }): void;
17
- export {};
@@ -1,121 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import { isTruthy } from '../../public/node/context/utilities.js';
3
- class DemoRecorder {
4
- constructor() {
5
- this.recorded = [];
6
- this.sleepStart = Date.now();
7
- this.command = ['shopify', ...process.argv.slice(2)].join(' ');
8
- }
9
- addEvent({ type, properties }) {
10
- if (type === 'taskbar') {
11
- this.resetSleep();
12
- }
13
- else {
14
- this.addSleep();
15
- }
16
- this.recorded.push({ type, properties: JSON.parse(JSON.stringify(properties)) });
17
- this.sleepStart = Date.now();
18
- }
19
- recordedEventsJson() {
20
- return JSON.stringify({
21
- command: this.command,
22
- steps: this.withFormattedConcurrent(this.recorded),
23
- }, null, 2);
24
- }
25
- addSleep() {
26
- const duration = (Date.now() - this.sleepStart) / 1000;
27
- this.sleepStart = Date.now();
28
- if (duration > 0.1) {
29
- this.recorded.push({ type: 'sleep', properties: { duration } });
30
- }
31
- }
32
- resetSleep() {
33
- this.sleepStart = Date.now();
34
- }
35
- addOrUpdateConcurrentOutput({ prefix, index, output }) {
36
- let last = this.recorded[this.recorded.length - 1];
37
- if (last?.type === 'concurrent') {
38
- // Don't sleep between concurrent lines
39
- this.resetSleep();
40
- }
41
- else {
42
- const eventProperties = {
43
- type: 'concurrent',
44
- properties: { processes: [], concurrencyStart: Date.now() },
45
- };
46
- this.addEvent(eventProperties);
47
- last = this.recorded[this.recorded.length - 1];
48
- }
49
- const { processes } = last.properties;
50
- while (processes.length <= index) {
51
- processes.push({ prefix: '', steps: [] });
52
- }
53
- processes[index].prefix = prefix;
54
- processes[index].steps.push({ timestamp: Date.now(), endMessage: output });
55
- }
56
- withFormattedConcurrent(recorded) {
57
- return recorded.map((event) => {
58
- if (event.type === 'concurrent') {
59
- const { processes, footer, concurrencyStart } = event.properties;
60
- const formatted = processes.map(({ prefix, steps }) => {
61
- let mostRecentTimestamp = concurrencyStart;
62
- const formattedSteps = steps.map(({ timestamp, endMessage }) => {
63
- const duration = (timestamp - mostRecentTimestamp) / 1000;
64
- mostRecentTimestamp = timestamp;
65
- return { duration, endMessage };
66
- });
67
- return { prefix, steps: formattedSteps };
68
- });
69
- return { type: 'concurrent', properties: { footer, processes: formatted } };
70
- }
71
- return event;
72
- });
73
- }
74
- }
75
- class NoopDemoRecorder {
76
- addEvent(_event) { }
77
- recordedEventsJson() {
78
- return JSON.stringify({ steps: [] }, null, 2);
79
- }
80
- addSleep() { }
81
- resetSleep() { }
82
- addOrUpdateConcurrentOutput(..._args) { }
83
- }
84
- let _instance;
85
- function ensureInstance() {
86
- if (!_instance) {
87
- if (isRecording()) {
88
- _instance = new DemoRecorder();
89
- }
90
- else {
91
- _instance = new NoopDemoRecorder();
92
- }
93
- }
94
- }
95
- export function initDemoRecorder() {
96
- ensureInstance();
97
- }
98
- export function recordUIEvent(event) {
99
- ensureInstance();
100
- _instance.addEvent(event);
101
- }
102
- export function resetRecordedSleep() {
103
- ensureInstance();
104
- _instance.resetSleep();
105
- }
106
- export function printEventsJson() {
107
- if (isRecording()) {
108
- ensureInstance();
109
- _instance.addSleep();
110
- // eslint-disable-next-line no-console
111
- console.log(_instance.recordedEventsJson());
112
- }
113
- }
114
- export function addOrUpdateConcurrentUIEventOutput(data) {
115
- ensureInstance();
116
- _instance.addOrUpdateConcurrentOutput(data);
117
- }
118
- function isRecording() {
119
- return isTruthy(process.env.RECORD_DEMO);
120
- }
121
- //# sourceMappingURL=demo-recorder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"demo-recorder.js","sourceRoot":"","sources":["../../../src/private/node/demo-recorder.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport {isTruthy} from '../../public/node/context/utilities.js'\n\ninterface Event {\n type: string\n properties: {[key: string]: unknown}\n // Only used within this recorder for tracking concurrency timeline\n concurrencyStart?: number\n}\n\ninterface ConcurrencyStep {\n timestamp: number\n endMessage: string\n}\n\ninterface ConcurrencyProcess {\n prefix: string\n steps: ConcurrencyStep[]\n}\n\nclass DemoRecorder {\n recorded: Event[]\n sleepStart: number\n command: string\n\n constructor() {\n this.recorded = []\n this.sleepStart = Date.now()\n this.command = ['shopify', ...process.argv.slice(2)].join(' ')\n }\n\n addEvent({type, properties}: Event) {\n if (type === 'taskbar') {\n this.resetSleep()\n } else {\n this.addSleep()\n }\n this.recorded.push({type, properties: JSON.parse(JSON.stringify(properties))})\n this.sleepStart = Date.now()\n }\n\n recordedEventsJson() {\n return JSON.stringify(\n {\n command: this.command,\n steps: this.withFormattedConcurrent(this.recorded),\n },\n null,\n 2,\n )\n }\n\n addSleep() {\n const duration = (Date.now() - this.sleepStart) / 1000\n this.sleepStart = Date.now()\n if (duration > 0.1) {\n this.recorded.push({type: 'sleep', properties: {duration}})\n }\n }\n\n resetSleep() {\n this.sleepStart = Date.now()\n }\n\n addOrUpdateConcurrentOutput({prefix, index, output}: {prefix: string; index: number; output: string}) {\n let last = this.recorded[this.recorded.length - 1]\n if (last?.type === 'concurrent') {\n // Don't sleep between concurrent lines\n this.resetSleep()\n } else {\n const eventProperties: Event = {\n type: 'concurrent',\n properties: {processes: [], concurrencyStart: Date.now()},\n }\n this.addEvent(eventProperties)\n last = this.recorded[this.recorded.length - 1]\n }\n const {processes} = last!.properties as {processes: ConcurrencyProcess[]}\n while (processes.length <= index) {\n processes.push({prefix: '', steps: []})\n }\n processes[index]!.prefix = prefix\n processes[index]!.steps.push({timestamp: Date.now(), endMessage: output})\n }\n\n withFormattedConcurrent(recorded: Event[]) {\n return recorded.map((event) => {\n if (event.type === 'concurrent') {\n const {processes, footer, concurrencyStart} = event.properties as {\n processes: ConcurrencyProcess[]\n footer?: string\n concurrencyStart: number\n }\n const formatted = processes.map(({prefix, steps}: {prefix: string; steps: ConcurrencyStep[]}) => {\n let mostRecentTimestamp = concurrencyStart\n const formattedSteps = steps.map(({timestamp, endMessage}) => {\n const duration = (timestamp - mostRecentTimestamp) / 1000\n mostRecentTimestamp = timestamp\n return {duration, endMessage}\n })\n return {prefix, steps: formattedSteps}\n })\n return {type: 'concurrent', properties: {footer, processes: formatted}}\n }\n return event\n })\n }\n}\n\nclass NoopDemoRecorder {\n addEvent(_event: Event) {}\n\n recordedEventsJson() {\n return JSON.stringify({steps: []}, null, 2)\n }\n\n addSleep() {}\n resetSleep() {}\n\n addOrUpdateConcurrentOutput(..._args: unknown[]) {}\n}\n\nlet _instance: {\n addEvent: (event: Event) => void\n recordedEventsJson: () => string\n resetSleep: () => void\n addSleep: () => void\n addOrUpdateConcurrentOutput: ({prefix, index, output}: {prefix: string; index: number; output: string}) => void\n}\n\nfunction ensureInstance() {\n if (!_instance) {\n if (isRecording()) {\n _instance = new DemoRecorder()\n } else {\n _instance = new NoopDemoRecorder()\n }\n }\n}\n\nexport function initDemoRecorder() {\n ensureInstance()\n}\n\nexport function recordUIEvent(event: Event) {\n ensureInstance()\n _instance.addEvent(event)\n}\n\nexport function resetRecordedSleep() {\n ensureInstance()\n _instance.resetSleep()\n}\n\nexport function printEventsJson(): void {\n if (isRecording()) {\n ensureInstance()\n _instance.addSleep()\n // eslint-disable-next-line no-console\n console.log(_instance.recordedEventsJson())\n }\n}\n\nexport function addOrUpdateConcurrentUIEventOutput(data: {prefix: string; index: number; output: string}) {\n ensureInstance()\n _instance.addOrUpdateConcurrentOutput(data)\n}\n\nfunction isRecording() {\n return isTruthy(process.env.RECORD_DEMO)\n}\n"]}