@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 @@
|
|
|
1
|
+
{"version":3,"file":"globalSetup.js","sourceRoot":"","sources":["../../src/playwright/globalSetup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Playwright preset for @essential-apps/shopify-test-runner.
|
|
3
|
+
* Imported by the consuming app's `playwright.config.ts`:
|
|
4
|
+
*
|
|
5
|
+
* import { definePlaywrightConfig } from
|
|
6
|
+
* '@essential-apps/shopify-test-runner/playwright';
|
|
7
|
+
*/
|
|
8
|
+
export { definePlaywrightConfig, type DefinePlaywrightConfigOptions, } from './baseConfig.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,GACnC,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Playwright preset for @essential-apps/shopify-test-runner.
|
|
3
|
+
* Imported by the consuming app's `playwright.config.ts`:
|
|
4
|
+
*
|
|
5
|
+
* import { definePlaywrightConfig } from
|
|
6
|
+
* '@essential-apps/shopify-test-runner/playwright';
|
|
7
|
+
*/
|
|
8
|
+
export { definePlaywrightConfig, } from './baseConfig.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,GAEvB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/probes/fonts.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AASxC,QAAA,MAAM,KAAK,EAAE,KAmKZ,CAAC;AA0DF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Font-mirror probe.
|
|
3
|
+
*
|
|
4
|
+
* Goal: download the actual font WOFF2 files Shopify ships, plus
|
|
5
|
+
* a manifest mapping `<family>_<handle>` → `{ url, file }`, so the
|
|
6
|
+
* offline storefront mock can serve byte-identical fonts at
|
|
7
|
+
* byte-identical URLs.
|
|
8
|
+
*
|
|
9
|
+
* Why this can't be a static download script: Shopify's font CDN
|
|
10
|
+
* URLs have a content hash baked in
|
|
11
|
+
* `https://fonts.shopifycdn.com/assistant/assistant_n4.<hash>.woff2`
|
|
12
|
+
* and that hash isn't published anywhere — you have to render a real
|
|
13
|
+
* storefront, observe what URL gets emitted by the Liquid
|
|
14
|
+
* `font_face` filter, then fetch.
|
|
15
|
+
*
|
|
16
|
+
* What we do:
|
|
17
|
+
* 1. Open the online store's homepage. The theme's
|
|
18
|
+
* `settings_data.json` picks fonts via handles; `font_face`
|
|
19
|
+
* renders @font-face rules whose URLs point at fonts.shopifycdn.com.
|
|
20
|
+
* 2. Observe page network. Every fonts.shopifycdn.com request is
|
|
21
|
+
* a font Shopify is actually using for this theme/store.
|
|
22
|
+
* 3. Download each font file with the original URL preserved.
|
|
23
|
+
* 4. Save under:
|
|
24
|
+
* packages/themes/themes/_shopify-fonts/<family>/<original-filename>
|
|
25
|
+
* and write a manifest.json:
|
|
26
|
+
* {
|
|
27
|
+
* "assistant_n4": {
|
|
28
|
+
* "family": "assistant",
|
|
29
|
+
* "handle": "assistant_n4",
|
|
30
|
+
* "file": "assistant_n4.f55fa3ec4ee20.woff2",
|
|
31
|
+
* "url": "https://fonts.shopifycdn.com/assistant/assistant_n4.f55fa3ec4ee20.woff2"
|
|
32
|
+
* },
|
|
33
|
+
* ...
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* Reading the manifest at runtime: `font_face` filter parses the
|
|
37
|
+
* font handle from its Liquid argument and emits the @font-face
|
|
38
|
+
* with the URL from the manifest. The storefront mock + edge proxy
|
|
39
|
+
* serve fonts.shopifycdn.com/<family>/<file> from the bundled
|
|
40
|
+
* directory.
|
|
41
|
+
*
|
|
42
|
+
* To capture fonts the online store doesn't currently use, change the
|
|
43
|
+
* theme's font settings in the merchant's admin first, then re-run
|
|
44
|
+
* this probe. (We could automate that too — argue for a follow-up
|
|
45
|
+
* if it becomes a pain.)
|
|
46
|
+
*/
|
|
47
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
48
|
+
import { resolve, basename } from 'node:path';
|
|
49
|
+
const probe = {
|
|
50
|
+
name: 'fonts',
|
|
51
|
+
description: 'Mirror Shopify-hosted fonts the online store uses + write a manifest the offline mock reads.',
|
|
52
|
+
outputDir: 'packages/themes/themes/_shopify-fonts',
|
|
53
|
+
async run(ctx) {
|
|
54
|
+
const passwordFromEnv = process.env['STOREFRONT_PASSWORD'] ?? '';
|
|
55
|
+
const homeUrl = `https://${ctx.store.shop}/`;
|
|
56
|
+
console.log(`[fonts] navigating to ${homeUrl}`);
|
|
57
|
+
// Capture every Shopify-hosted font URL the page references.
|
|
58
|
+
// Two flavours both end up serving the same blob:
|
|
59
|
+
// - canonical: https://fonts.shopifycdn.com/<family>/<file>.woff2
|
|
60
|
+
// (emitted by Dawn's @font-face `src:` via the
|
|
61
|
+
// `font_url` Liquid filter)
|
|
62
|
+
// - per-shop: https://<shop>.myshopify.com/cdn/fonts/<family>/<file>.woff2
|
|
63
|
+
// (emitted by `<link rel="preload" as="font">` and
|
|
64
|
+
// some CSS variable assignments)
|
|
65
|
+
// We listen on requests AND scrape the rendered DOM so both
|
|
66
|
+
// flavours surface; everything gets normalized back to the
|
|
67
|
+
// canonical fonts.shopifycdn.com URL before download (the manifest
|
|
68
|
+
// is keyed on the canonical URL because that's what our offline
|
|
69
|
+
// `font_face` filter emits).
|
|
70
|
+
const fontUrls = new Set();
|
|
71
|
+
const captureUrl = (raw) => {
|
|
72
|
+
const canonical = normalizeToShopifycdn(raw);
|
|
73
|
+
if (canonical)
|
|
74
|
+
fontUrls.add(canonical);
|
|
75
|
+
};
|
|
76
|
+
ctx.page.on('request', (req) => captureUrl(req.url()));
|
|
77
|
+
await ctx.page.goto(homeUrl, { waitUntil: 'domcontentloaded' });
|
|
78
|
+
// Storefront-password gate: type the password from .env.test and
|
|
79
|
+
// submit. Skips silently if the store doesn't require one.
|
|
80
|
+
const passwordField = ctx.page.locator('input[name="password"], input#password');
|
|
81
|
+
if (await passwordField.count().catch(() => 0)) {
|
|
82
|
+
if (!passwordFromEnv) {
|
|
83
|
+
throw new Error(`Store ${ctx.store.shop} has a password gate but STOREFRONT_PASSWORD ` +
|
|
84
|
+
`is not set in .env.test. Set it or use a public store.`);
|
|
85
|
+
}
|
|
86
|
+
console.log('[fonts] entering storefront password');
|
|
87
|
+
await passwordField.first().fill(passwordFromEnv);
|
|
88
|
+
await ctx.page.locator('button[type="submit"], input[type="submit"]').first().click();
|
|
89
|
+
await ctx.page.waitForLoadState('domcontentloaded');
|
|
90
|
+
}
|
|
91
|
+
// Wait for network idle so any deferred font loads (e.g. lazy
|
|
92
|
+
// CSS imports) have a chance to fire.
|
|
93
|
+
await ctx.page.waitForLoadState('networkidle', { timeout: 30_000 }).catch(() => {
|
|
94
|
+
console.warn('[fonts] networkidle timed out — proceeding with what we have');
|
|
95
|
+
});
|
|
96
|
+
// Some themes embed all @font-face rules but don't actually
|
|
97
|
+
// fetch the WOFF2 until a glyph is needed. As a backstop, scrape
|
|
98
|
+
// the rendered DOM for both canonical and per-shop font URLs.
|
|
99
|
+
const dom = await ctx.page.content();
|
|
100
|
+
for (const m of dom.matchAll(/https:\/\/fonts\.shopifycdn\.com\/[^"')\s]+/g)) {
|
|
101
|
+
captureUrl(m[0]);
|
|
102
|
+
}
|
|
103
|
+
for (const m of dom.matchAll(/https?:\/\/[^"')\s]+\/cdn\/fonts\/[^"')\s]+/g)) {
|
|
104
|
+
captureUrl(m[0]);
|
|
105
|
+
}
|
|
106
|
+
// Some preload links use protocol-relative `//<shop>/cdn/fonts/...`.
|
|
107
|
+
for (const m of dom.matchAll(/\/\/[^"')\s]+\/cdn\/fonts\/[^"')\s]+/g)) {
|
|
108
|
+
captureUrl('https:' + m[0]);
|
|
109
|
+
}
|
|
110
|
+
if (fontUrls.size === 0) {
|
|
111
|
+
throw new Error(`No fonts.shopifycdn.com URLs observed on ${homeUrl}. ` +
|
|
112
|
+
`The theme may be using a system font (mono/sans/serif handles), ` +
|
|
113
|
+
`in which case no Shopify fonts are needed — the mock's system stack ` +
|
|
114
|
+
`is already correct.`);
|
|
115
|
+
}
|
|
116
|
+
console.log(`[fonts] discovered ${fontUrls.size} font URL(s)`);
|
|
117
|
+
// Download each font + record metadata. Use the page's request
|
|
118
|
+
// context so cookies + headers match what the browser sent
|
|
119
|
+
// (avoids 403s on hashed URLs that key on referer etc.).
|
|
120
|
+
const manifest = {};
|
|
121
|
+
let downloaded = 0;
|
|
122
|
+
for (const url of fontUrls) {
|
|
123
|
+
const parsed = parseFontUrl(url);
|
|
124
|
+
if (!parsed) {
|
|
125
|
+
console.warn(`[fonts] skipping unrecognized URL shape: ${url}`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const familyDir = resolve(ctx.outputDir, parsed.family);
|
|
129
|
+
mkdirSync(familyDir, { recursive: true });
|
|
130
|
+
const destPath = resolve(familyDir, parsed.file);
|
|
131
|
+
// Skip re-download if file already exists with same size — keeps
|
|
132
|
+
// re-runs quick. Use HEAD to compare; if HEAD fails fall through
|
|
133
|
+
// to a fresh GET.
|
|
134
|
+
let needFetch = true;
|
|
135
|
+
if (existsSync(destPath)) {
|
|
136
|
+
try {
|
|
137
|
+
const head = await ctx.page.request.fetch(url, { method: 'HEAD' });
|
|
138
|
+
const remoteLen = Number(head.headers()['content-length'] ?? -1);
|
|
139
|
+
if (remoteLen > 0) {
|
|
140
|
+
const localLen = readFileSync(destPath).byteLength;
|
|
141
|
+
if (remoteLen === localLen)
|
|
142
|
+
needFetch = false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
/* fall through to GET */
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (needFetch) {
|
|
150
|
+
const resp = await ctx.page.request.fetch(url, { method: 'GET' });
|
|
151
|
+
if (!resp.ok()) {
|
|
152
|
+
console.warn(`[fonts] ${resp.status()} ${url} — skipping`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const body = await resp.body();
|
|
156
|
+
writeFileSync(destPath, body);
|
|
157
|
+
downloaded++;
|
|
158
|
+
console.log(`[fonts] ${parsed.handle.padEnd(20)} ${body.byteLength.toString().padStart(7)}b ${url}`);
|
|
159
|
+
}
|
|
160
|
+
// Prefer woff2 over woff when a handle has both — Shopify ships
|
|
161
|
+
// both formats from /cdn for browser compatibility; our offline
|
|
162
|
+
// @font-face filter emits a single `src ... format("woff2")` so
|
|
163
|
+
// recording the woff URL would cause Chrome to fetch a file we
|
|
164
|
+
// mis-label as woff2.
|
|
165
|
+
const existing = manifest[parsed.handle];
|
|
166
|
+
const isWoff2 = parsed.file.endsWith('.woff2');
|
|
167
|
+
const existingIsWoff2 = existing?.file.endsWith('.woff2');
|
|
168
|
+
if (existing && existingIsWoff2 && !isWoff2)
|
|
169
|
+
continue;
|
|
170
|
+
manifest[parsed.handle] = {
|
|
171
|
+
family: parsed.family,
|
|
172
|
+
handle: parsed.handle,
|
|
173
|
+
file: parsed.file,
|
|
174
|
+
url,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// Merge into existing manifest (so probes run against different
|
|
178
|
+
// themes accumulate). Conflicting handles overwrite — the latest
|
|
179
|
+
// run wins.
|
|
180
|
+
const manifestPath = resolve(ctx.outputDir, 'manifest.json');
|
|
181
|
+
let existing = {};
|
|
182
|
+
if (existsSync(manifestPath)) {
|
|
183
|
+
try {
|
|
184
|
+
existing = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* corrupted — start fresh */
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const merged = { ...existing, ...manifest };
|
|
191
|
+
writeFileSync(manifestPath, JSON.stringify(merged, null, 2) + '\n');
|
|
192
|
+
console.log(`[fonts] downloaded ${downloaded} new file(s); manifest has ${Object.keys(merged).length} entries`);
|
|
193
|
+
console.log(`[fonts] manifest: ${manifestPath}`);
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Map a font URL (canonical fonts.shopifycdn.com OR per-shop
|
|
198
|
+
* `/cdn/fonts/...` proxy) to the canonical fonts.shopifycdn.com URL.
|
|
199
|
+
* Returns null for anything that doesn't look like a font URL.
|
|
200
|
+
*
|
|
201
|
+
* Examples:
|
|
202
|
+
* https://fonts.shopifycdn.com/assistant/assistant_n4.<hash>.woff2
|
|
203
|
+
* → unchanged
|
|
204
|
+
* https://theme-dawn-demo.myshopify.com/cdn/fonts/assistant/assistant_n4.<hash>.woff2
|
|
205
|
+
* → https://fonts.shopifycdn.com/assistant/assistant_n4.<hash>.woff2
|
|
206
|
+
*
|
|
207
|
+
* The per-shop proxy serves byte-identical files at byte-identical
|
|
208
|
+
* filenames (Shopify just rewrites the host) so the canonical form is
|
|
209
|
+
* always recoverable.
|
|
210
|
+
*/
|
|
211
|
+
function normalizeToShopifycdn(raw) {
|
|
212
|
+
try {
|
|
213
|
+
const u = new URL(raw);
|
|
214
|
+
if (u.hostname === 'fonts.shopifycdn.com')
|
|
215
|
+
return u.toString();
|
|
216
|
+
// Per-shop proxy path is `/cdn/fonts/<rest>`; strip the prefix
|
|
217
|
+
// and re-host on fonts.shopifycdn.com.
|
|
218
|
+
const m = u.pathname.match(/^\/cdn\/fonts\/(.+)$/);
|
|
219
|
+
if (m) {
|
|
220
|
+
return `https://fonts.shopifycdn.com/${m[1]}`;
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Parse a fonts.shopifycdn.com URL into:
|
|
230
|
+
* family — the URL's first path segment (e.g. `assistant`)
|
|
231
|
+
* file — the trailing filename
|
|
232
|
+
* handle — Shopify-style font handle derived from the filename,
|
|
233
|
+
* e.g. `assistant_n4.f55fa3ec4ee20.woff2` → `assistant_n4`
|
|
234
|
+
*
|
|
235
|
+
* Returns null if the URL doesn't match the expected
|
|
236
|
+
* `/<family>/<family>_<style+weight>.<hash>.woff2`
|
|
237
|
+
* shape — anything else gets logged + skipped rather than guessed.
|
|
238
|
+
*/
|
|
239
|
+
function parseFontUrl(url) {
|
|
240
|
+
const u = new URL(url);
|
|
241
|
+
const parts = u.pathname.split('/').filter(Boolean);
|
|
242
|
+
if (parts.length < 2)
|
|
243
|
+
return null;
|
|
244
|
+
const family = parts[0];
|
|
245
|
+
const file = basename(u.pathname);
|
|
246
|
+
// handle = the leading "<family>_<code>" before the first dot.
|
|
247
|
+
// e.g. `assistant_n4.f55fa3ec4ee20.woff2` → `assistant_n4`.
|
|
248
|
+
// `inter_v1_n4.woff2` → `inter_v1_n4` (handles dotless names too).
|
|
249
|
+
const handle = file.split('.')[0];
|
|
250
|
+
if (!handle)
|
|
251
|
+
return null;
|
|
252
|
+
return { family, handle, file };
|
|
253
|
+
}
|
|
254
|
+
export default probe;
|
|
255
|
+
//# sourceMappingURL=fonts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.js","sourceRoot":"","sources":["../../src/probes/fonts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror.d.ts","sourceRoot":"","sources":["../../src/probes/mirror.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AA4ExC,QAAA,MAAM,KAAK,EAAE,KA8KZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Site mirror probe — capture every static asset a real Shopify
|
|
3
|
+
* storefront loads (CSS, JS, images, fonts, SVG, …) and bundle them
|
|
4
|
+
* so the offline mock can serve byte-identical responses at
|
|
5
|
+
* byte-identical URLs.
|
|
6
|
+
*
|
|
7
|
+
* Why: the offline storefront uses real Liquid templates (Dawn), and
|
|
8
|
+
* Dawn's HTML references ~170 distinct asset URLs on a single page
|
|
9
|
+
* (theme CSS, theme JS, shopifycloud scripts proxied through the
|
|
10
|
+
* shop's CDN, fonts, product images, theme images). The fonts probe
|
|
11
|
+
* handles the fonts subset; this probe handles the rest, end-to-end:
|
|
12
|
+
*
|
|
13
|
+
* 1. Open the source storefront page(s) with a real browser.
|
|
14
|
+
* 2. Watch the network. Capture every GET request to a Shopify
|
|
15
|
+
* host that returns 200.
|
|
16
|
+
* 3. Download each response body.
|
|
17
|
+
* 4. Save under `packages/themes/themes/_shopify-mirror/<host>/<path>`.
|
|
18
|
+
* 5. Update `manifest.json`: URL → { file, contentType, size, etag }.
|
|
19
|
+
*
|
|
20
|
+
* The mock storefront's edge proxy routes Shopify hostnames into a
|
|
21
|
+
* single `/__shopify-mirror/*` handler that serves files from this
|
|
22
|
+
* directory with the captured content-type.
|
|
23
|
+
*
|
|
24
|
+
* Re-run idempotent: existing files (same size) are skipped; new
|
|
25
|
+
* files added, conflicting URLs overwritten with the latest version.
|
|
26
|
+
* Commit the mirror dir to git so consumers get it from the tarball.
|
|
27
|
+
*/
|
|
28
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync, rmSync } from 'node:fs';
|
|
29
|
+
import { resolve, dirname, basename } from 'node:path';
|
|
30
|
+
import { vendoredAssetFilenames } from '@essential-apps/shopify-test-themes';
|
|
31
|
+
/**
|
|
32
|
+
* Hosts whose asset traffic we mirror. Two flavours:
|
|
33
|
+
* - exact match (e.g. `cdn.shopify.com`, `fonts.shopifycdn.com`)
|
|
34
|
+
* - suffix match for per-shop CDNs (`*.myshopify.com/cdn/*`)
|
|
35
|
+
*
|
|
36
|
+
* Tracking endpoints (`monorail-edge.shopifysvc.com`,
|
|
37
|
+
* `otlp-http-production.shopifysvc.com`) intentionally NOT mirrored —
|
|
38
|
+
* they're POST-only telemetry that the offline mock already no-ops.
|
|
39
|
+
*/
|
|
40
|
+
function shouldMirror(url) {
|
|
41
|
+
let u;
|
|
42
|
+
try {
|
|
43
|
+
u = new URL(url);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (u.protocol !== 'https:' && u.protocol !== 'http:')
|
|
49
|
+
return false;
|
|
50
|
+
// Per-shop CDN proxy: any *.myshopify.com under /cdn/.
|
|
51
|
+
if (u.hostname.endsWith('.myshopify.com') && u.pathname.startsWith('/cdn/'))
|
|
52
|
+
return true;
|
|
53
|
+
// Shopify's CDN edge.
|
|
54
|
+
if (u.hostname === 'cdn.shopify.com')
|
|
55
|
+
return true;
|
|
56
|
+
// Fonts CDN.
|
|
57
|
+
if (u.hostname === 'fonts.shopifycdn.com')
|
|
58
|
+
return true;
|
|
59
|
+
// shopifycloud subdomains, if/when used directly.
|
|
60
|
+
if (u.hostname.endsWith('.shopifycdn.com'))
|
|
61
|
+
return true;
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Translate a URL to a path on disk under the mirror root:
|
|
66
|
+
* https://theme-dawn-demo.myshopify.com/cdn/shop/t/53/assets/global.js?v=12345
|
|
67
|
+
* → theme-dawn-demo.myshopify.com/cdn/shop/t/53/assets/global.js
|
|
68
|
+
*
|
|
69
|
+
* Query strings are STRIPPED for now — most Shopify asset URLs carry
|
|
70
|
+
* a `?v=<cachebuster>` that doesn't affect content. If we hit a case
|
|
71
|
+
* where the same path serves different bodies under different query
|
|
72
|
+
* params, we'll switch to including a hash of the query.
|
|
73
|
+
*
|
|
74
|
+
* Returns null for paths that would escape the mirror root.
|
|
75
|
+
*/
|
|
76
|
+
function pathForUrl(url) {
|
|
77
|
+
const u = new URL(url);
|
|
78
|
+
// Strip leading slash so resolve(mirror, p) puts it INSIDE mirror.
|
|
79
|
+
let p = u.pathname.replace(/^\/+/, '');
|
|
80
|
+
if (!p)
|
|
81
|
+
p = '_index';
|
|
82
|
+
// Defence-in-depth: reject any segment that's `..` etc.
|
|
83
|
+
if (p.split('/').some((seg) => seg === '..' || seg === ''))
|
|
84
|
+
return null;
|
|
85
|
+
return `${u.hostname}/${p}`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Pages to crawl. The base URL is whatever the operator passes in
|
|
89
|
+
* via `--url`; we also visit a couple of canonical sub-pages so the
|
|
90
|
+
* mirror covers product pages and collection grids, not just the
|
|
91
|
+
* homepage. Failures on sub-pages are non-fatal (the site might
|
|
92
|
+
* have password gates, locale redirects, etc.).
|
|
93
|
+
*/
|
|
94
|
+
const CRAWL_PATHS = [
|
|
95
|
+
'/',
|
|
96
|
+
'/products.json?limit=1',
|
|
97
|
+
'/collections/all',
|
|
98
|
+
];
|
|
99
|
+
const probe = {
|
|
100
|
+
name: 'mirror',
|
|
101
|
+
description: 'Mirror every static asset (CSS, JS, images, fonts, …) a real Shopify storefront loads.',
|
|
102
|
+
outputDir: 'packages/themes/themes/_shopify-mirror',
|
|
103
|
+
async run(ctx) {
|
|
104
|
+
const passwordFromEnv = process.env['STOREFRONT_PASSWORD'] ?? '';
|
|
105
|
+
const baseUrl = `https://${ctx.store.shop}`;
|
|
106
|
+
const mirrorRoot = ctx.outputDir;
|
|
107
|
+
// Read existing manifest (so reruns merge rather than truncate).
|
|
108
|
+
const manifestPath = resolve(mirrorRoot, 'manifest.json');
|
|
109
|
+
const manifest = existsSync(manifestPath)
|
|
110
|
+
? (() => {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
})()
|
|
118
|
+
: {};
|
|
119
|
+
// Capture every Shopify asset URL the pages reference. We listen on
|
|
120
|
+
// BOTH `request` (catches preloads + speculative loads) and
|
|
121
|
+
// `response` (so we can record content-type from the response
|
|
122
|
+
// headers without an extra HEAD/GET).
|
|
123
|
+
const seen = new Set();
|
|
124
|
+
const captureUrl = (url) => {
|
|
125
|
+
if (shouldMirror(url))
|
|
126
|
+
seen.add(url);
|
|
127
|
+
};
|
|
128
|
+
ctx.page.on('request', (req) => captureUrl(req.url()));
|
|
129
|
+
ctx.page.on('response', (resp) => captureUrl(resp.url()));
|
|
130
|
+
let visited = 0;
|
|
131
|
+
let passwordHandled = false;
|
|
132
|
+
for (const path of CRAWL_PATHS) {
|
|
133
|
+
const url = `${baseUrl}${path}`;
|
|
134
|
+
console.log(`[mirror] crawl ${url}`);
|
|
135
|
+
try {
|
|
136
|
+
await ctx.page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
console.warn(`[mirror] nav failed: ${err.message}`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
// Password gate (only check once — subsequent navigations
|
|
143
|
+
// already carry the cookie).
|
|
144
|
+
if (!passwordHandled) {
|
|
145
|
+
const pwd = ctx.page.locator('input[name="password"], input#password');
|
|
146
|
+
if (await pwd.count().catch(() => 0)) {
|
|
147
|
+
if (!passwordFromEnv) {
|
|
148
|
+
throw new Error(`Store ${ctx.store.shop} has a password gate but STOREFRONT_PASSWORD is unset.`);
|
|
149
|
+
}
|
|
150
|
+
console.log('[mirror] entering storefront password');
|
|
151
|
+
await pwd.first().fill(passwordFromEnv);
|
|
152
|
+
await ctx.page.locator('button[type="submit"], input[type="submit"]').first().click();
|
|
153
|
+
await ctx.page.waitForLoadState('domcontentloaded');
|
|
154
|
+
passwordHandled = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Let lazy-loaded assets (images below the fold, scripts on
|
|
158
|
+
// requestIdleCallback, etc.) fire.
|
|
159
|
+
await ctx.page
|
|
160
|
+
.waitForLoadState('networkidle', { timeout: 20_000 })
|
|
161
|
+
.catch(() => { });
|
|
162
|
+
visited++;
|
|
163
|
+
}
|
|
164
|
+
if (visited === 0) {
|
|
165
|
+
throw new Error(`Failed to load any pages on ${baseUrl}`);
|
|
166
|
+
}
|
|
167
|
+
// Also scrape the rendered DOM for asset URLs the network may
|
|
168
|
+
// not have surfaced (e.g. `<link rel="preload">` references
|
|
169
|
+
// sometimes don't fetch until a glyph/element is used).
|
|
170
|
+
const dom = await ctx.page.content();
|
|
171
|
+
for (const m of dom.matchAll(/https?:\/\/[^"')\s<>]+/g)) {
|
|
172
|
+
captureUrl(m[0]);
|
|
173
|
+
}
|
|
174
|
+
// Protocol-relative.
|
|
175
|
+
for (const m of dom.matchAll(/(["'(])\/\/([^"')\s<>]+)/g)) {
|
|
176
|
+
captureUrl('https://' + m[2]);
|
|
177
|
+
}
|
|
178
|
+
console.log(`[mirror] ${seen.size} candidate URL(s) discovered`);
|
|
179
|
+
// Don't mirror files the vendored themes already ship. Dawn's
|
|
180
|
+
// `/assets/` directory contains 185 CSS/JS/SVG files; real
|
|
181
|
+
// Shopify serves the SAME logical files (possibly compiled) at
|
|
182
|
+
// `/cdn/shop/t/<theme-id>/assets/<file>`. Mirroring them
|
|
183
|
+
// duplicates bytes and creates stale-vs-upgrade drift. Match by
|
|
184
|
+
// basename — that's the only stable identifier across the
|
|
185
|
+
// un-compiled (Dawn source) and compiled (CDN) versions.
|
|
186
|
+
const vendored = vendoredAssetFilenames();
|
|
187
|
+
// Download each. Use the page's request context so cookies/CF
|
|
188
|
+
// tokens flow through; some asset URLs 403 without them.
|
|
189
|
+
let downloaded = 0;
|
|
190
|
+
let skipped = 0;
|
|
191
|
+
let skippedVendored = 0;
|
|
192
|
+
let failed = 0;
|
|
193
|
+
for (const url of seen) {
|
|
194
|
+
const rel = pathForUrl(url);
|
|
195
|
+
if (!rel) {
|
|
196
|
+
console.warn(`[mirror] skip unsafe path: ${url}`);
|
|
197
|
+
failed++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const fileName = basename(rel);
|
|
201
|
+
if (vendored.has(fileName)) {
|
|
202
|
+
skippedVendored++;
|
|
203
|
+
// Make sure we also DON'T retain a stale copy from a previous
|
|
204
|
+
// run that pre-dates the skip-vendored rule. (Cleanup is
|
|
205
|
+
// additive — we remove ONLY the file we'd otherwise overwrite.)
|
|
206
|
+
const abs = resolve(mirrorRoot, rel);
|
|
207
|
+
try {
|
|
208
|
+
if (existsSync(abs))
|
|
209
|
+
rmSync(abs);
|
|
210
|
+
}
|
|
211
|
+
catch { /* ignore */ }
|
|
212
|
+
delete manifest[url];
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const abs = resolve(mirrorRoot, rel);
|
|
216
|
+
// Skip if a file with the same size is already on disk AND
|
|
217
|
+
// already in the manifest (immutable Shopify URLs include a
|
|
218
|
+
// content hash so any change means a new URL anyway).
|
|
219
|
+
if (existsSync(abs) && manifest[url] && statSync(abs).size === manifest[url].size) {
|
|
220
|
+
skipped++;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
let resp;
|
|
224
|
+
try {
|
|
225
|
+
resp = await ctx.page.request.fetch(url, { method: 'GET' });
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
console.warn(`[mirror] fetch error ${url} ${err.message}`);
|
|
229
|
+
failed++;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (!resp.ok()) {
|
|
233
|
+
console.warn(`[mirror] ${resp.status()} ${url}`);
|
|
234
|
+
failed++;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const body = await resp.body();
|
|
238
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
239
|
+
writeFileSync(abs, body);
|
|
240
|
+
const contentType = (resp.headers()['content-type'] ?? 'application/octet-stream')
|
|
241
|
+
.split(';')[0]
|
|
242
|
+
.trim();
|
|
243
|
+
manifest[url] = {
|
|
244
|
+
url,
|
|
245
|
+
file: rel,
|
|
246
|
+
contentType,
|
|
247
|
+
size: body.byteLength,
|
|
248
|
+
};
|
|
249
|
+
downloaded++;
|
|
250
|
+
if (downloaded <= 10 || downloaded % 25 === 0) {
|
|
251
|
+
console.log(`[mirror] ${downloaded.toString().padStart(3)} ${body.byteLength.toString().padStart(8)}b ${contentType.padEnd(28)} ${url}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
255
|
+
console.log(`[mirror] done: ${downloaded} downloaded, ${skipped} cached, ${skippedVendored} skipped (vendored in theme repo), ${failed} failed, ${Object.keys(manifest).length} total in manifest`);
|
|
256
|
+
console.log(`[mirror] manifest: ${manifestPath}`);
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
export default probe;
|
|
260
|
+
//# sourceMappingURL=mirror.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror.js","sourceRoot":"","sources":["../../src/probes/mirror.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC/F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAc7E;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACpE,uDAAuD;IACvD,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACzF,sBAAsB;IACtB,IAAI,CAAC,CAAC,QAAQ,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAClD,aAAa;IACb,IAAI,CAAC,CAAC,QAAQ,KAAK,sBAAsB;QAAE,OAAO,IAAI,CAAC;IACvD,kDAAkD;IAClD,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,mEAAmE;IACnE,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,CAAC,GAAG,QAAQ,CAAC;IACrB,wDAAwD;IACxD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,OAAO,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,GAAG;IAClB,GAAG;IACH,wBAAwB;IACxB,kBAAkB;CACnB,CAAC;AAEF,MAAM,KAAK,GAAU;IACnB,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,wFAAwF;IAC1F,SAAS,EAAE,wCAAwC;IAEnD,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC;QACjE,MAAM,OAAO,GAAG,WAAW,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,SAAS,CAAC;QAEjC,iEAAiE;QACjE,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAgC,UAAU,CAAC,YAAY,CAAC;YACpE,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,IAAI,CAAC;oBACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAgC,CAAC;gBACvF,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,EAAE,CAAC;QAEP,oEAAoE;QACpE,4DAA4D;QAC5D,8DAA8D;QAC9D,sCAAsC;QACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE;YACjC,IAAI,YAAY,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACvD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAE1D,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,IAAI,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,0BAA2B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;gBACjE,SAAS;YACX,CAAC;YAED,0DAA0D;YAC1D,6BAA6B;YAC7B,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;gBACvE,IAAI,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrC,IAAI,CAAC,eAAe,EAAE,CAAC;wBACrB,MAAM,IAAI,KAAK,CACb,SAAS,GAAG,CAAC,KAAK,CAAC,IAAI,wDAAwD,CAChF,CAAC;oBACJ,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;oBACvD,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;oBACxC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;oBACtF,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;oBACpD,eAAe,GAAG,IAAI,CAAC;gBACzB,CAAC;YACH,CAAC;YAED,4DAA4D;YAC5D,mCAAmC;YACnC,MAAM,GAAG,CAAC,IAAI;iBACX,gBAAgB,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;iBACpD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,8DAA8D;QAC9D,4DAA4D;QAC5D,wDAAwD;QACxD,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC;YACxD,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;QACD,qBAAqB;QACrB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,CAAC;YAC1D,UAAU,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,IAAI,8BAA8B,CAAC,CAAC;QAEjE,8DAA8D;QAC9D,2DAA2D;QAC3D,+DAA+D;QAC/D,yDAAyD;QACzD,gEAAgE;QAChE,0DAA0D;QAC1D,yDAAyD;QACzD,MAAM,QAAQ,GAAG,sBAAsB,EAAE,CAAC;QAE1C,8DAA8D;QAC9D,yDAAyD;QACzD,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,CAAC,IAAI,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;gBACpD,MAAM,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3B,eAAe,EAAE,CAAC;gBAClB,8DAA8D;gBAC9D,yDAAyD;gBACzD,gEAAgE;gBAChE,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;gBACrC,IAAI,CAAC;oBAAC,IAAI,UAAU,CAAC,GAAG,CAAC;wBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;gBAChE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAErC,2DAA2D;YAC3D,4DAA4D;YAC5D,sDAAsD;YACtD,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,GAAG,CAAE,CAAC,IAAI,EAAE,CAAC;gBACnF,OAAO,EAAE,CAAC;gBACV,SAAS;YACX,CAAC;YAED,IAAI,IAAI,CAAC;YACT,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1E,MAAM,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;gBACpD,MAAM,EAAE,CAAC;gBACT,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACzB,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,0BAA0B,CAAC;iBAC/E,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE;iBACd,IAAI,EAAE,CAAC;YACV,QAAQ,CAAC,GAAG,CAAC,GAAG;gBACd,GAAG;gBACH,IAAI,EAAE,GAAG;gBACT,WAAW;gBACX,IAAI,EAAE,IAAI,CAAC,UAAU;aACtB,CAAC;YACF,UAAU,EAAE,CAAC;YACb,IAAI,UAAU,IAAI,EAAE,IAAI,UAAU,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CACT,cAAc,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CACjI,CAAC;YACJ,CAAC;QACH,CAAC;QAED,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAEtE,OAAO,CAAC,GAAG,CACT,kBAAkB,UAAU,gBAAgB,OAAO,YAAY,eAAe,sCAAsC,MAAM,YAAY,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,oBAAoB,CACvL,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,sBAAsB,YAAY,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runProbe.d.ts","sourceRoot":"","sources":["../../src/probes/runProbe.ts"],"names":[],"mappings":""}
|