@essential-apps/shopify-test-runner 1.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/contracts/normalize.d.ts +61 -0
- package/dist/contracts/normalize.d.ts.map +1 -0
- package/dist/contracts/normalize.js +99 -0
- package/dist/contracts/normalize.js.map +1 -0
- package/dist/contracts/normalizeHtml.d.ts +37 -0
- package/dist/contracts/normalizeHtml.d.ts.map +1 -0
- package/dist/contracts/normalizeHtml.js +89 -0
- package/dist/contracts/normalizeHtml.js.map +1 -0
- package/dist/edge/cert.d.ts +44 -0
- package/dist/edge/cert.d.ts.map +1 -0
- package/dist/edge/cert.js +117 -0
- package/dist/edge/cert.js.map +1 -0
- package/dist/edge/edgeProxy.d.ts +43 -0
- package/dist/edge/edgeProxy.d.ts.map +1 -0
- package/dist/edge/edgeProxy.js +297 -0
- package/dist/edge/edgeProxy.js.map +1 -0
- package/dist/edge/nodeShim.d.ts +2 -0
- package/dist/edge/nodeShim.d.ts.map +1 -0
- package/dist/edge/nodeShim.js +217 -0
- package/dist/edge/nodeShim.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/buildSourceBundle.d.ts +56 -0
- package/dist/lib/buildSourceBundle.d.ts.map +1 -0
- package/dist/lib/buildSourceBundle.js +153 -0
- package/dist/lib/buildSourceBundle.js.map +1 -0
- package/dist/lib/freePort.d.ts +5 -0
- package/dist/lib/freePort.d.ts.map +1 -0
- package/dist/lib/freePort.js +33 -0
- package/dist/lib/freePort.js.map +1 -0
- package/dist/lib/functionBuild.d.ts +99 -0
- package/dist/lib/functionBuild.d.ts.map +1 -0
- package/dist/lib/functionBuild.js +413 -0
- package/dist/lib/functionBuild.js.map +1 -0
- package/dist/lib/neonWsProxy.d.ts +41 -0
- package/dist/lib/neonWsProxy.d.ts.map +1 -0
- package/dist/lib/neonWsProxy.js +101 -0
- package/dist/lib/neonWsProxy.js.map +1 -0
- package/dist/lib/sourceZipUpload.d.ts +45 -0
- package/dist/lib/sourceZipUpload.d.ts.map +1 -0
- package/dist/lib/sourceZipUpload.js +129 -0
- package/dist/lib/sourceZipUpload.js.map +1 -0
- package/dist/lib/stealthLaunch.d.ts +35 -0
- package/dist/lib/stealthLaunch.d.ts.map +1 -0
- package/dist/lib/stealthLaunch.js +46 -0
- package/dist/lib/stealthLaunch.js.map +1 -0
- package/dist/lib/storeAutomation.d.ts +22 -0
- package/dist/lib/storeAutomation.d.ts.map +1 -0
- package/dist/lib/storeAutomation.js +85 -0
- package/dist/lib/storeAutomation.js.map +1 -0
- package/dist/playwright/baseConfig.d.ts +62 -0
- package/dist/playwright/baseConfig.d.ts.map +1 -0
- package/dist/playwright/baseConfig.js +68 -0
- package/dist/playwright/baseConfig.js.map +1 -0
- package/dist/playwright/globalSetup.d.ts +2 -0
- package/dist/playwright/globalSetup.d.ts.map +1 -0
- package/dist/playwright/globalSetup.js +139 -0
- package/dist/playwright/globalSetup.js.map +1 -0
- package/dist/playwright/index.d.ts +9 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +9 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/probes/fonts.d.ts +4 -0
- package/dist/probes/fonts.d.ts.map +1 -0
- package/dist/probes/fonts.js +255 -0
- package/dist/probes/fonts.js.map +1 -0
- package/dist/probes/mirror.d.ts +4 -0
- package/dist/probes/mirror.d.ts.map +1 -0
- package/dist/probes/mirror.js +260 -0
- package/dist/probes/mirror.js.map +1 -0
- package/dist/probes/runProbe.d.ts +3 -0
- package/dist/probes/runProbe.d.ts.map +1 -0
- package/dist/probes/runProbe.js +219 -0
- package/dist/probes/runProbe.js.map +1 -0
- package/dist/probes/types.d.ts +72 -0
- package/dist/probes/types.d.ts.map +1 -0
- package/dist/probes/types.js +2 -0
- package/dist/probes/types.js.map +1 -0
- package/dist/scripts/_probeSourceUrl.d.ts +3 -0
- package/dist/scripts/_probeSourceUrl.d.ts.map +1 -0
- package/dist/scripts/_probeSourceUrl.js +119 -0
- package/dist/scripts/_probeSourceUrl.js.map +1 -0
- package/dist/scripts/addStore.d.ts +3 -0
- package/dist/scripts/addStore.d.ts.map +1 -0
- package/dist/scripts/addStore.js +46 -0
- package/dist/scripts/addStore.js.map +1 -0
- package/dist/scripts/buildDockerImage.d.ts +3 -0
- package/dist/scripts/buildDockerImage.d.ts.map +1 -0
- package/dist/scripts/buildDockerImage.js +60 -0
- package/dist/scripts/buildDockerImage.js.map +1 -0
- package/dist/scripts/captureAuth.d.ts +3 -0
- package/dist/scripts/captureAuth.d.ts.map +1 -0
- package/dist/scripts/captureAuth.js +124 -0
- package/dist/scripts/captureAuth.js.map +1 -0
- package/dist/scripts/captureContracts.d.ts +3 -0
- package/dist/scripts/captureContracts.d.ts.map +1 -0
- package/dist/scripts/captureContracts.js +517 -0
- package/dist/scripts/captureContracts.js.map +1 -0
- package/dist/scripts/captureRestContracts.d.ts +3 -0
- package/dist/scripts/captureRestContracts.d.ts.map +1 -0
- package/dist/scripts/captureRestContracts.js +245 -0
- package/dist/scripts/captureRestContracts.js.map +1 -0
- package/dist/scripts/checkOperationCoverage.d.ts +3 -0
- package/dist/scripts/checkOperationCoverage.d.ts.map +1 -0
- package/dist/scripts/checkOperationCoverage.js +302 -0
- package/dist/scripts/checkOperationCoverage.js.map +1 -0
- package/dist/scripts/cleanupStores.d.ts +3 -0
- package/dist/scripts/cleanupStores.d.ts.map +1 -0
- package/dist/scripts/cleanupStores.js +77 -0
- package/dist/scripts/cleanupStores.js.map +1 -0
- package/dist/scripts/createStores.d.ts +3 -0
- package/dist/scripts/createStores.d.ts.map +1 -0
- package/dist/scripts/createStores.js +66 -0
- package/dist/scripts/createStores.js.map +1 -0
- package/dist/scripts/deployAppVersion.d.ts +3 -0
- package/dist/scripts/deployAppVersion.d.ts.map +1 -0
- package/dist/scripts/deployAppVersion.js +591 -0
- package/dist/scripts/deployAppVersion.js.map +1 -0
- package/dist/scripts/devE2eBackend.d.ts +3 -0
- package/dist/scripts/devE2eBackend.d.ts.map +1 -0
- package/dist/scripts/devE2eBackend.js +117 -0
- package/dist/scripts/devE2eBackend.js.map +1 -0
- package/dist/scripts/devOnlineBackend.d.ts +3 -0
- package/dist/scripts/devOnlineBackend.d.ts.map +1 -0
- package/dist/scripts/devOnlineBackend.js +117 -0
- package/dist/scripts/devOnlineBackend.js.map +1 -0
- package/dist/scripts/installApp.d.ts +3 -0
- package/dist/scripts/installApp.d.ts.map +1 -0
- package/dist/scripts/installApp.js +163 -0
- package/dist/scripts/installApp.js.map +1 -0
- package/dist/scripts/listStores.d.ts +3 -0
- package/dist/scripts/listStores.d.ts.map +1 -0
- package/dist/scripts/listStores.js +18 -0
- package/dist/scripts/listStores.js.map +1 -0
- package/dist/scripts/runDocker.d.ts +3 -0
- package/dist/scripts/runDocker.d.ts.map +1 -0
- package/dist/scripts/runDocker.js +88 -0
- package/dist/scripts/runDocker.js.map +1 -0
- package/dist/scripts/runDockerAuth.d.ts +3 -0
- package/dist/scripts/runDockerAuth.d.ts.map +1 -0
- package/dist/scripts/runDockerAuth.js +108 -0
- package/dist/scripts/runDockerAuth.js.map +1 -0
- package/dist/scripts/runDockerOffline.d.ts +3 -0
- package/dist/scripts/runDockerOffline.d.ts.map +1 -0
- package/dist/scripts/runDockerOffline.js +129 -0
- package/dist/scripts/runDockerOffline.js.map +1 -0
- package/dist/scripts/runDockerOfflineExplore.d.ts +3 -0
- package/dist/scripts/runDockerOfflineExplore.d.ts.map +1 -0
- package/dist/scripts/runDockerOfflineExplore.js +116 -0
- package/dist/scripts/runDockerOfflineExplore.js.map +1 -0
- package/dist/scripts/runIsolatedDockerOffline.d.ts +3 -0
- package/dist/scripts/runIsolatedDockerOffline.d.ts.map +1 -0
- package/dist/scripts/runIsolatedDockerOffline.js +351 -0
- package/dist/scripts/runIsolatedDockerOffline.js.map +1 -0
- package/dist/scripts/runOffline.d.ts +3 -0
- package/dist/scripts/runOffline.d.ts.map +1 -0
- package/dist/scripts/runOffline.js +521 -0
- package/dist/scripts/runOffline.js.map +1 -0
- package/dist/scripts/runOfflineE2e.d.ts +3 -0
- package/dist/scripts/runOfflineE2e.d.ts.map +1 -0
- package/dist/scripts/runOfflineE2e.js +408 -0
- package/dist/scripts/runOfflineE2e.js.map +1 -0
- package/dist/scripts/runOfflineFullTests.d.ts +3 -0
- package/dist/scripts/runOfflineFullTests.d.ts.map +1 -0
- package/dist/scripts/runOfflineFullTests.js +1456 -0
- package/dist/scripts/runOfflineFullTests.js.map +1 -0
- package/dist/scripts/runSupermachine.d.ts +3 -0
- package/dist/scripts/runSupermachine.d.ts.map +1 -0
- package/dist/scripts/runSupermachine.js +474 -0
- package/dist/scripts/runSupermachine.js.map +1 -0
- package/dist/scripts/runSupermachineAuth.d.ts +3 -0
- package/dist/scripts/runSupermachineAuth.d.ts.map +1 -0
- package/dist/scripts/runSupermachineAuth.js +454 -0
- package/dist/scripts/runSupermachineAuth.js.map +1 -0
- package/dist/scripts/runTests.d.ts +3 -0
- package/dist/scripts/runTests.d.ts.map +1 -0
- package/dist/scripts/runTests.js +278 -0
- package/dist/scripts/runTests.js.map +1 -0
- package/dist/scripts/runVm.d.ts +3 -0
- package/dist/scripts/runVm.d.ts.map +1 -0
- package/dist/scripts/runVm.js +524 -0
- package/dist/scripts/runVm.js.map +1 -0
- package/dist/scripts/runVmAuth.d.ts +3 -0
- package/dist/scripts/runVmAuth.d.ts.map +1 -0
- package/dist/scripts/runVmAuth.js +475 -0
- package/dist/scripts/runVmAuth.js.map +1 -0
- package/dist/scripts/runVmScript.d.ts +3 -0
- package/dist/scripts/runVmScript.d.ts.map +1 -0
- package/dist/scripts/runVmScript.js +242 -0
- package/dist/scripts/runVmScript.js.map +1 -0
- package/dist/scripts/setupTestDb.d.ts +3 -0
- package/dist/scripts/setupTestDb.d.ts.map +1 -0
- package/dist/scripts/setupTestDb.js +61 -0
- package/dist/scripts/setupTestDb.js.map +1 -0
- package/dist/scripts/verifyContracts.d.ts +3 -0
- package/dist/scripts/verifyContracts.d.ts.map +1 -0
- package/dist/scripts/verifyContracts.js +258 -0
- package/dist/scripts/verifyContracts.js.map +1 -0
- package/dist/scripts/verifyRestContracts.d.ts +3 -0
- package/dist/scripts/verifyRestContracts.d.ts.map +1 -0
- package/dist/scripts/verifyRestContracts.js +237 -0
- package/dist/scripts/verifyRestContracts.js.map +1 -0
- package/dist/vite/offlineConfig.d.ts +34 -0
- package/dist/vite/offlineConfig.d.ts.map +1 -0
- package/dist/vite/offlineConfig.js +61 -0
- package/dist/vite/offlineConfig.js.map +1 -0
- package/dist/vite/onlineConfig.d.ts +42 -0
- package/dist/vite/onlineConfig.d.ts.map +1 -0
- package/dist/vite/onlineConfig.js +56 -0
- package/dist/vite/onlineConfig.js.map +1 -0
- package/docker/Dockerfile +67 -0
- package/docker/Dockerfile.vm +137 -0
- package/docker/README.md +50 -0
- package/docker/entrypoint.sh +198 -0
- package/package.json +85 -0
- package/src/contracts/normalize.ts +96 -0
- package/src/contracts/normalizeHtml.ts +98 -0
- package/src/edge/ca.cnf +14 -0
- package/src/edge/ca.crt +22 -0
- package/src/edge/ca.key +28 -0
- package/src/edge/cert.ts +117 -0
- package/src/edge/edgeProxy.ts +390 -0
- package/src/edge/server.cnf +28 -0
- package/src/edge/server.crt +26 -0
- package/src/edge/server.key +28 -0
- package/src/index.ts +67 -0
- package/src/lib/buildSourceBundle.ts +197 -0
- package/src/lib/freePort.ts +33 -0
- package/src/lib/functionBuild.ts +490 -0
- package/src/lib/neonWsProxy.ts +124 -0
- package/src/lib/sourceZipUpload.ts +168 -0
- package/src/lib/stealthLaunch.ts +57 -0
- package/src/lib/storeAutomation.ts +110 -0
- package/src/playwright/baseConfig.ts +120 -0
- package/src/playwright/globalSetup.ts +179 -0
- package/src/playwright/index.ts +11 -0
- package/src/probes/fonts.ts +279 -0
- package/src/probes/mirror.ts +283 -0
- package/src/probes/runProbe.ts +257 -0
- package/src/probes/types.ts +73 -0
- package/src/scripts/addStore.ts +59 -0
- package/src/scripts/buildDockerImage.ts +66 -0
- package/src/scripts/captureAuth.ts +145 -0
- package/src/scripts/captureContracts.ts +675 -0
- package/src/scripts/captureRestContracts.ts +319 -0
- package/src/scripts/checkOperationCoverage.ts +365 -0
- package/src/scripts/cleanupStores.ts +91 -0
- package/src/scripts/createStores.ts +77 -0
- package/src/scripts/deployAppVersion.ts +692 -0
- package/src/scripts/devOnlineBackend.ts +141 -0
- package/src/scripts/installApp.ts +188 -0
- package/src/scripts/listStores.ts +19 -0
- package/src/scripts/runDockerAuth.ts +120 -0
- package/src/scripts/runOffline.ts +577 -0
- package/src/scripts/runOfflineFullTests.ts +1634 -0
- package/src/scripts/runTests.ts +306 -0
- package/src/scripts/runVm.ts +562 -0
- package/src/scripts/runVmAuth.ts +541 -0
- package/src/scripts/runVmScript.ts +282 -0
- package/src/scripts/setupTestDb.ts +71 -0
- package/src/scripts/verifyContracts.ts +310 -0
- package/src/scripts/verifyRestContracts.ts +275 -0
- package/src/vite/onlineConfig.ts +60 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge proxy — a real HTTPS reverse-proxy that takes Chromium
|
|
3
|
+
* requests for Shopify-shaped hostnames (test-shop.myshopify.com,
|
|
4
|
+
* admin.shopify.com, cdn.shopify.com) and dispatches them to the
|
|
5
|
+
* right internal mock based on Host + path.
|
|
6
|
+
*
|
|
7
|
+
* Why this exists: we abandoned Playwright's `page.route()` for
|
|
8
|
+
* routing because `route.fulfill({status: 302, …})` causes
|
|
9
|
+
* Chromium to follow redirects via its native network stack,
|
|
10
|
+
* bypassing route handlers — and our `test-shop.myshopify.com`
|
|
11
|
+
* domain resolves to real Shopify on the public internet, so any
|
|
12
|
+
* un-intercepted request leaks out of the test harness.
|
|
13
|
+
*
|
|
14
|
+
* The fix: drop down a network layer. With Chromium launched via
|
|
15
|
+
*
|
|
16
|
+
* --host-resolver-rules="MAP test-shop.myshopify.com 127.0.0.1:<edgePort>, …"
|
|
17
|
+
* --ignore-certificate-errors
|
|
18
|
+
*
|
|
19
|
+
* ALL browser traffic to those hostnames (initial requests, redirect
|
|
20
|
+
* follow-ups, sub-resources, XHR, fetch, service workers) lands at
|
|
21
|
+
* this proxy. There is no per-request interception layer to bypass.
|
|
22
|
+
* Redirects are handled by Chromium natively. The browser's URL bar
|
|
23
|
+
* stays correct.
|
|
24
|
+
*
|
|
25
|
+
* The proxy itself uses Node's `http` module (raw — no undici/fetch,
|
|
26
|
+
* which hangs against sibling-process loopback ports), forwards the
|
|
27
|
+
* request to the right internal mock, and streams the response back.
|
|
28
|
+
* 302/307/etc. responses are passed through unchanged; Chromium does
|
|
29
|
+
* the right thing with them.
|
|
30
|
+
*
|
|
31
|
+
* Cert: a static self-signed cert lives in `src/edge/cert.pem` +
|
|
32
|
+
* `src/edge/key.pem`, with SANs covering `*.myshopify.com`,
|
|
33
|
+
* `*.shopify.com`, etc. (See `src/edge/openssl.cnf`.) The cert is
|
|
34
|
+
* trusted because Chromium runs with `--ignore-certificate-errors`.
|
|
35
|
+
*/
|
|
36
|
+
import { createServer as createHttpsServer } from 'node:https';
|
|
37
|
+
import { request as httpRequest } from 'node:http';
|
|
38
|
+
import { TEST_CA_CERT_PEM, TEST_SERVER_CERT_PEM, TEST_SERVER_KEY_PEM, } from './cert.js';
|
|
39
|
+
/**
|
|
40
|
+
* Resolve an incoming request to (internalBase, overridePath).
|
|
41
|
+
*
|
|
42
|
+
* Host-based first (admin/cdn pick a backend), then path-based on
|
|
43
|
+
* the shop domain (/admin/api/, /api/ go to dedicated mocks).
|
|
44
|
+
*/
|
|
45
|
+
function dispatch(hostHeader, pathWithQuery, shopDomain, backends) {
|
|
46
|
+
// Strip ":port" — Host may include it; we only care about hostname.
|
|
47
|
+
const host = hostHeader.split(':')[0]?.toLowerCase() ?? '';
|
|
48
|
+
const path = pathWithQuery;
|
|
49
|
+
// ── admin.shopify.com → admin shell ─────────────────────
|
|
50
|
+
if (host === 'admin.shopify.com') {
|
|
51
|
+
return { internalBase: backends.adminShell, overridePath: path };
|
|
52
|
+
}
|
|
53
|
+
// ── fonts.shopifycdn.com → storefront (handles its /cdn/fonts route) ─
|
|
54
|
+
// The storefront mock owns the bundled font mirror produced by
|
|
55
|
+
// the `fonts` probe. Routing the real Shopify font-CDN hostname
|
|
56
|
+
// here means `font_face` filter output (which contains the real
|
|
57
|
+
// shopifycdn URL by design) just works in-browser.
|
|
58
|
+
if (host === 'fonts.shopifycdn.com') {
|
|
59
|
+
return { internalBase: backends.storefront, overridePath: `/__shopify-fonts${path}` };
|
|
60
|
+
}
|
|
61
|
+
// ── *.shopifycdn.com → storefront mirror ────────────────────
|
|
62
|
+
// Any other Shopify CDN subdomain not handled above falls back to
|
|
63
|
+
// the generic asset-mirror handler. Bundled by the `mirror` probe.
|
|
64
|
+
if (host.endsWith('.shopifycdn.com')) {
|
|
65
|
+
return {
|
|
66
|
+
internalBase: backends.storefront,
|
|
67
|
+
overridePath: `/__shopify-mirror/${host}${path}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ── cdn.shopify.com → split by path ─────────────────────
|
|
71
|
+
if (host === 'cdn.shopify.com') {
|
|
72
|
+
// App Bridge + Polaris CSS etc. live under /shopifycloud
|
|
73
|
+
// and /static, both served by the admin shell mock (which
|
|
74
|
+
// mirrors Shopify's CDN snapshot at packages/mock-admin/
|
|
75
|
+
// cdn-mirror).
|
|
76
|
+
if (path.startsWith('/shopifycloud/')) {
|
|
77
|
+
return { internalBase: backends.adminShell, overridePath: path };
|
|
78
|
+
}
|
|
79
|
+
if (path.startsWith('/static/')) {
|
|
80
|
+
return { internalBase: backends.adminShell, overridePath: path };
|
|
81
|
+
}
|
|
82
|
+
// Extension assets and theme assets live on the storefront
|
|
83
|
+
// mock. cdn.shopify.com/foo/bar/assets/baz.js → /assets/baz.js
|
|
84
|
+
if (path.startsWith('/extensions/')) {
|
|
85
|
+
return { internalBase: backends.storefront, overridePath: path };
|
|
86
|
+
}
|
|
87
|
+
const assetIdx = path.lastIndexOf('/assets/');
|
|
88
|
+
if (assetIdx >= 0) {
|
|
89
|
+
return {
|
|
90
|
+
internalBase: backends.storefront,
|
|
91
|
+
overridePath: path.slice(assetIdx),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Fall through: anything else on cdn.shopify.com → storefront.
|
|
95
|
+
return { internalBase: backends.storefront, overridePath: path };
|
|
96
|
+
}
|
|
97
|
+
// ── shop.myshopify.com (or any *.myshopify.com) ──────────
|
|
98
|
+
if (host === shopDomain.toLowerCase() || host.endsWith('.myshopify.com')) {
|
|
99
|
+
if (path.startsWith('/admin/api/')) {
|
|
100
|
+
return { internalBase: backends.adminApi, overridePath: path };
|
|
101
|
+
}
|
|
102
|
+
if (path.startsWith('/api/')) {
|
|
103
|
+
return { internalBase: backends.storefrontApi, overridePath: path };
|
|
104
|
+
}
|
|
105
|
+
// Per-shop CDN proxy: theme assets, shopifycloud scripts,
|
|
106
|
+
// product images, fonts. Real Shopify hosts them all under
|
|
107
|
+
// `<shop>/cdn/*`. The mirror probe captures these into the
|
|
108
|
+
// shared mirror dir; serve from there transparently so any
|
|
109
|
+
// shop hostname resolves to mirrored bytes.
|
|
110
|
+
if (path.startsWith('/cdn/')) {
|
|
111
|
+
return {
|
|
112
|
+
internalBase: backends.storefront,
|
|
113
|
+
overridePath: `/__shopify-mirror/${host}${path}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return { internalBase: backends.storefront, overridePath: path };
|
|
117
|
+
}
|
|
118
|
+
// ── unknown host: best-effort → storefront ─────────────
|
|
119
|
+
// Chromium with host-resolver-rules wouldn't deliver an
|
|
120
|
+
// unmapped host here, but if someone hits this directly (a
|
|
121
|
+
// test using page.request with a custom host header, etc.)
|
|
122
|
+
// returning storefront 404s with a useful body is friendlier
|
|
123
|
+
// than connection refused.
|
|
124
|
+
return { internalBase: backends.storefront, overridePath: path };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Read a request body into a Buffer. Streaming would be more
|
|
128
|
+
* memory-efficient, but mock-sized POSTs are tiny (cart items,
|
|
129
|
+
* form data) and buffering keeps the proxy logic simple.
|
|
130
|
+
*/
|
|
131
|
+
function readBody(req) {
|
|
132
|
+
return new Promise((resolveBody, rejectBody) => {
|
|
133
|
+
const chunks = [];
|
|
134
|
+
req.on('data', (c) => chunks.push(c));
|
|
135
|
+
req.on('end', () => resolveBody(Buffer.concat(chunks)));
|
|
136
|
+
req.on('error', rejectBody);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/** Forward one request to the chosen internal mock and stream the response back. */
|
|
140
|
+
async function forwardOne(internalBase, overridePath, method, headers, body) {
|
|
141
|
+
const target = new URL(internalBase);
|
|
142
|
+
// Drop hop-by-hop headers and the original Host — we set Host
|
|
143
|
+
// to the internal mock's address so Hono's c.req.url is
|
|
144
|
+
// consistent.
|
|
145
|
+
const outHeaders = {};
|
|
146
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
147
|
+
if (!v)
|
|
148
|
+
continue;
|
|
149
|
+
const lower = k.toLowerCase();
|
|
150
|
+
if (lower === 'host' || lower === 'connection' || lower === 'keep-alive' || lower === 'transfer-encoding')
|
|
151
|
+
continue;
|
|
152
|
+
if (typeof v === 'string')
|
|
153
|
+
outHeaders[k] = v;
|
|
154
|
+
else if (Array.isArray(v))
|
|
155
|
+
outHeaders[k] = v.join(', ');
|
|
156
|
+
}
|
|
157
|
+
return new Promise((resolveReq, rejectReq) => {
|
|
158
|
+
const r = httpRequest({
|
|
159
|
+
hostname: target.hostname,
|
|
160
|
+
port: Number(target.port),
|
|
161
|
+
path: overridePath,
|
|
162
|
+
method,
|
|
163
|
+
headers: outHeaders,
|
|
164
|
+
}, (res) => {
|
|
165
|
+
const chunks = [];
|
|
166
|
+
res.on('data', (c) => chunks.push(c));
|
|
167
|
+
res.on('end', () => resolveReq({
|
|
168
|
+
status: res.statusCode ?? 502,
|
|
169
|
+
headers: res.headers,
|
|
170
|
+
body: Buffer.concat(chunks),
|
|
171
|
+
}));
|
|
172
|
+
res.on('error', rejectReq);
|
|
173
|
+
});
|
|
174
|
+
r.on('error', rejectReq);
|
|
175
|
+
if (body.length > 0)
|
|
176
|
+
r.write(body);
|
|
177
|
+
r.end();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Boot the edge HTTPS proxy. Returns a handle with the bound port
|
|
182
|
+
* and a `close()` to tear it down.
|
|
183
|
+
*/
|
|
184
|
+
export async function startEdgeProxy(opts) {
|
|
185
|
+
const server = createHttpsServer({
|
|
186
|
+
// Send server cert + CA chain so Chrome's chain validation
|
|
187
|
+
// sees a complete path even without `intermediate_certs`.
|
|
188
|
+
// Some Chrome versions are stricter about chain
|
|
189
|
+
// completeness when the CA is "private" (NSS-trusted only).
|
|
190
|
+
cert: `${TEST_SERVER_CERT_PEM}\n${TEST_CA_CERT_PEM}`,
|
|
191
|
+
key: TEST_SERVER_KEY_PEM,
|
|
192
|
+
}, async (req, res) => {
|
|
193
|
+
try {
|
|
194
|
+
const hostHeader = req.headers.host ?? '';
|
|
195
|
+
const pathWithQuery = req.url ?? '/';
|
|
196
|
+
const { internalBase, overridePath } = dispatch(hostHeader, pathWithQuery, opts.shopDomain, opts.backends);
|
|
197
|
+
const body = await readBody(req);
|
|
198
|
+
const proxied = await forwardOne(internalBase, overridePath, req.method ?? 'GET', req.headers, body);
|
|
199
|
+
// Strip headers that don't make sense to forward verbatim
|
|
200
|
+
// (Node decompressed the body for us; content-length will
|
|
201
|
+
// be wrong; transfer-encoding shouldn't survive a hop).
|
|
202
|
+
const outHeaders = {};
|
|
203
|
+
for (const [k, v] of Object.entries(proxied.headers)) {
|
|
204
|
+
if (!v)
|
|
205
|
+
continue;
|
|
206
|
+
const lower = k.toLowerCase();
|
|
207
|
+
if (lower === 'content-encoding' || lower === 'content-length' || lower === 'transfer-encoding')
|
|
208
|
+
continue;
|
|
209
|
+
if (typeof v === 'string')
|
|
210
|
+
outHeaders[k] = v;
|
|
211
|
+
else if (Array.isArray(v))
|
|
212
|
+
outHeaders[k] = v;
|
|
213
|
+
}
|
|
214
|
+
// CORS — the offline stack lives behind ONE edge proxy serving
|
|
215
|
+
// multiple Shopify origins (admin.shopify.com, cdn.shopify.com,
|
|
216
|
+
// *.myshopify.com). Any cross-origin XHR/fetch issued by the
|
|
217
|
+
// embedded app or by storefront JS would otherwise be blocked
|
|
218
|
+
// by Chrome with "TypeError: Failed to fetch" (the symptom in
|
|
219
|
+
// offline-full-stack tests that try to `fetch('https://cdn.
|
|
220
|
+
// shopify.com/...')` from an admin.shopify.com page). Real
|
|
221
|
+
// Shopify sets these on cdn.shopify.com responses too. Allow
|
|
222
|
+
// everything because this is a test-only proxy bound to
|
|
223
|
+
// 127.0.0.1 — no real traffic ever reaches it.
|
|
224
|
+
if (!outHeaders['Access-Control-Allow-Origin']) {
|
|
225
|
+
outHeaders['Access-Control-Allow-Origin'] = '*';
|
|
226
|
+
}
|
|
227
|
+
if (!outHeaders['Access-Control-Allow-Methods']) {
|
|
228
|
+
outHeaders['Access-Control-Allow-Methods'] =
|
|
229
|
+
'GET, POST, PUT, PATCH, DELETE, OPTIONS';
|
|
230
|
+
}
|
|
231
|
+
if (!outHeaders['Access-Control-Allow-Headers']) {
|
|
232
|
+
outHeaders['Access-Control-Allow-Headers'] = '*';
|
|
233
|
+
}
|
|
234
|
+
if (!outHeaders['Access-Control-Expose-Headers']) {
|
|
235
|
+
outHeaders['Access-Control-Expose-Headers'] = '*';
|
|
236
|
+
}
|
|
237
|
+
// Short-circuit CORS preflights (the upstream mock might not
|
|
238
|
+
// implement OPTIONS at all; serving them here is cheaper anyway).
|
|
239
|
+
if (req.method === 'OPTIONS') {
|
|
240
|
+
res.writeHead(204, outHeaders);
|
|
241
|
+
res.end();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
res.writeHead(proxied.status, outHeaders);
|
|
245
|
+
res.end(proxied.body);
|
|
246
|
+
if (process.env['TEST_OFFLINE_EDGE_DEBUG'] === 'true') {
|
|
247
|
+
console.log(`[edge] ${req.method} https://${hostHeader}${pathWithQuery} → ${internalBase}${overridePath} → ${proxied.status}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
console.error('[edge] error:', err.message);
|
|
252
|
+
res.writeHead(502, { 'content-type': 'text/plain' });
|
|
253
|
+
res.end(`edge proxy error: ${err.message}`);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
// Wait for listen() to either succeed OR error. Without an error
|
|
257
|
+
// handler, a failed bind (EADDRINUSE, EACCES on <1024 without
|
|
258
|
+
// privileges, no IPv6 stack when hostname='::', etc.) leaves the
|
|
259
|
+
// promise unresolved and the whole offline test run hangs silently.
|
|
260
|
+
const targetHost = opts.hostname ?? '127.0.0.1';
|
|
261
|
+
const targetPort = opts.port ?? 0;
|
|
262
|
+
// Wait for listen() to either succeed OR fail. Without explicit
|
|
263
|
+
// error/timeout handling, a failed bind (EADDRINUSE; EACCES on
|
|
264
|
+
// <1024 ports without privileges; a kernel that hangs on `::`
|
|
265
|
+
// dual-stack bind — the VM's libkrun does this) leaves the
|
|
266
|
+
// promise unresolved and the whole offline run stalls silently.
|
|
267
|
+
// The 10 s timeout surfaces any "listen never called back" case
|
|
268
|
+
// as a real error instead of a wedge.
|
|
269
|
+
await new Promise((resolveListen, rejectListen) => {
|
|
270
|
+
const timer = setTimeout(() => {
|
|
271
|
+
rejectListen(new Error(`edge proxy listen() did not call back within 10 s on ${targetHost}:${targetPort} ` +
|
|
272
|
+
`(no 'error' event, no 'listening' callback). Kernel issue? ` +
|
|
273
|
+
`Try '0.0.0.0' instead of '::'.`));
|
|
274
|
+
}, 10_000);
|
|
275
|
+
const onError = (err) => {
|
|
276
|
+
clearTimeout(timer);
|
|
277
|
+
server.off('error', onError);
|
|
278
|
+
rejectListen(new Error(`edge proxy bind failed on ${targetHost}:${targetPort}: ` +
|
|
279
|
+
`${err.code ?? '?'} ${err.message}`));
|
|
280
|
+
};
|
|
281
|
+
server.on('error', onError);
|
|
282
|
+
server.listen(targetPort, targetHost, () => {
|
|
283
|
+
clearTimeout(timer);
|
|
284
|
+
server.off('error', onError);
|
|
285
|
+
resolveListen();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
const addr = server.address();
|
|
289
|
+
return {
|
|
290
|
+
port: addr.port,
|
|
291
|
+
baseUrl: `https://${opts.hostname ?? '127.0.0.1'}:${addr.port}`,
|
|
292
|
+
close: () => new Promise((resolveClose, rejectClose) => {
|
|
293
|
+
server.close((err) => (err ? rejectClose(err) : resolveClose()));
|
|
294
|
+
}),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=edgeProxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edgeProxy.js","sourceRoot":"","sources":["../../src/edge/edgeProxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeShim.d.ts","sourceRoot":"","sources":["../../src/edge/nodeShim.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-side socket-layer shim that routes Shopify hostnames to the
|
|
3
|
+
* edge proxy. Mirrors what `--host-resolver-rules` does for Chromium,
|
|
4
|
+
* but for the Node runtime that Playwright tests execute in.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists:
|
|
7
|
+
* Chromium's `--host-resolver-rules` only affects the browser.
|
|
8
|
+
* Node's HTTP stack — used by Playwright's `page.request`, by
|
|
9
|
+
* `globalThis.fetch` (undici-based), and by anything calling
|
|
10
|
+
* `node:http` / `node:https` directly — uses Node's own DNS. A
|
|
11
|
+
* test that does `page.request.get('https://test-shop.myshopify.com/x')`
|
|
12
|
+
* would resolve that hostname via Node's DNS and hit real Shopify
|
|
13
|
+
* on the public internet.
|
|
14
|
+
*
|
|
15
|
+
* What this does:
|
|
16
|
+
* - Patches `dns.lookup` so `*.shopify.com` / `*.myshopify.com`
|
|
17
|
+
* resolve to `127.0.0.1`.
|
|
18
|
+
* - Patches `net.createConnection` (the path every HTTPS client
|
|
19
|
+
* eventually takes, including undici) so when the resolved
|
|
20
|
+
* address is `127.0.0.1` AND the original hostname was a
|
|
21
|
+
* Shopify host, the connect targets the edge port instead of
|
|
22
|
+
* the original 80/443.
|
|
23
|
+
*
|
|
24
|
+
* Net effect: any Node-side HTTP/HTTPS request to a Shopify
|
|
25
|
+
* hostname lands on our edge proxy. From the calling code's
|
|
26
|
+
* perspective, it's hitting real Shopify; only the kernel-adjacent
|
|
27
|
+
* shim knows the difference. TLS SNI carries the original hostname
|
|
28
|
+
* to the edge, which presents a cert with broad SANs for it.
|
|
29
|
+
*
|
|
30
|
+
* Loading: import this module BEFORE Playwright loads its HTTP
|
|
31
|
+
* machinery — `NODE_OPTIONS=--import <path-to-built-shim.js>` is
|
|
32
|
+
* the canonical hook (Node 20.6+). The orchestrator sets this when
|
|
33
|
+
* it spawns Playwright.
|
|
34
|
+
*
|
|
35
|
+
* Env: reads `E2E_MOCK_EDGE_PORT` at module load. If unset, the
|
|
36
|
+
* shim no-ops (so loading it in non-offline contexts is harmless).
|
|
37
|
+
*/
|
|
38
|
+
import dns from 'node:dns';
|
|
39
|
+
import net from 'node:net';
|
|
40
|
+
const SHOPIFY_HOSTNAME = /(?:^|\.)(my)?shopify\.com$/i;
|
|
41
|
+
const EDGE_PORT = process.env['E2E_MOCK_EDGE_PORT']
|
|
42
|
+
? Number(process.env['E2E_MOCK_EDGE_PORT'])
|
|
43
|
+
: undefined;
|
|
44
|
+
if (EDGE_PORT && Number.isFinite(EDGE_PORT)) {
|
|
45
|
+
installDnsPatch();
|
|
46
|
+
installConnectPatch(EDGE_PORT);
|
|
47
|
+
// Accept self-signed certs at the Node TLS layer. The edge proxy
|
|
48
|
+
// serves a self-signed cert for *.myshopify.com / *.shopify.com
|
|
49
|
+
// (see packages/runner/src/edge/cert.ts) — Chromium already
|
|
50
|
+
// accepts it via the `--ignore-certificate-errors` launch flag,
|
|
51
|
+
// and Playwright's APIRequestContext inherits the BrowserContext's
|
|
52
|
+
// `ignoreHTTPSErrors: true`. But raw `globalThis.fetch` (undici)
|
|
53
|
+
// and direct `https.request` calls in the test process have no
|
|
54
|
+
// per-call override — they need this process-level flag.
|
|
55
|
+
//
|
|
56
|
+
// SCOPE: this affects ALL TLS in the test process, not just
|
|
57
|
+
// Shopify hostnames. That's acceptable here because:
|
|
58
|
+
// 1. The test process should never make TLS connections that
|
|
59
|
+
// depend on cert verification — production Shopify code
|
|
60
|
+
// runs in the Remix backend (a separate process), not here.
|
|
61
|
+
// 2. The shim already aggressively redirects to localhost via
|
|
62
|
+
// DNS+connect patches; cert verification on those would
|
|
63
|
+
// always fail anyway (hostname mismatch).
|
|
64
|
+
// If a future test genuinely needs strict TLS verification against
|
|
65
|
+
// a real public host, it should reset this flag locally for that
|
|
66
|
+
// request.
|
|
67
|
+
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
|
68
|
+
if (process.env['E2E_OFFLINE_SHIM_DEBUG'] === 'true') {
|
|
69
|
+
console.error(`[node-shim] Shopify hostname routing → 127.0.0.1:${EDGE_PORT}; ` +
|
|
70
|
+
`NODE_TLS_REJECT_UNAUTHORIZED=0 (test-process scope)`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (process.env['E2E_OFFLINE_SHIM_DEBUG'] === 'true') {
|
|
74
|
+
console.error('[node-shim] E2E_MOCK_EDGE_PORT not set — shim is a no-op');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Patch `dns.lookup` so Shopify hostnames resolve to 127.0.0.1.
|
|
78
|
+
* Every HTTP client in Node ultimately calls this (or `dns.lookup`
|
|
79
|
+
* with the `family`/`hints` options form). We handle both shapes.
|
|
80
|
+
*
|
|
81
|
+
* Don't patch `dns.resolve*` — those do direct DNS queries (used
|
|
82
|
+
* for explicit DNS-record inspection, not for connection setup);
|
|
83
|
+
* patching them would surprise tests that genuinely want to query
|
|
84
|
+
* DNS records.
|
|
85
|
+
*/
|
|
86
|
+
function installDnsPatch() {
|
|
87
|
+
const origLookup = dns.lookup;
|
|
88
|
+
/**
|
|
89
|
+
* Signature variants to support:
|
|
90
|
+
* dns.lookup(hostname, callback)
|
|
91
|
+
* dns.lookup(hostname, family, callback)
|
|
92
|
+
* dns.lookup(hostname, options, callback)
|
|
93
|
+
*/
|
|
94
|
+
const patched = function patched(hostname, optionsOrCallback, maybeCallback) {
|
|
95
|
+
if (!SHOPIFY_HOSTNAME.test(hostname)) {
|
|
96
|
+
// Pass through to the original — same arity & types.
|
|
97
|
+
return origLookup.call(dns, hostname, optionsOrCallback, maybeCallback);
|
|
98
|
+
}
|
|
99
|
+
// Synthesize the response Node's resolver would have produced.
|
|
100
|
+
const cb = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
|
|
101
|
+
const opts = typeof optionsOrCallback === 'object' && optionsOrCallback !== null
|
|
102
|
+
? optionsOrCallback
|
|
103
|
+
: { family: typeof optionsOrCallback === 'number' ? optionsOrCallback : 0 };
|
|
104
|
+
if (typeof cb !== 'function') {
|
|
105
|
+
// No callback → Promise form. Node 18+ supports this via
|
|
106
|
+
// `dns/promises`, but `dns.lookup` itself is callback-only.
|
|
107
|
+
// If someone calls it without a callback, that's their bug —
|
|
108
|
+
// throw the same TypeError Node would.
|
|
109
|
+
throw new TypeError('dns.lookup: callback required');
|
|
110
|
+
}
|
|
111
|
+
const address = { address: '127.0.0.1', family: 4 };
|
|
112
|
+
if (opts.all) {
|
|
113
|
+
cb(null, [address]);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
cb(null, address.address, address.family);
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
};
|
|
120
|
+
// `dns.lookup` is a property of the `dns` module object; reassigning
|
|
121
|
+
// it affects every consumer that does `dns.lookup(...)` (which is
|
|
122
|
+
// every Node HTTP client). `Object.defineProperty` rather than `=`
|
|
123
|
+
// to avoid surprise from frozen properties in future Node versions.
|
|
124
|
+
Object.defineProperty(dns, 'lookup', { value: patched, writable: true, configurable: true });
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Patch `net.createConnection` (aliased as `net.connect`) so that
|
|
128
|
+
* outbound TCP connections to Shopify hosts get their port rewritten
|
|
129
|
+
* to the edge port. The hostname is preserved on the socket, so TLS
|
|
130
|
+
* SNI carries it through and the edge sees the real Host header.
|
|
131
|
+
*
|
|
132
|
+
* Detection: we look at the `host` option (most callers) or the
|
|
133
|
+
* `hostname` option (some), AND/OR the path option (Unix sockets,
|
|
134
|
+
* irrelevant here). If neither matches, we pass through.
|
|
135
|
+
*/
|
|
136
|
+
function installConnectPatch(edgePort) {
|
|
137
|
+
/**
|
|
138
|
+
* Decide whether a connect() call should be rewritten to the edge.
|
|
139
|
+
*
|
|
140
|
+
* Two triggers:
|
|
141
|
+
* 1. `host` is a Shopify hostname (e.g. callers that pass
|
|
142
|
+
* hostname+port to net.connect and let the kernel resolve
|
|
143
|
+
* DNS during connect).
|
|
144
|
+
* 2. `host` is loopback (127.0.0.1 / ::1) AND port is 80/443.
|
|
145
|
+
* This catches clients that resolve DNS themselves (undici
|
|
146
|
+
* does this — calls dns.lookup, then connects with the IP).
|
|
147
|
+
* Our dns.lookup patch maps Shopify hostnames to 127.0.0.1;
|
|
148
|
+
* the only way loopback:80/443 happens in the test process
|
|
149
|
+
* is via that redirected resolution.
|
|
150
|
+
*/
|
|
151
|
+
function parseAndMaybeRewrite(args) {
|
|
152
|
+
const first = args[0];
|
|
153
|
+
let opts = null;
|
|
154
|
+
if (typeof first === 'object' && first !== null && !Array.isArray(first)) {
|
|
155
|
+
opts = first;
|
|
156
|
+
}
|
|
157
|
+
else if (typeof first === 'number') {
|
|
158
|
+
const second = args[1];
|
|
159
|
+
const host = typeof second === 'string' ? second : undefined;
|
|
160
|
+
opts = host !== undefined ? { port: first, host } : { port: first };
|
|
161
|
+
}
|
|
162
|
+
if (!opts)
|
|
163
|
+
return null;
|
|
164
|
+
const host = opts.host ?? opts.hostname;
|
|
165
|
+
const isShopifyHost = !!host && SHOPIFY_HOSTNAME.test(host);
|
|
166
|
+
const isLoopback = host === '127.0.0.1' || host === '::1' || host === '::ffff:127.0.0.1';
|
|
167
|
+
const isWellKnownPort = opts.port === 80 || opts.port === 443;
|
|
168
|
+
const shouldRedirect = isShopifyHost || (isLoopback && isWellKnownPort);
|
|
169
|
+
if (!shouldRedirect)
|
|
170
|
+
return null;
|
|
171
|
+
if (process.env['E2E_OFFLINE_SHIM_DEBUG'] === 'true') {
|
|
172
|
+
console.error(`[node-shim] connect ${host}:${opts.port ?? '?'} → 127.0.0.1:${edgePort}`);
|
|
173
|
+
}
|
|
174
|
+
return { ...opts, port: edgePort };
|
|
175
|
+
}
|
|
176
|
+
// ── 1. net.createConnection / net.connect ───────────────────
|
|
177
|
+
// Path used by `http.request` / `https.request` (Node's built-in
|
|
178
|
+
// HTTP clients) and many libraries built on them.
|
|
179
|
+
const origCreate = net.createConnection;
|
|
180
|
+
const patchedCreate = function patchedCreate(...args) {
|
|
181
|
+
const rewritten = parseAndMaybeRewrite(args);
|
|
182
|
+
if (rewritten) {
|
|
183
|
+
const listener = args.find((a) => typeof a === 'function');
|
|
184
|
+
return listener
|
|
185
|
+
? origCreate.call(net, rewritten, listener)
|
|
186
|
+
: origCreate.call(net, rewritten);
|
|
187
|
+
}
|
|
188
|
+
return origCreate.apply(net, args);
|
|
189
|
+
};
|
|
190
|
+
Object.defineProperty(net, 'createConnection', {
|
|
191
|
+
value: patchedCreate,
|
|
192
|
+
writable: true,
|
|
193
|
+
configurable: true,
|
|
194
|
+
});
|
|
195
|
+
Object.defineProperty(net, 'connect', {
|
|
196
|
+
value: patchedCreate,
|
|
197
|
+
writable: true,
|
|
198
|
+
configurable: true,
|
|
199
|
+
});
|
|
200
|
+
// ── 2. net.Socket.prototype.connect ─────────────────────────
|
|
201
|
+
// Path used by undici (Node's built-in `fetch`). undici creates
|
|
202
|
+
// a Socket directly and calls .connect() on it — bypassing
|
|
203
|
+
// net.createConnection entirely. Patch the prototype method so
|
|
204
|
+
// it gets the same rewrite treatment.
|
|
205
|
+
const origSocketConnect = net.Socket.prototype.connect;
|
|
206
|
+
net.Socket.prototype.connect = function patchedSocketConnect(...args) {
|
|
207
|
+
const rewritten = parseAndMaybeRewrite(args);
|
|
208
|
+
if (rewritten) {
|
|
209
|
+
const listener = args.find((a) => typeof a === 'function');
|
|
210
|
+
return listener
|
|
211
|
+
? origSocketConnect.call(this, rewritten, listener)
|
|
212
|
+
: origSocketConnect.call(this, rewritten);
|
|
213
|
+
}
|
|
214
|
+
return origSocketConnect.apply(this, args);
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=nodeShim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeShim.js","sourceRoot":"","sources":["../../src/edge/nodeShim.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API of @essential-apps/shopify-test-runner.
|
|
3
|
+
*
|
|
4
|
+
* The CLI binaries (shopify-test-run-docker, etc.) are exposed via
|
|
5
|
+
* the `bin` field in package.json — they don't import from this
|
|
6
|
+
* file. This module re-exports a few utilities that consuming apps
|
|
7
|
+
* occasionally use programmatically (port checking, stealth browser
|
|
8
|
+
* launch).
|
|
9
|
+
*
|
|
10
|
+
* Most apps will only import from this package's `/playwright`
|
|
11
|
+
* subpath:
|
|
12
|
+
* import { definePlaywrightConfig } from
|
|
13
|
+
* '@essential-apps/shopify-test-runner/playwright';
|
|
14
|
+
*/
|
|
15
|
+
export { isPortFree, findFreePort } from './lib/freePort.js';
|
|
16
|
+
export { launchStealthBrowser, stealthLaunchArgs } from './lib/stealthLaunch.js';
|
|
17
|
+
/**
|
|
18
|
+
* Shopify Functions JS-source → deployable .wasm pipeline. Builds
|
|
19
|
+
* without the Shopify CLI; downloads stock Javy + the Shopify-CDN
|
|
20
|
+
* plugin .wasm on first use. See `./lib/functionBuild.ts` for the
|
|
21
|
+
* full rationale.
|
|
22
|
+
*/
|
|
23
|
+
export { buildFunctionWasm, ensureJavy, ensureJavyPlugin, parseFunctionToml, JAVY_VERSION, PLUGIN_URL, } from './lib/functionBuild.js';
|
|
24
|
+
export type { BuildFunctionWasmOptions, BuildFunctionWasmResult, FunctionTarget, ParsedFunctionToml, } from './lib/functionBuild.js';
|
|
25
|
+
/**
|
|
26
|
+
* App Management API source-zip upload helpers — used together
|
|
27
|
+
* when deploying app versions that contain a function or
|
|
28
|
+
* post-purchase extension (their binary artifacts don't fit
|
|
29
|
+
* inline in the `source` manifest).
|
|
30
|
+
*/
|
|
31
|
+
export { requestSourceUploadUrl, uploadSourceToSignedUrl, } from './lib/sourceZipUpload.js';
|
|
32
|
+
export type { RequestSourceUploadUrlOptions, UploadSourceOptions, } from './lib/sourceZipUpload.js';
|
|
33
|
+
/**
|
|
34
|
+
* Source-bundle (zip) assembly. Produces the artifact uploaded to
|
|
35
|
+
* GCS and referenced via `AppVersionInput.sourceUrl`.
|
|
36
|
+
*/
|
|
37
|
+
export { buildSourceBundle, readExtensionFilesAsBuffers, } from './lib/buildSourceBundle.js';
|
|
38
|
+
export type { BuildSourceBundleOptions, ManifestModule, } from './lib/buildSourceBundle.js';
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEjF;;;;;GAKG;AACH,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,UAAU,GACX,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC;;;;;GAKG;AACH,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC;;;GAGG;AACH,OAAO,EACL,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,wBAAwB,EACxB,cAAc,GACf,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API of @essential-apps/shopify-test-runner.
|
|
3
|
+
*
|
|
4
|
+
* The CLI binaries (shopify-test-run-docker, etc.) are exposed via
|
|
5
|
+
* the `bin` field in package.json — they don't import from this
|
|
6
|
+
* file. This module re-exports a few utilities that consuming apps
|
|
7
|
+
* occasionally use programmatically (port checking, stealth browser
|
|
8
|
+
* launch).
|
|
9
|
+
*
|
|
10
|
+
* Most apps will only import from this package's `/playwright`
|
|
11
|
+
* subpath:
|
|
12
|
+
* import { definePlaywrightConfig } from
|
|
13
|
+
* '@essential-apps/shopify-test-runner/playwright';
|
|
14
|
+
*/
|
|
15
|
+
export { isPortFree, findFreePort } from './lib/freePort.js';
|
|
16
|
+
export { launchStealthBrowser, stealthLaunchArgs } from './lib/stealthLaunch.js';
|
|
17
|
+
/**
|
|
18
|
+
* Shopify Functions JS-source → deployable .wasm pipeline. Builds
|
|
19
|
+
* without the Shopify CLI; downloads stock Javy + the Shopify-CDN
|
|
20
|
+
* plugin .wasm on first use. See `./lib/functionBuild.ts` for the
|
|
21
|
+
* full rationale.
|
|
22
|
+
*/
|
|
23
|
+
export { buildFunctionWasm, ensureJavy, ensureJavyPlugin, parseFunctionToml, JAVY_VERSION, PLUGIN_URL, } from './lib/functionBuild.js';
|
|
24
|
+
/**
|
|
25
|
+
* App Management API source-zip upload helpers — used together
|
|
26
|
+
* when deploying app versions that contain a function or
|
|
27
|
+
* post-purchase extension (their binary artifacts don't fit
|
|
28
|
+
* inline in the `source` manifest).
|
|
29
|
+
*/
|
|
30
|
+
export { requestSourceUploadUrl, uploadSourceToSignedUrl, } from './lib/sourceZipUpload.js';
|
|
31
|
+
/**
|
|
32
|
+
* Source-bundle (zip) assembly. Produces the artifact uploaded to
|
|
33
|
+
* GCS and referenced via `AppVersionInput.sourceUrl`.
|
|
34
|
+
*/
|
|
35
|
+
export { buildSourceBundle, readExtensionFilesAsBuffers, } from './lib/buildSourceBundle.js';
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEjF;;;;;GAKG;AACH,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,UAAU,GACX,MAAM,wBAAwB,CAAC;AAQhC;;;;;GAKG;AACH,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAMlC;;;GAGG;AACH,OAAO,EACL,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC"}
|