@tileflow/capture 0.1.0-alpha.21 → 0.1.0-alpha.22

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/README.md CHANGED
@@ -16,12 +16,12 @@ const result = await captureTileflowScenes({
16
16
  const [{png, receipt, sha256, networkDependent}] = result.captures;
17
17
  ```
18
18
 
19
- Standalone scenes compile through `@tileflow/dev`, inject the installed MapLibre JS and CSS into a
20
- pinned Playwright Chromium headless shell, fulfill generated local icon assets in memory, and wait
21
- for `load`, `idle`, and two animation frames. They never open a visible window or an HTTP listener.
22
- One call with multiple scenes uses one Browser and a fresh isolated context per scene. Capture
23
- installs the exact pinned shell automatically when `allowBrowserInstall` is true; the CLI enables
24
- that normal happy path by default.
19
+ Standalone scenes compile through `@tileflow/dev`, fulfill the installed MapLibre main module,
20
+ shared module, worker module, and CSS closure in a pinned Playwright Chromium headless shell,
21
+ fulfill generated local icon assets in memory, and wait for `load`, `idle`, and two animation
22
+ frames. They never open a visible window or an HTTP listener. One call with multiple scenes uses
23
+ one Browser and a fresh isolated context per scene. Capture installs the exact pinned shell
24
+ automatically when `allowBrowserInstall` is true; the CLI enables that normal happy path by default.
25
25
 
26
26
  For a warm integration, retain and close a session:
27
27
 
@@ -18,7 +18,7 @@ the platform-specific headless shell into its versioned per-user browser cache;
18
18
  distribution carries Chromium's license and credits. Chromium source and license information are
19
19
  available at https://www.chromium.org/chromium-projects/.
20
20
 
21
- ## MapLibre GL JS 5.24.0
21
+ ## MapLibre GL JS 6.9.0
22
22
 
23
23
  Copyright (c) 2023 MapLibre contributors. Licensed under BSD-3-Clause. The installed `maplibre-gl`
24
24
  package includes `LICENSE.txt`, including notices for code derived from Mapbox GL JS and other
package/dist/index.js CHANGED
@@ -320,8 +320,12 @@ import { getTileflowStyleFontFaces } from "@tileflow/core/runtime";
320
320
  import { assertValidTileflowStyle, TileflowStyleValidationError } from "@tileflow/dev/validation";
321
321
  var tileflowSyntheticAssetOrigin = "https://tileflow.local.invalid";
322
322
  var require3 = createRequire2(import.meta.url);
323
- var maplibreJsPath = require3.resolve("maplibre-gl/dist/maplibre-gl.js");
324
- var maplibreCssPath = require3.resolve("maplibre-gl/dist/maplibre-gl.css");
323
+ var mapLibreRuntimePaths = Object.freeze({
324
+ css: require3.resolve("maplibre-gl/dist/maplibre-gl.css"),
325
+ main: require3.resolve("maplibre-gl/dist/maplibre-gl.mjs"),
326
+ shared: require3.resolve("maplibre-gl/dist/maplibre-gl-shared.mjs"),
327
+ worker: require3.resolve("maplibre-gl/dist/maplibre-gl-worker.mjs")
328
+ });
325
329
  var tileflowCorePackagePath = require3.resolve("@tileflow/core/package.json");
326
330
  var tileflowBrowserModule = `${readFileSync2(
327
331
  join2(dirname2(tileflowCorePackagePath), "dist", "browser.js"),
@@ -351,6 +355,9 @@ async function captureStandaloneTileflowScene(input) {
351
355
  throw error;
352
356
  }
353
357
  const timeoutMs = input.timeoutMs ?? 3e4;
358
+ const mapLibreRuntimeUrls = createMapLibreRuntimeUrls(
359
+ resolveMapLibreRuntimeDocumentOrigin(input.style)
360
+ );
354
361
  let termination;
355
362
  let context;
356
363
  let phase = "browser-start";
@@ -407,6 +414,13 @@ async function captureStandaloneTileflowScene(input) {
407
414
  };
408
415
  await context.route("**/*", async (route) => {
409
416
  const url = new URL(route.request().url());
417
+ if (url.origin === mapLibreRuntimeUrls.origin) {
418
+ const runtime = getMapLibreRuntimeResponse(url.pathname, input.scene.viewport);
419
+ if (runtime) {
420
+ await route.fulfill(runtime);
421
+ return;
422
+ }
423
+ }
410
424
  if (url.origin === tileflowSyntheticAssetOrigin) {
411
425
  const fileName = decodeURIComponent(url.pathname.slice(1));
412
426
  const localTileset = url.search === "" ? localTilesets.get(fileName) : void 0;
@@ -415,7 +429,10 @@ async function captureStandaloneTileflowScene(input) {
415
429
  route.request().headers()["range"],
416
430
  localTileset
417
431
  );
418
- await route.fulfill(response);
432
+ await route.fulfill({
433
+ ...response,
434
+ headers: { "Access-Control-Allow-Origin": "*", ...response.headers }
435
+ });
419
436
  return;
420
437
  }
421
438
  const asset = url.search === "" ? assets.get(fileName) : void 0;
@@ -428,6 +445,7 @@ async function captureStandaloneTileflowScene(input) {
428
445
  await route.fulfill({
429
446
  body: typeof source === "string" ? source : Buffer.from(source),
430
447
  contentType: asset.contentType,
448
+ headers: { "Access-Control-Allow-Origin": "*" },
431
449
  status: 200
432
450
  });
433
451
  return;
@@ -457,9 +475,17 @@ async function captureStandaloneTileflowScene(input) {
457
475
  });
458
476
  page.on("requestfailed", (request) => recordResourceFailure(request.url()));
459
477
  page.setDefaultTimeout(timeoutMs);
460
- await page.setContent(renderHtml(input.scene.viewport), { waitUntil: "domcontentloaded" });
461
- await page.addStyleTag({ path: maplibreCssPath });
462
- await page.addScriptTag({ path: maplibreJsPath });
478
+ await page.goto(mapLibreRuntimeUrls.document, { waitUntil: "domcontentloaded" });
479
+ await page.addStyleTag({ url: mapLibreRuntimeUrls.css });
480
+ await page.addScriptTag({
481
+ content: `import * as maplibregl from ${JSON.stringify(mapLibreRuntimeUrls.main)};
482
+ maplibregl.setWorkerUrl(${JSON.stringify(mapLibreRuntimeUrls.worker)});
483
+ globalThis.maplibregl = maplibregl;`,
484
+ type: "module"
485
+ });
486
+ await page.waitForFunction(
487
+ () => Boolean(globalThis.maplibregl)
488
+ );
463
489
  await page.addScriptTag({ content: tileflowBrowserModule, type: "module" });
464
490
  await page.addScriptTag({ content: renderMapInPageScript });
465
491
  phase = "map-load";
@@ -559,6 +585,78 @@ async function captureStandaloneTileflowScene(input) {
559
585
  await context?.close().catch(() => void 0);
560
586
  }
561
587
  }
588
+ function createMapLibreRuntimeUrls(origin) {
589
+ return Object.freeze({
590
+ css: `${origin}/__runtime/maplibre-gl.css`,
591
+ document: `${origin}/__runtime/document.html`,
592
+ main: `${origin}/__runtime/maplibre-gl.mjs`,
593
+ origin,
594
+ shared: `${origin}/__runtime/maplibre-gl-shared.mjs`,
595
+ worker: `${origin}/__runtime/maplibre-gl-worker.mjs`
596
+ });
597
+ }
598
+ function resolveMapLibreRuntimeDocumentOrigin(style) {
599
+ const origins = /* @__PURE__ */ new Set();
600
+ const loopbackOrigins = /* @__PURE__ */ new Set();
601
+ const addOrigin = (value) => {
602
+ if (typeof value !== "string") return;
603
+ try {
604
+ const url = new URL(value);
605
+ if ((url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "") {
606
+ origins.add(url.origin);
607
+ if (isLoopbackUrl(url)) loopbackOrigins.add(url.origin);
608
+ }
609
+ } catch {
610
+ }
611
+ };
612
+ addOrigin(style.glyphs);
613
+ if (Array.isArray(style.sprite)) {
614
+ for (const sprite of style.sprite) {
615
+ if (sprite && typeof sprite === "object") {
616
+ addOrigin(sprite.url);
617
+ }
618
+ }
619
+ } else {
620
+ addOrigin(style.sprite);
621
+ }
622
+ const fontFaces = style.metadata?.["tileflow:fontFaces"];
623
+ if (Array.isArray(fontFaces)) {
624
+ for (const fontFace of fontFaces) {
625
+ if (fontFace && typeof fontFace === "object") {
626
+ addOrigin(fontFace.source);
627
+ }
628
+ }
629
+ }
630
+ for (const source of Object.values(style.sources)) {
631
+ const candidate = source;
632
+ addOrigin(candidate.data);
633
+ addOrigin(candidate.url);
634
+ if (Array.isArray(candidate.tiles)) {
635
+ for (const tile of candidate.tiles) addOrigin(tile);
636
+ }
637
+ if (Array.isArray(candidate.urls)) {
638
+ for (const url of candidate.urls) addOrigin(url);
639
+ }
640
+ }
641
+ const preferredOrigins = loopbackOrigins.size > 0 ? loopbackOrigins : origins;
642
+ return [...preferredOrigins].sort(compareCodeUnits)[0] ?? tileflowSyntheticAssetOrigin;
643
+ }
644
+ function getMapLibreRuntimeResponse(pathname, viewport) {
645
+ if (pathname === "/__runtime/document.html") {
646
+ return {
647
+ body: renderHtml(viewport),
648
+ contentType: "text/html; charset=utf-8",
649
+ status: 200
650
+ };
651
+ }
652
+ const asset = pathname === "/__runtime/maplibre-gl.mjs" ? mapLibreRuntimePaths.main : pathname === "/__runtime/maplibre-gl-shared.mjs" ? mapLibreRuntimePaths.shared : pathname === "/__runtime/maplibre-gl-worker.mjs" ? mapLibreRuntimePaths.worker : pathname === "/__runtime/maplibre-gl.css" ? mapLibreRuntimePaths.css : void 0;
653
+ if (!asset) return void 0;
654
+ return {
655
+ body: readFileSync2(asset, "utf8"),
656
+ contentType: pathname === "/__runtime/maplibre-gl.css" ? "text/css; charset=utf-8" : "text/javascript; charset=utf-8",
657
+ status: 200
658
+ };
659
+ }
562
660
  async function localTilesetCaptureResponse(rangeHeader, file) {
563
661
  const match = rangeHeader?.match(/^bytes=(\d+)-(\d*)$/u);
564
662
  if (!match) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/capture",
3
- "version": "0.1.0-alpha.21",
3
+ "version": "0.1.0-alpha.22",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Deterministic local visual capture and comparison for Tileflow maps.",
6
6
  "engines": {
@@ -48,8 +48,8 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@tileflow/core": ">=0.1.0-alpha.24 <0.1.0-beta.0",
51
- "@tileflow/dev": ">=0.1.0-alpha.22 <0.1.0-beta.0",
52
- "maplibre-gl": "5.24.0",
51
+ "@tileflow/dev": ">=0.1.0-alpha.23 <0.1.0-beta.0",
52
+ "maplibre-gl": "6.9.0",
53
53
  "pixelmatch": "7.2.0",
54
54
  "playwright": "1.62.1",
55
55
  "pngjs": "7.0.0"
@@ -59,6 +59,7 @@
59
59
  "@types/node": "^25.9.2",
60
60
  "@types/pngjs": "6.0.5",
61
61
  "@vitejs/plugin-vue": "^6.0.8",
62
+ "maplibre-gl-min": "npm:maplibre-gl@6.4.1",
62
63
  "next": "16.3.3",
63
64
  "react": "^19.2.7",
64
65
  "react-dom": "^19.2.7",
@@ -66,13 +67,13 @@
66
67
  "vite": "^8.0.16",
67
68
  "vue": "^3.5.39",
68
69
  "webpack": "5.108.3",
69
- "@tileflow/maps": "0.1.0-alpha.2",
70
- "@tileflow/next": "0.1.0-alpha.20",
71
- "@tileflow/svelte": "0.1.0-alpha.22",
72
- "@tileflow/vite": "0.1.0-alpha.20",
73
- "@tileflow/vue": "0.1.0-alpha.22",
74
- "@tileflow/react": "0.1.0-alpha.23",
75
- "@tileflow/webpack": "0.1.0-alpha.20"
70
+ "@tileflow/maps": "0.1.0-alpha.3",
71
+ "@tileflow/react": "0.1.0-alpha.24",
72
+ "@tileflow/vite": "0.1.0-alpha.21",
73
+ "@tileflow/next": "0.1.0-alpha.21",
74
+ "@tileflow/svelte": "0.1.0-alpha.23",
75
+ "@tileflow/webpack": "0.1.0-alpha.21",
76
+ "@tileflow/vue": "0.1.0-alpha.23"
76
77
  },
77
78
  "scripts": {
78
79
  "build": "tsup src/index.ts src/receipt.ts --format esm --dts --clean --platform node",