@tileflow/capture 0.1.0-alpha.25 → 0.1.0-alpha.27

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
@@ -198,7 +198,10 @@ query strings, response bodies, raw browser stacks, or DOM contents.
198
198
  New receipts use schema version 4. Version-2 and version-3 receipts remain readable as historical
199
199
  evidence, not as newly verified version-4 captures. Import `@tileflow/capture/receipt` for receipt-only
200
200
  tooling without loading the capture runtime. World selectors resolve once per capture session to
201
- an immutable release. Remote-dependent rendering is not a guarantee of globally identical pixels
201
+ an immutable release. Capture retains the complete resolved TileJSON, including its zoom range,
202
+ bounds, attribution and vector-layer metadata. Above the data's maximum zoom, MapLibre enlarges
203
+ available tiles while preserving the scene camera. Retries reuse the same frozen metadata.
204
+ Remote-dependent rendering is not a guarantee of globally identical pixels
202
205
  across platforms or future runs.
203
206
 
204
207
  Read the [capture contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/local-visual-capture.md)
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Browser } from 'playwright';
2
2
  import { T as TileflowCaptureRendererIdentity, a as TileflowCaptureReceiptV4, b as TileflowCaptureDataInput, c as TileflowCaptureWorldIdentityV3, d as TileflowCaptureReceipt } from './receipt-Q7wQ68tG.js';
3
3
  export { C as CreateTileflowCaptureReceiptInput, e as TileflowCaptureDataBindingsV2, f as TileflowCaptureDataCapabilitiesV2, g as TileflowCaptureDataIdentityV2, h as TileflowCaptureDataIdentityV3, i as TileflowCaptureDataSemanticsV2, j as TileflowCaptureDataSourceV2, k as TileflowCaptureReceiptV2, l as TileflowCaptureReceiptV3, m as TileflowCaptureVectorIdentityV3, n as TileflowCaptureVerificationV2, o as createTileflowCaptureReceipt, p as createTileflowCaptureRendererIdentity, q as parseTileflowCaptureReceipt, s as serializeTileflowCaptureReceipt, t as tileflowCaptureReceiptLimits, r as tileflowCaptureReceiptSchemaVersion, u as tileflowCaptureRuntime, v as validateTileflowCaptureReceipt } from './receipt-Q7wQ68tG.js';
4
4
  import { TileflowCaptureScene, MapLibreStyle, NormalizedTileflowCaptureScene } from '@tileflow/core';
5
- import { TileflowIconResolutionOptions, TileflowBuildArtifacts } from '@tileflow/dev/artifacts';
5
+ import { TileflowIconResolutionOptions, TileflowBuildArtifacts, TileflowBuildAsset } from '@tileflow/dev/artifacts';
6
6
 
7
7
  type TileflowBrowserInstallProgress = 'installing' | 'installed';
8
8
  type TileflowBrowserLaunchOptions = {
@@ -106,6 +106,11 @@ declare class TileflowCaptureError extends Error {
106
106
  }
107
107
  declare function captureErrorMessage(error: unknown, fallback: string): string;
108
108
 
109
+ declare const tileflowSyntheticAssetOrigin = "https://tileflow.local.invalid";
110
+ type TileflowCaptureAsset = TileflowBuildAsset & {
111
+ url?: string;
112
+ };
113
+
109
114
  declare const tileflowWorldCurrentTileJsonUrl: "https://api.tileflow.dev/tiles/world/tiles.json";
110
115
  type FetchTileJson = (input: string, init: {
111
116
  cache: 'no-store';
@@ -115,9 +120,11 @@ type FetchTileJson = (input: string, init: {
115
120
  type TileflowCaptureResolvedWorldV1 = Readonly<{
116
121
  identity: Omit<TileflowCaptureWorldIdentityV3, 'kind' | 'schema' | 'schemaVersion' | 'semantics' | 'sourceId'>;
117
122
  tileJsonUrl: string;
123
+ tileJson: string;
118
124
  tiles: readonly [string];
119
125
  }>;
120
126
  type PreparedTileflowCaptureStyle = Readonly<{
127
+ assets?: TileflowCaptureAsset[];
121
128
  data: TileflowCaptureDataInput;
122
129
  style: MapLibreStyle;
123
130
  }>;
@@ -135,8 +142,6 @@ declare function resolveTileflowCaptureWorldTileJson(tileJsonUrl: string, option
135
142
  signal?: AbortSignal;
136
143
  }): Promise<TileflowCaptureResolvedWorldV1>;
137
144
 
138
- declare const tileflowSyntheticAssetOrigin = "https://tileflow.local.invalid";
139
-
140
145
  declare function resolveTileflowApplicationUrl(input: {
141
146
  appOrigin?: string;
142
147
  appUrl?: string;
package/dist/index.js CHANGED
@@ -318,7 +318,11 @@ import { createRequire as createRequire2 } from "module";
318
318
  import { dirname as dirname2, join as join2 } from "path";
319
319
  import { getTileflowStyleFontFaces } from "@tileflow/core/runtime";
320
320
  import { assertValidTileflowStyle, TileflowStyleValidationError } from "@tileflow/dev/validation";
321
+
322
+ // src/assets.ts
321
323
  var tileflowSyntheticAssetOrigin = "https://tileflow.local.invalid";
324
+
325
+ // src/standalone.ts
322
326
  var require3 = createRequire2(import.meta.url);
323
327
  var mapLibreRuntimePaths = Object.freeze({
324
328
  css: require3.resolve("maplibre-gl/dist/maplibre-gl.css"),
@@ -332,7 +336,8 @@ var tileflowBrowserModule = `${readFileSync2(
332
336
  "utf8"
333
337
  )}
334
338
  globalThis.__tileflowRegisterContourProtocol = registerTileflowContourProtocol;
335
- globalThis.__tileflowRegisterPmtilesProtocol = registerTileflowPmtilesProtocol;`;
339
+ globalThis.__tileflowRegisterPmtilesProtocol = registerTileflowPmtilesProtocol;
340
+ globalThis.__tileflowAttachAtmosphere = attachTileflowAtmosphere;`;
336
341
  async function captureStandaloneTileflowScene(input) {
337
342
  if (input.scene.target.kind !== "map") {
338
343
  throw new TileflowCaptureError(
@@ -396,6 +401,9 @@ async function captureStandaloneTileflowScene(input) {
396
401
  }, timeoutMs);
397
402
  timeout.unref?.();
398
403
  const assets = new Map(input.assets.map((asset) => [asset.fileName, asset]));
404
+ const frozenResources = new Map(
405
+ input.assets.filter((asset) => asset.url !== void 0).map((asset) => [asset.url, asset])
406
+ );
399
407
  const localTilesets = new Map(
400
408
  (input.localTilesets ?? []).map((tileset) => [tileset.fileName, tileset])
401
409
  );
@@ -414,6 +422,16 @@ async function captureStandaloneTileflowScene(input) {
414
422
  };
415
423
  await context.route("**/*", async (route) => {
416
424
  const url = new URL(route.request().url());
425
+ const frozenResource = frozenResources.get(url.toString());
426
+ if (frozenResource) {
427
+ await route.fulfill({
428
+ body: typeof frozenResource.source === "string" ? frozenResource.source : Buffer.from(frozenResource.source),
429
+ contentType: frozenResource.contentType,
430
+ headers: { "Access-Control-Allow-Origin": "*" },
431
+ status: 200
432
+ });
433
+ return;
434
+ }
417
435
  if (url.origin === mapLibreRuntimeUrls.origin) {
418
436
  const runtime = getMapLibreRuntimeResponse(url.pathname, input.scene.viewport);
419
437
  if (runtime) {
@@ -887,8 +905,10 @@ window.__tileflowCaptureLoad = async function(input) {
887
905
  await loadTileflowFontFaces(input.fontFaces || []);
888
906
  window.__tileflowRegisterContourProtocol?.({addProtocol: window.maplibregl.addProtocol});
889
907
  window.__tileflowRegisterPmtilesProtocol?.({addProtocol: window.maplibregl.addProtocol});
908
+ const data = input.style.metadata?.["tileflow:data"];
909
+ const worldSourceId = data?.kind === "tileflow-world" ? data.sourceId : undefined;
890
910
  window.__tileflowCaptureLoopbackSourceIds = Object.entries(input.style.sources || {})
891
- .filter(([, source]) => isLoopbackSourceUrl(source?.url))
911
+ .filter(([sourceId, source]) => sourceId !== worldSourceId && isLoopbackSourceUrl(source?.url))
892
912
  .map(([sourceId]) => sourceId);
893
913
  const map = new window.maplibregl.Map({
894
914
  attributionControl: false,
@@ -898,6 +918,7 @@ window.__tileflowCaptureLoad = async function(input) {
898
918
  style: input.style
899
919
  });
900
920
  window.__tileflowMap = map;
921
+ window.__tileflowAttachAtmosphere(map);
901
922
  return await waitForMapEvent(map, "load", input.mapEventTimeoutMs);
902
923
  } catch (error) {
903
924
  return {status: "failed", reason: "error", message: String(error?.message || error || "")};
@@ -1456,6 +1477,7 @@ function compareCodeUnits2(left, right) {
1456
1477
  }
1457
1478
 
1458
1479
  // src/world.ts
1480
+ import { createHash } from "crypto";
1459
1481
  import {
1460
1482
  isTileflowWorldReleaseId,
1461
1483
  tileflowWorldTileJsonUrl
@@ -1487,13 +1509,21 @@ var TileflowCaptureWorldSession = class {
1487
1509
  sourceId: requireLiteral(metadata.sourceId, "tileflow", "sourceId")
1488
1510
  };
1489
1511
  const { tiles: _mutableTiles, url: _mutableUrl, ...sourceWithoutSelector } = source;
1512
+ const tileJsonSha256 = createHash("sha256").update(resolution.tileJson).digest("hex");
1513
+ const fileName = `capture/world/${tileJsonSha256}.json`;
1514
+ const exactSelector = new URL(resolution.tileJsonUrl);
1515
+ exactSelector.searchParams.set("worldReleaseId", resolution.identity.releaseId);
1516
+ exactSelector.searchParams.set("worldDescriptorSha256", resolution.identity.descriptorSha256);
1517
+ const url = exactSelector.toString();
1490
1518
  return {
1519
+ assets: [{ contentType: "application/json", fileName, source: resolution.tileJson, url }],
1491
1520
  data,
1492
1521
  style: {
1493
1522
  ...style,
1523
+ metadata: { ...style.metadata, "tileflow:captureWorldTileJsonSha256": tileJsonSha256 },
1494
1524
  sources: {
1495
1525
  ...style.sources,
1496
- tileflow: { ...sourceWithoutSelector, tiles: [...resolution.tiles] }
1526
+ tileflow: { ...sourceWithoutSelector, url }
1497
1527
  }
1498
1528
  }
1499
1529
  };
@@ -1580,6 +1610,7 @@ async function resolveTileflowCaptureWorldTileJson(tileJsonUrl, options = {}) {
1580
1610
  releaseId
1581
1611
  },
1582
1612
  tileJsonUrl: normalizedUrl,
1613
+ tileJson: text,
1583
1614
  tiles: [tileTemplate]
1584
1615
  };
1585
1616
  }
@@ -1839,7 +1870,7 @@ var TileflowCaptureSessionImpl = class {
1839
1870
  signal,
1840
1871
  timeoutMs: this.#options.timeoutMs
1841
1872
  }) : await captureStandaloneTileflowScene({
1842
- assets: artifacts.assets,
1873
+ assets: [...artifacts.assets, ...prepared.assets ?? []],
1843
1874
  browser,
1844
1875
  ...artifacts.localTilesets ? { localTilesets: artifacts.localTilesets } : {},
1845
1876
  scene,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/capture",
3
- "version": "0.1.0-alpha.25",
3
+ "version": "0.1.0-alpha.27",
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
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@tileflow/core": ">=0.1.0-alpha.27 <0.1.0-beta.0",
52
- "@tileflow/dev": ">=0.1.0-alpha.26 <0.1.0-beta.0",
51
+ "@tileflow/core": ">=0.1.0-alpha.29 <0.1.0-beta.0",
52
+ "@tileflow/dev": ">=0.1.0-alpha.27 <0.1.0-beta.0",
53
53
  "maplibre-gl": "6.9.0",
54
54
  "pixelmatch": "7.2.0",
55
55
  "playwright": "1.62.1",
@@ -68,12 +68,12 @@
68
68
  "vite": "^8.0.16",
69
69
  "vue": "^3.5.39",
70
70
  "webpack": "5.108.3",
71
+ "@tileflow/maps": "0.1.0-alpha.6",
71
72
  "@tileflow/next": "0.1.0-alpha.24",
72
- "@tileflow/react": "0.1.0-alpha.26",
73
- "@tileflow/svelte": "0.1.0-alpha.25",
74
- "@tileflow/maps": "0.1.0-alpha.5",
73
+ "@tileflow/react": "0.1.0-alpha.27",
75
74
  "@tileflow/vite": "0.1.0-alpha.24",
76
- "@tileflow/vue": "0.1.0-alpha.25",
75
+ "@tileflow/svelte": "0.1.0-alpha.26",
76
+ "@tileflow/vue": "0.1.0-alpha.26",
77
77
  "@tileflow/webpack": "0.1.0-alpha.24"
78
78
  },
79
79
  "scripts": {