@shopify/cli-hydrogen 7.1.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/hydrogen/build-vite.js +19 -10
- package/dist/commands/hydrogen/build.js +10 -2
- package/dist/commands/hydrogen/check.js +1 -0
- package/dist/commands/hydrogen/codegen.js +1 -0
- package/dist/commands/hydrogen/customer-account/push.js +170 -0
- package/dist/commands/hydrogen/debug/cpu.js +3 -0
- package/dist/commands/hydrogen/deploy.js +121 -36
- package/dist/commands/hydrogen/dev-vite.js +128 -59
- package/dist/commands/hydrogen/dev.js +108 -51
- package/dist/commands/hydrogen/env/list.js +7 -8
- package/dist/commands/hydrogen/env/pull.js +17 -1
- package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
- package/dist/commands/hydrogen/generate/route.js +1 -0
- package/dist/commands/hydrogen/init.js +45 -17
- package/dist/commands/hydrogen/link.js +20 -4
- package/dist/commands/hydrogen/list.js +1 -0
- package/dist/commands/hydrogen/login.js +1 -0
- package/dist/commands/hydrogen/logout.js +1 -0
- package/dist/commands/hydrogen/preview.js +31 -16
- package/dist/commands/hydrogen/setup/css.js +8 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -0
- package/dist/commands/hydrogen/setup/vite.js +244 -138
- package/dist/commands/hydrogen/setup.js +21 -22
- package/dist/commands/hydrogen/shortcut.js +10 -0
- package/dist/commands/hydrogen/unlink.js +1 -0
- package/dist/commands/hydrogen/upgrade.js +2 -1
- package/dist/generator-templates/assets/vite/package.json +3 -4
- package/dist/generator-templates/assets/vite/vite.config.js +10 -2
- package/dist/generator-templates/starter/CHANGELOG.md +89 -0
- package/dist/generator-templates/starter/README.md +3 -44
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
- package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
- package/dist/generator-templates/starter/app/root.tsx +2 -5
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
- package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
- package/dist/generator-templates/starter/package.json +14 -9
- package/dist/generator-templates/starter/server.ts +2 -1
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
- package/dist/generator-templates/starter/vite.config.ts +21 -0
- package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
- package/dist/lib/check-lockfile.js +12 -18
- package/dist/lib/codegen.js +37 -13
- package/dist/lib/common.js +50 -0
- package/dist/lib/cpu-profiler.js +4 -1
- package/dist/lib/dev-shared.js +97 -0
- package/dist/lib/environment-variables.js +51 -30
- package/dist/lib/file.js +8 -1
- package/dist/lib/flags.js +37 -16
- package/dist/lib/graphql/admin/customer-application-update.js +29 -0
- package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
- package/dist/lib/graphql/admin/list-environments.js +1 -0
- package/dist/lib/graphql/admin/pull-variables.js +4 -4
- package/dist/lib/graphql/admin/test-helper.js +37 -0
- package/dist/lib/log.js +86 -13
- package/dist/lib/mini-oxygen/common.js +19 -33
- package/dist/lib/mini-oxygen/index.js +6 -2
- package/dist/lib/mini-oxygen/node.js +43 -31
- package/dist/lib/mini-oxygen/workerd.js +72 -165
- package/dist/lib/missing-routes.js +1 -1
- package/dist/lib/onboarding/common.js +82 -70
- package/dist/lib/onboarding/local.js +19 -9
- package/dist/lib/onboarding/remote.js +35 -30
- package/dist/lib/package-managers.js +24 -0
- package/dist/lib/remix-config.js +17 -1
- package/dist/lib/request-events.js +6 -1
- package/dist/lib/setups/i18n/replacers.js +9 -6
- package/dist/lib/setups/routes/generate.js +1 -0
- package/dist/lib/shell.js +2 -1
- package/dist/lib/shopify-config.js +19 -1
- package/dist/lib/template-diff.js +36 -15
- package/dist/lib/template-downloader.js +35 -5
- package/dist/lib/transpile/morph/typedefs.js +5 -2
- package/dist/lib/transpile/project.js +8 -4
- package/dist/lib/tunneling.js +44 -0
- package/dist/lib/virtual-routes.js +1 -1
- package/dist/lib/vite-config.js +39 -9
- package/oclif.manifest.json +711 -498
- package/package.json +32 -24
- package/dist/commands/hydrogen/deploy.test.js +0 -553
- package/dist/commands/hydrogen/env/list.test.js +0 -148
- package/dist/commands/hydrogen/env/pull.test.js +0 -207
- package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
- package/dist/commands/hydrogen/generate/route.test.js +0 -43
- package/dist/commands/hydrogen/init.test.js +0 -641
- package/dist/commands/hydrogen/link.test.js +0 -187
- package/dist/commands/hydrogen/list.test.js +0 -111
- package/dist/commands/hydrogen/setup.test.js +0 -61
- package/dist/commands/hydrogen/shortcut.test.js +0 -30
- package/dist/commands/hydrogen/unlink.test.js +0 -36
- package/dist/commands/hydrogen/upgrade.test.js +0 -786
- package/dist/generator-templates/starter/remix.config.js +0 -24
- package/dist/lib/auth.test.js +0 -157
- package/dist/lib/check-lockfile.test.js +0 -81
- package/dist/lib/check-version.test.js +0 -86
- package/dist/lib/environment-variables.test.js +0 -149
- package/dist/lib/file.test.js +0 -68
- package/dist/lib/flags.test.js +0 -43
- package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
- package/dist/lib/gid.test.js +0 -15
- package/dist/lib/graphql/admin/client.test.js +0 -76
- package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
- package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
- package/dist/lib/graphql/admin/list-environments.test.js +0 -44
- package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
- package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
- package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
- package/dist/lib/log.test.js +0 -92
- package/dist/lib/mini-oxygen/assets.js +0 -134
- package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
- package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
- package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
- package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
- package/dist/lib/missing-routes.test.js +0 -45
- package/dist/lib/remix-version-check.test.js +0 -39
- package/dist/lib/remix-version-interop.test.js +0 -13
- package/dist/lib/setups/i18n/domains.test.js +0 -39
- package/dist/lib/setups/i18n/replacers.test.js +0 -261
- package/dist/lib/setups/i18n/subdomains.test.js +0 -39
- package/dist/lib/setups/i18n/subfolders.test.js +0 -39
- package/dist/lib/setups/routes/generate.test.js +0 -296
- package/dist/lib/shell.test.js +0 -111
- package/dist/lib/shopify-config.test.js +0 -199
- package/dist/lib/string.test.js +0 -16
- package/dist/lib/virtual-routes.test.js +0 -49
- package/dist/lib/vite/hydrogen-middleware.js +0 -82
- package/dist/lib/vite/mini-oxygen.js +0 -152
- package/dist/lib/vite/plugins.d.ts +0 -27
- package/dist/lib/vite/plugins.js +0 -139
- package/dist/lib/vite/shared.js +0 -10
- package/dist/lib/vite/utils.js +0 -55
- package/dist/lib/vite/worker-entry.js +0 -1518
- /package/dist/generator-templates/starter/{.eslintrc.js → .eslintrc.cjs} +0 -0
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import crypto from 'node:crypto';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { createServer } from 'node:http';
|
|
4
|
-
import { WebSocketServer } from 'ws';
|
|
5
|
-
import { request } from 'undici';
|
|
6
|
-
|
|
7
|
-
const CFW_DEVTOOLS = "https://devtools.devprod.cloudflare.dev";
|
|
8
|
-
const H2_FAVICON_URL = "https://cdn.shopify.com/s/files/1/0598/4822/8886/files/favicon.svg";
|
|
9
|
-
function createInspectorProxy(port, sourceFilePath, newInspectorConnection) {
|
|
10
|
-
const sessionId = crypto.randomUUID();
|
|
11
|
-
let debuggerWs = void 0;
|
|
12
|
-
let inspector = newInspectorConnection;
|
|
13
|
-
let isDevToolsInBrowser = false;
|
|
14
|
-
const sourceMapPathname = "/__index.js.map";
|
|
15
|
-
const sourceMapURL = `http://localhost:${port}${sourceMapPathname}`;
|
|
16
|
-
const server = createServer((req, res) => {
|
|
17
|
-
const [url = "/", queryString = ""] = req.url?.split("?") || [];
|
|
18
|
-
switch (url) {
|
|
19
|
-
case "/json/version":
|
|
20
|
-
res.setHeader("Content-Type", "application/json");
|
|
21
|
-
res.end(
|
|
22
|
-
JSON.stringify({ Browser: "hydrogen/v2", "Protocol-Version": "1.3" })
|
|
23
|
-
);
|
|
24
|
-
break;
|
|
25
|
-
case "/json":
|
|
26
|
-
case "/json/list":
|
|
27
|
-
{
|
|
28
|
-
res.setHeader("Content-Type", "application/json");
|
|
29
|
-
const localHost = `localhost:${port}/ws`;
|
|
30
|
-
const devtoolsFrontendUrl = `devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=${localHost}`;
|
|
31
|
-
const devtoolsFrontendUrlCompat = `devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${localHost}`;
|
|
32
|
-
res.end(
|
|
33
|
-
JSON.stringify([
|
|
34
|
-
{
|
|
35
|
-
id: sessionId,
|
|
36
|
-
type: "node",
|
|
37
|
-
webSocketDebuggerUrl: `ws://${localHost}`,
|
|
38
|
-
devtoolsFrontendUrl,
|
|
39
|
-
devtoolsFrontendUrlCompat,
|
|
40
|
-
// Below are fields that are visible in the DevTools UI.
|
|
41
|
-
title: "Hydrogen / Oxygen Worker",
|
|
42
|
-
faviconUrl: H2_FAVICON_URL,
|
|
43
|
-
url: "https://" + new URL(inspector.ws.url).host
|
|
44
|
-
}
|
|
45
|
-
])
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
return;
|
|
49
|
-
case sourceMapPathname:
|
|
50
|
-
res.setHeader("Content-Type", "text/plain");
|
|
51
|
-
res.setHeader("Cache-Control", "no-store");
|
|
52
|
-
res.setHeader(
|
|
53
|
-
"Access-Control-Allow-Origin",
|
|
54
|
-
req.headers.origin ?? "devtools://devtools"
|
|
55
|
-
);
|
|
56
|
-
res.end(readFileSync(sourceFilePath + ".map", "utf-8"));
|
|
57
|
-
break;
|
|
58
|
-
case "/favicon.ico":
|
|
59
|
-
proxyHttp(H2_FAVICON_URL, req.headers, res);
|
|
60
|
-
break;
|
|
61
|
-
case "/":
|
|
62
|
-
if (!queryString) {
|
|
63
|
-
res.statusCode = 302;
|
|
64
|
-
res.setHeader(
|
|
65
|
-
"Location",
|
|
66
|
-
`/?experiments=true&v8only=true&debugger=true&ws=localhost:${port}/ws`
|
|
67
|
-
);
|
|
68
|
-
res.end();
|
|
69
|
-
} else {
|
|
70
|
-
proxyHttp(
|
|
71
|
-
CFW_DEVTOOLS + "/js_app",
|
|
72
|
-
req.headers,
|
|
73
|
-
res,
|
|
74
|
-
(content) => (
|
|
75
|
-
// HTML from DevTools comes without closing <body> and <html> tags.
|
|
76
|
-
// The browser closes them automatically, then modifies the DOM with JS.
|
|
77
|
-
// This adds a loading indicator before the JS kicks in and modifies the DOM.
|
|
78
|
-
content + '<div style="display: flex; flex-direction: column; align-items: center; padding-top: 20px; font-family: Arial; color: white">Loading DevTools...</div></body></html>'
|
|
79
|
-
)
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
default:
|
|
84
|
-
if (url === "/panels/sources/sources-meta.js" || url.startsWith("/core/i18n/locales/") && url.endsWith(".json")) {
|
|
85
|
-
proxyHttp(
|
|
86
|
-
CFW_DEVTOOLS + url,
|
|
87
|
-
req.headers,
|
|
88
|
-
res,
|
|
89
|
-
(content) => content.replace(/['"]Cloudflare['"]/g, '"Hydrogen"')
|
|
90
|
-
);
|
|
91
|
-
} else {
|
|
92
|
-
proxyHttp(CFW_DEVTOOLS + url, req.headers, res);
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
const wsServer = new WebSocketServer({ server, clientTracking: true });
|
|
98
|
-
server.listen(port);
|
|
99
|
-
let messageBuffer = [];
|
|
100
|
-
wsServer.on("connection", (ws, req) => {
|
|
101
|
-
if (wsServer.clients.size > 1) {
|
|
102
|
-
console.error(
|
|
103
|
-
"Tried to open a new devtools window when a previous one was already open."
|
|
104
|
-
);
|
|
105
|
-
ws.close(1013, "Too many clients; only one can be connected at a time");
|
|
106
|
-
} else {
|
|
107
|
-
inspector.ws.send(
|
|
108
|
-
JSON.stringify({ id: 1e8, method: "Debugger.disable" })
|
|
109
|
-
);
|
|
110
|
-
debuggerWs?.removeEventListener("message", sendMessageToInspector);
|
|
111
|
-
debuggerWs = ws;
|
|
112
|
-
isDevToolsInBrowser = /mozilla/i.test(req.headers["user-agent"] ?? "");
|
|
113
|
-
debuggerWs.addEventListener("message", sendMessageToInspector);
|
|
114
|
-
debuggerWs.addEventListener("close", () => {
|
|
115
|
-
debuggerWs?.removeEventListener("message", sendMessageToInspector);
|
|
116
|
-
debuggerWs = void 0;
|
|
117
|
-
});
|
|
118
|
-
messageBuffer.forEach(sendMessageToDebugger);
|
|
119
|
-
messageBuffer = [];
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
if (inspector.ws)
|
|
123
|
-
onInspectorConnection();
|
|
124
|
-
function onInspectorConnection() {
|
|
125
|
-
inspector.ws.addEventListener("message", sendMessageToDebugger);
|
|
126
|
-
debuggerWs?.send(
|
|
127
|
-
JSON.stringify({
|
|
128
|
-
method: "Runtime.consoleAPICalled",
|
|
129
|
-
params: {
|
|
130
|
-
type: "warning",
|
|
131
|
-
args: [
|
|
132
|
-
{
|
|
133
|
-
type: "string",
|
|
134
|
-
value: "Source code changed. Please reload the DevTools to reconnect the debugger."
|
|
135
|
-
}
|
|
136
|
-
],
|
|
137
|
-
executionContextId: Date.now(),
|
|
138
|
-
timestamp: Date.now()
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
debuggerWs?.close(1001, "Source code changed");
|
|
143
|
-
}
|
|
144
|
-
function sendMessageToInspector(event) {
|
|
145
|
-
inspector.ws.send(event.data);
|
|
146
|
-
}
|
|
147
|
-
function sendMessageToDebugger(event) {
|
|
148
|
-
if (isDevToolsInBrowser) {
|
|
149
|
-
event = enhanceDevToolsEvent(event, sourceMapURL);
|
|
150
|
-
}
|
|
151
|
-
if (debuggerWs) {
|
|
152
|
-
debuggerWs.send(event.data);
|
|
153
|
-
} else {
|
|
154
|
-
messageBuffer.push(event);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
updateInspectorConnection(newConnection) {
|
|
159
|
-
inspector = newConnection;
|
|
160
|
-
onInspectorConnection();
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function enhanceDevToolsEvent(event, sourceMapUrl) {
|
|
165
|
-
const message = JSON.parse(event.data);
|
|
166
|
-
if (message.method === "Debugger.scriptParsed") {
|
|
167
|
-
if (message.params.sourceMapURL === "index.js.map") {
|
|
168
|
-
message.params.sourceMapURL = sourceMapUrl;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return { ...event, data: JSON.stringify(message) };
|
|
172
|
-
}
|
|
173
|
-
function proxyHttp(url, originalHeaders, nodeResponse, contentReplacer) {
|
|
174
|
-
const headers = Object.fromEntries(Object.entries(originalHeaders));
|
|
175
|
-
delete headers["host"];
|
|
176
|
-
delete headers["cookie"];
|
|
177
|
-
if (contentReplacer)
|
|
178
|
-
delete headers["accept-encoding"];
|
|
179
|
-
return request(url, { responseHeader: "raw", headers }).then((response) => {
|
|
180
|
-
nodeResponse.statusCode = response.statusCode;
|
|
181
|
-
if (nodeResponse.statusCode === 404) {
|
|
182
|
-
return nodeResponse.end("Not found");
|
|
183
|
-
}
|
|
184
|
-
Object.entries(response.headers).forEach(([key, value]) => {
|
|
185
|
-
if (value) {
|
|
186
|
-
nodeResponse.setHeader(key, value);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
if (contentReplacer) {
|
|
190
|
-
return response.body?.text().then(contentReplacer).then(nodeResponse.end.bind(nodeResponse));
|
|
191
|
-
}
|
|
192
|
-
return response.body.pipe(nodeResponse);
|
|
193
|
-
}).catch((err) => {
|
|
194
|
-
console.error(err);
|
|
195
|
-
nodeResponse.statusCode = 500;
|
|
196
|
-
nodeResponse.end("Internal error");
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export { createInspectorProxy };
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import { dirname } from 'node:path';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { fetch } from '@shopify/cli-kit/node/http';
|
|
4
|
-
import { SourceMapConsumer } from 'source-map';
|
|
5
|
-
import { WebSocket } from 'ws';
|
|
6
|
-
import { addInspectorConsoleLogger, formatStack } from './workerd-inspector-logs.js';
|
|
7
|
-
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
8
|
-
import { createInspectorProxy } from './workerd-inspector-proxy.js';
|
|
9
|
-
|
|
10
|
-
function createInspectorConnector(options) {
|
|
11
|
-
let inspectorUrl;
|
|
12
|
-
let inspectorConnection;
|
|
13
|
-
let inspectorProxy;
|
|
14
|
-
return async (onBeforeConnect) => {
|
|
15
|
-
inspectorConnection?.close();
|
|
16
|
-
inspectorUrl ??= await findInspectorUrl(options.privateInspectorPort);
|
|
17
|
-
await onBeforeConnect?.();
|
|
18
|
-
inspectorConnection = connectToInspector({
|
|
19
|
-
inspectorUrl,
|
|
20
|
-
sourceMapPath: options.sourceMapPath
|
|
21
|
-
});
|
|
22
|
-
addInspectorConsoleLogger(inspectorConnection);
|
|
23
|
-
if (options.debug) {
|
|
24
|
-
if (inspectorProxy) {
|
|
25
|
-
inspectorProxy.updateInspectorConnection(inspectorConnection);
|
|
26
|
-
} else {
|
|
27
|
-
inspectorProxy = createInspectorProxy(
|
|
28
|
-
options.publicInspectorPort,
|
|
29
|
-
options.absoluteBundlePath,
|
|
30
|
-
inspectorConnection
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
async function findInspectorUrl(inspectorPort) {
|
|
37
|
-
try {
|
|
38
|
-
const jsonUrl = `http://127.0.0.1:${inspectorPort}/json`;
|
|
39
|
-
const body = await (await fetch(jsonUrl)).json();
|
|
40
|
-
const url = body?.find(
|
|
41
|
-
({ id }) => id === "core:user:hydrogen" || id === "core:user:oxygen"
|
|
42
|
-
)?.webSocketDebuggerUrl;
|
|
43
|
-
if (!url) {
|
|
44
|
-
throw new Error("Unable to find inspector URL");
|
|
45
|
-
}
|
|
46
|
-
return url;
|
|
47
|
-
} catch (error) {
|
|
48
|
-
const abortError = new AbortError(
|
|
49
|
-
"Unable to connect to Worker inspector",
|
|
50
|
-
`Please report this issue. ${error.stack}`
|
|
51
|
-
);
|
|
52
|
-
abortError.stack = error.stack;
|
|
53
|
-
throw abortError;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function connectToInspector({ inspectorUrl, sourceMapPath }) {
|
|
57
|
-
const messageCounterRef = { value: -1 };
|
|
58
|
-
const getMessageId = () => messageCounterRef.value--;
|
|
59
|
-
const pendingMessages = /* @__PURE__ */ new Map();
|
|
60
|
-
const ws = new WebSocket(inspectorUrl);
|
|
61
|
-
let keepAliveInterval;
|
|
62
|
-
const isClosed = () => ws.readyState === WebSocket.CLOSED || ws.readyState === WebSocket.CLOSING;
|
|
63
|
-
const send = (method, params) => {
|
|
64
|
-
if (!isClosed()) {
|
|
65
|
-
const id = getMessageId();
|
|
66
|
-
let promiseResolve = void 0;
|
|
67
|
-
const promise = new Promise(
|
|
68
|
-
(resolve) => promiseResolve = resolve
|
|
69
|
-
);
|
|
70
|
-
pendingMessages.set(id, promiseResolve);
|
|
71
|
-
ws.send(JSON.stringify({ id, method, params }));
|
|
72
|
-
return promise;
|
|
73
|
-
}
|
|
74
|
-
return Promise.resolve(void 0);
|
|
75
|
-
};
|
|
76
|
-
const cleanupMessageQueue = (data) => {
|
|
77
|
-
try {
|
|
78
|
-
if (data?.id < 0) {
|
|
79
|
-
const resolve = pendingMessages.get(data.id);
|
|
80
|
-
if (resolve !== void 0) {
|
|
81
|
-
pendingMessages.delete(data.id);
|
|
82
|
-
resolve(data.result);
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error(error);
|
|
88
|
-
}
|
|
89
|
-
return false;
|
|
90
|
-
};
|
|
91
|
-
function getPropertyValue(name, response) {
|
|
92
|
-
return response?.result.find((prop) => prop.name === name)?.value;
|
|
93
|
-
}
|
|
94
|
-
async function reconstructError(initialProperties, ro) {
|
|
95
|
-
let errorProperties = { ...initialProperties };
|
|
96
|
-
const objectId = ro?.objectId;
|
|
97
|
-
if (objectId) {
|
|
98
|
-
const [sourceMapConsumer, getPropertiesResponse] = await Promise.all([
|
|
99
|
-
getSourceMapConsumer(),
|
|
100
|
-
send("Runtime.getProperties", {
|
|
101
|
-
objectId,
|
|
102
|
-
ownProperties: false,
|
|
103
|
-
accessorPropertiesOnly: false,
|
|
104
|
-
generatePreview: false,
|
|
105
|
-
nonIndexedPropertiesOnly: false
|
|
106
|
-
})
|
|
107
|
-
]);
|
|
108
|
-
const message = getPropertyValue("message", getPropertiesResponse);
|
|
109
|
-
if (message?.value) {
|
|
110
|
-
errorProperties.message = message.value;
|
|
111
|
-
}
|
|
112
|
-
const stack = getPropertyValue("stack", getPropertiesResponse);
|
|
113
|
-
if (stack?.value) {
|
|
114
|
-
errorProperties.stack = sourceMapConsumer ? formatStack(sourceMapConsumer, stack.value) : stack.value;
|
|
115
|
-
}
|
|
116
|
-
const cause = getPropertyValue("cause", getPropertiesResponse);
|
|
117
|
-
if (cause) {
|
|
118
|
-
errorProperties.cause = cause.description ?? cause.value;
|
|
119
|
-
if (cause.subtype === "error" && sourceMapConsumer && cause.description !== void 0) {
|
|
120
|
-
errorProperties.stack = formatStack(
|
|
121
|
-
sourceMapConsumer,
|
|
122
|
-
cause.description
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const isDomException = ro?.className === "DOMException";
|
|
127
|
-
if (isDomException) {
|
|
128
|
-
const stackDescriptor = getPropertiesResponse?.result.find(
|
|
129
|
-
(prop) => prop.name === "stack"
|
|
130
|
-
);
|
|
131
|
-
const getObjectId = stackDescriptor?.get?.objectId;
|
|
132
|
-
if (getObjectId !== void 0) {
|
|
133
|
-
const callFunctionResponse = await send("Runtime.callFunctionOn", {
|
|
134
|
-
objectId,
|
|
135
|
-
functionDeclaration: "function invokeGetter(getter) { return Reflect.apply(getter, this, []); }",
|
|
136
|
-
arguments: [{ objectId: getObjectId }],
|
|
137
|
-
silent: true
|
|
138
|
-
});
|
|
139
|
-
if (callFunctionResponse !== void 0) {
|
|
140
|
-
const stack2 = callFunctionResponse.result.value;
|
|
141
|
-
if (typeof stack2 === "string" && sourceMapConsumer !== void 0) {
|
|
142
|
-
errorProperties.stack = formatStack(sourceMapConsumer, stack2);
|
|
143
|
-
} else {
|
|
144
|
-
try {
|
|
145
|
-
errorProperties.stack = JSON.stringify(stack2);
|
|
146
|
-
} catch {
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const error = new Error(errorProperties.message);
|
|
154
|
-
error.stack = errorProperties.stack;
|
|
155
|
-
if (errorProperties.cause) {
|
|
156
|
-
error.cause = errorProperties.cause;
|
|
157
|
-
}
|
|
158
|
-
return error;
|
|
159
|
-
}
|
|
160
|
-
const sourceMapAbortController = new AbortController();
|
|
161
|
-
let sourceMapConsumerPromise;
|
|
162
|
-
const getSourceMapConsumer = () => {
|
|
163
|
-
return sourceMapConsumerPromise ??= (async () => {
|
|
164
|
-
if (!sourceMapPath || sourceMapAbortController.signal.aborted) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
try {
|
|
168
|
-
const mapContent = await readFile(sourceMapPath, "utf-8");
|
|
169
|
-
if (sourceMapAbortController.signal.aborted)
|
|
170
|
-
return;
|
|
171
|
-
const map = JSON.parse(mapContent);
|
|
172
|
-
map.sourceRoot = dirname(sourceMapPath);
|
|
173
|
-
const sourceMapConsumer = await new SourceMapConsumer(map);
|
|
174
|
-
if (sourceMapAbortController.signal.aborted) {
|
|
175
|
-
sourceMapConsumer.destroy();
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
sourceMapAbortController.signal.addEventListener("abort", () => {
|
|
179
|
-
sourceMapConsumerPromise = Promise.resolve(void 0);
|
|
180
|
-
sourceMapConsumer.destroy();
|
|
181
|
-
});
|
|
182
|
-
return sourceMapConsumer;
|
|
183
|
-
} catch {
|
|
184
|
-
}
|
|
185
|
-
})();
|
|
186
|
-
};
|
|
187
|
-
ws.once("open", () => {
|
|
188
|
-
send("Runtime.enable");
|
|
189
|
-
keepAliveInterval = setInterval(() => send("Runtime.getIsolateId"), 1e4);
|
|
190
|
-
});
|
|
191
|
-
ws.on("unexpected-response", () => {
|
|
192
|
-
console.log("Waiting for connection...");
|
|
193
|
-
});
|
|
194
|
-
ws.once("close", () => {
|
|
195
|
-
clearInterval(keepAliveInterval);
|
|
196
|
-
sourceMapAbortController.abort();
|
|
197
|
-
});
|
|
198
|
-
return {
|
|
199
|
-
ws,
|
|
200
|
-
send,
|
|
201
|
-
reconstructError,
|
|
202
|
-
getSourceMapConsumer,
|
|
203
|
-
cleanupMessageQueue,
|
|
204
|
-
isClosed,
|
|
205
|
-
close: () => {
|
|
206
|
-
clearInterval(keepAliveInterval);
|
|
207
|
-
if (!isClosed()) {
|
|
208
|
-
try {
|
|
209
|
-
ws.removeAllListeners();
|
|
210
|
-
ws.close();
|
|
211
|
-
} catch (err) {
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
sourceMapAbortController.abort();
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export { createInspectorConnector };
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { findMissingRoutes } from './missing-routes.js';
|
|
3
|
-
|
|
4
|
-
const createRoute = (path) => ({
|
|
5
|
-
routes: {
|
|
6
|
-
"route-id": {
|
|
7
|
-
file: "a/file",
|
|
8
|
-
id: "route-id",
|
|
9
|
-
path
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
describe("missing-routes", () => {
|
|
14
|
-
it("matches routes with dots", async () => {
|
|
15
|
-
const requiredRoutes = ["sitemap.xml"];
|
|
16
|
-
expect(findMissingRoutes({ routes: {} }, requiredRoutes)).toHaveLength(1);
|
|
17
|
-
expect(
|
|
18
|
-
findMissingRoutes(createRoute("sitemap.xml"), requiredRoutes)
|
|
19
|
-
).toHaveLength(0);
|
|
20
|
-
});
|
|
21
|
-
it("matches routes with different parameter names", async () => {
|
|
22
|
-
const requiredRoutes = ["collections/:collectionHandle"];
|
|
23
|
-
expect(findMissingRoutes({ routes: {} }, requiredRoutes)).toHaveLength(1);
|
|
24
|
-
expect(
|
|
25
|
-
findMissingRoutes(createRoute("collections/:param"), requiredRoutes)
|
|
26
|
-
).toHaveLength(0);
|
|
27
|
-
});
|
|
28
|
-
it("matches optional segments in different positions", async () => {
|
|
29
|
-
const requiredRoutes = ["collections/products"];
|
|
30
|
-
const validRoutes = [
|
|
31
|
-
"segment?/collections/products",
|
|
32
|
-
":segment?/collections/products",
|
|
33
|
-
"collections/segment?/products",
|
|
34
|
-
"collections/:segment?/products",
|
|
35
|
-
"collections/products/segment?",
|
|
36
|
-
"collections/products/:segment?"
|
|
37
|
-
];
|
|
38
|
-
expect(findMissingRoutes({ routes: {} }, requiredRoutes)).toHaveLength(1);
|
|
39
|
-
for (const validRoute of validRoutes) {
|
|
40
|
-
expect(
|
|
41
|
-
findMissingRoutes(createRoute(validRoute), requiredRoutes)
|
|
42
|
-
).toHaveLength(0);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { vi, describe, it, expect } from 'vitest';
|
|
2
|
-
import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
|
|
3
|
-
import { checkRemixVersions } from './remix-version-check.js';
|
|
4
|
-
|
|
5
|
-
const requireMock = vi.fn();
|
|
6
|
-
vi.mock("node:module", async () => {
|
|
7
|
-
const { createRequire } = await vi.importActual(
|
|
8
|
-
"node:module"
|
|
9
|
-
);
|
|
10
|
-
return {
|
|
11
|
-
createRequire: (url) => {
|
|
12
|
-
const actualRequire = createRequire(url);
|
|
13
|
-
requireMock.mockImplementation((mod) => actualRequire(mod));
|
|
14
|
-
const require2 = requireMock;
|
|
15
|
-
require2.resolve = actualRequire.resolve.bind(actualRequire);
|
|
16
|
-
return require2;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
|
-
describe("remix-version-check", () => {
|
|
21
|
-
it("does nothing when versions are in sync", () => {
|
|
22
|
-
const outputMock = mockAndCaptureOutput();
|
|
23
|
-
checkRemixVersions();
|
|
24
|
-
expect(outputMock.warn()).toBe("");
|
|
25
|
-
});
|
|
26
|
-
it("warns when versions are out of sync", () => {
|
|
27
|
-
const expectedVersion = "42.0.0-test";
|
|
28
|
-
vi.mocked(requireMock).mockReturnValueOnce({
|
|
29
|
-
// Hydrogen expected version
|
|
30
|
-
peerDependencies: { "@remix-run/dev": expectedVersion }
|
|
31
|
-
});
|
|
32
|
-
const outputMock = mockAndCaptureOutput();
|
|
33
|
-
checkRemixVersions();
|
|
34
|
-
const output = outputMock.warn();
|
|
35
|
-
expect(output).toMatch(`Hydrogen requires Remix @${expectedVersion}`);
|
|
36
|
-
expect(output).toMatch(`@remix-run/dev@`);
|
|
37
|
-
expect(output).toMatch(`@remix-run/react@`);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { convertRouteToV1 } from './remix-version-interop.js';
|
|
3
|
-
|
|
4
|
-
describe("remix-version-interop", () => {
|
|
5
|
-
it("converts routes to v1", () => {
|
|
6
|
-
expect(convertRouteToV1("_index")).toEqual("index");
|
|
7
|
-
expect(convertRouteToV1("path.to.file")).toEqual("path/to/file");
|
|
8
|
-
expect(convertRouteToV1("path.to._index")).toEqual("path/to/index");
|
|
9
|
-
expect(convertRouteToV1("patht.to.[sitemap.xml]")).toEqual(
|
|
10
|
-
"patht/to/[sitemap.xml]"
|
|
11
|
-
);
|
|
12
|
-
});
|
|
13
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath } from 'node:url';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import { getLocaleFromRequest } from './templates/domains.js';
|
|
4
|
-
import { readFile } from '@shopify/cli-kit/node/fs';
|
|
5
|
-
|
|
6
|
-
describe("Setup i18n with domains", () => {
|
|
7
|
-
it("extracts the locale from the domain", () => {
|
|
8
|
-
expect(
|
|
9
|
-
getLocaleFromRequest(new Request("https://example.com"))
|
|
10
|
-
).toMatchObject({
|
|
11
|
-
language: "EN",
|
|
12
|
-
country: "US"
|
|
13
|
-
});
|
|
14
|
-
expect(
|
|
15
|
-
getLocaleFromRequest(new Request("https://example.jp"))
|
|
16
|
-
).toMatchObject({
|
|
17
|
-
language: "JA",
|
|
18
|
-
country: "JP"
|
|
19
|
-
});
|
|
20
|
-
expect(
|
|
21
|
-
getLocaleFromRequest(new Request("https://www.example.es"))
|
|
22
|
-
).toMatchObject({
|
|
23
|
-
language: "ES",
|
|
24
|
-
country: "ES"
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
it("does not access imported types directly", async () => {
|
|
28
|
-
const template = await readFile(
|
|
29
|
-
fileURLToPath(new URL("./templates/domains.ts", import.meta.url))
|
|
30
|
-
);
|
|
31
|
-
const typeImports = (template.match(/import\s+type\s+{([^}]+)}/)?.[1] || "").trim().split(/\s*,\s*/);
|
|
32
|
-
expect(typeImports).not.toHaveLength(0);
|
|
33
|
-
const fnCode = template.match(/function .*\n}$/ms)?.[0] || "";
|
|
34
|
-
expect(fnCode).toBeTruthy();
|
|
35
|
-
typeImports.forEach(
|
|
36
|
-
(typeImport) => expect(fnCode).not.toContain(typeImport)
|
|
37
|
-
);
|
|
38
|
-
});
|
|
39
|
-
});
|