@tileflow/dev 0.1.0-alpha.41 → 0.1.0-alpha.43

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/artifacts.js CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  usesTileflowLineBackgroundGlyphs,
33
33
  writeTileflowArtifactPlan,
34
34
  writeTileflowBuildArtifacts
35
- } from "./chunk-GXLY73PD.js";
35
+ } from "./chunk-3IHCBD7R.js";
36
36
  import {
37
37
  getTileflowAssetBasePath,
38
38
  getTileflowAssetFileName,
@@ -51,7 +51,7 @@ import {
51
51
  defaultTileflowConfigPath
52
52
  } from "./chunk-AQUGMUZW.js";
53
53
  import "./chunk-D4OE4ITL.js";
54
- import "./chunk-ONYQNLNA.js";
54
+ import "./chunk-6SLT6ONM.js";
55
55
  export {
56
56
  TileflowHostedManifestOverwriteError,
57
57
  TileflowLocalTilesetProductionError,
@@ -25,7 +25,7 @@ import {
25
25
  } from "./chunk-D4OE4ITL.js";
26
26
  import {
27
27
  inspectTileflowPmtilesForLocalUse
28
- } from "./chunk-ONYQNLNA.js";
28
+ } from "./chunk-6SLT6ONM.js";
29
29
 
30
30
  // src/artifacts.ts
31
31
  import { createHash as createHash5 } from "crypto";
@@ -70,6 +70,58 @@ import {
70
70
  } from "@tileflow/core/native-profile";
71
71
  import { prepareTileflowStyleFamilyForRendering } from "@tileflow/core/runtime";
72
72
 
73
+ // src/family-style-resources.ts
74
+ function rebaseTileflowFamilyStyle(style, mapName, themeName) {
75
+ const rebase = (value) => {
76
+ let start = 0;
77
+ let end = value.length;
78
+ while (start < end && value.charCodeAt(start) <= 32) start++;
79
+ while (end > start && value.charCodeAt(end - 1) <= 32) end--;
80
+ const reference = value.slice(start, end);
81
+ if (/^[\\/]/u.test(reference) || /^[a-z][a-z\d+.-]*:/iu.test(reference)) return value;
82
+ const target = !reference || /^[?#]/u.test(reference) ? `${themeName}.json${reference}` : reference;
83
+ return `../styles/${mapName}/${target}`;
84
+ };
85
+ const property = (value, key2) => {
86
+ if (record(value) && typeof value[key2] === "string") value[key2] = rebase(value[key2]);
87
+ };
88
+ const result = structuredClone(style);
89
+ property(result, "glyphs");
90
+ if (typeof result.sprite === "string") result.sprite = rebase(result.sprite);
91
+ else if (Array.isArray(result.sprite))
92
+ for (const sprite of result.sprite) property(sprite, "url");
93
+ const fontFaces = result["font-faces"];
94
+ if (record(fontFaces))
95
+ for (const [family, face] of Object.entries(fontFaces)) {
96
+ if (typeof face === "string") fontFaces[family] = rebase(face);
97
+ else property(face, "url");
98
+ }
99
+ for (const source of Object.values(result.sources)) {
100
+ property(source, "url");
101
+ if (source.type === "geojson") property(source, "data");
102
+ for (const key2 of ["tiles", "urls"]) {
103
+ const value = source[key2];
104
+ if (Array.isArray(value))
105
+ source[key2] = value.map(
106
+ (url) => typeof url === "string" ? rebase(url) : url
107
+ );
108
+ }
109
+ }
110
+ const fonts = result.metadata?.["tileflow:fontFaces"];
111
+ if (Array.isArray(fonts)) for (const face of fonts) property(face, "source");
112
+ for (const key2 of ["tileflow:buildings", "tileflow:vegetation"]) {
113
+ const descriptor = result.metadata?.[key2];
114
+ if (!record(descriptor)) continue;
115
+ if (Array.isArray(descriptor.models))
116
+ for (const model of descriptor.models) property(model, "url");
117
+ property(descriptor.landmarks, "url");
118
+ }
119
+ return result;
120
+ }
121
+ function record(value) {
122
+ return value !== null && typeof value === "object" && !Array.isArray(value);
123
+ }
124
+
73
125
  // src/image-source-assets.ts
74
126
  import { createHash } from "crypto";
75
127
  function prepareEmbeddedImageSources(input) {
@@ -326,6 +378,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
326
378
  for (const [sourceId, source] of Object.entries(map.sources ?? {}).sort(
327
379
  ([left], [right]) => compareCodeUnits(left, right)
328
380
  )) {
381
+ if (source.kind !== "hosted-tileset") continue;
329
382
  const requestedPath = resolve2(options.baseDirectory, source.local);
330
383
  const sourcePath = await realpath(requestedPath).catch(() => requestedPath);
331
384
  if (!isPathWithin(projectRoot, sourcePath)) {
@@ -2034,8 +2087,8 @@ function optionalDiagnosticPath(value) {
2034
2087
  }
2035
2088
  function isTileflowMapResolutionDiagnostic(value, path) {
2036
2089
  if (!value || typeof value !== "object" || !path) return false;
2037
- const record = value;
2038
- return record.name === "TileflowMapResolutionError" && typeof record.code === "string" && typeof record.mapId === "string" && path.startsWith("/modules/") && !/[\p{Cc}]/u.test(path) && !/~(?:[^01]|$)/u.test(path);
2090
+ const record2 = value;
2091
+ return record2.name === "TileflowMapResolutionError" && typeof record2.code === "string" && typeof record2.mapId === "string" && path.startsWith("/modules/") && !/[\p{Cc}]/u.test(path) && !/~(?:[^01]|$)/u.test(path);
2039
2092
  }
2040
2093
  function removeSemanticResolutionPath(message, path) {
2041
2094
  if (!path) return message;
@@ -2443,7 +2496,7 @@ function getStableTileflowArtifactFiles(artifacts) {
2443
2496
  ...!artifacts.nativeBuild ? Object.entries(artifacts.styles).map(([mapName, styles]) => ({
2444
2497
  contentType: "application/json; charset=utf-8",
2445
2498
  fileName: `families/${mapName}.json`,
2446
- source: `${JSON.stringify(prepareTileflowStyleFamilyForRendering(createTileflowStyleFamily(styles)))}
2499
+ source: `${JSON.stringify(prepareArtifactStyleFamily(mapName, styles))}
2447
2500
  `
2448
2501
  })) : [],
2449
2502
  ...artifacts.assets,
@@ -2458,6 +2511,18 @@ function getStableTileflowArtifactFiles(artifacts) {
2458
2511
  ];
2459
2512
  return validateArtifactFiles(files);
2460
2513
  }
2514
+ function prepareArtifactStyleFamily(mapName, styles) {
2515
+ return prepareTileflowStyleFamilyForRendering(
2516
+ createTileflowStyleFamily(
2517
+ Object.fromEntries(
2518
+ Object.entries(styles).map(([theme, style]) => [
2519
+ theme,
2520
+ rebaseTileflowFamilyStyle(style, mapName, theme)
2521
+ ])
2522
+ )
2523
+ )
2524
+ );
2525
+ }
2461
2526
  function validateArtifactFiles(files) {
2462
2527
  const seen = /* @__PURE__ */ new Set();
2463
2528
  for (const file of files) {
@@ -2553,20 +2618,19 @@ function createGenerationArtifactFiles(artifacts, generation, nativeUrls) {
2553
2618
  contentType: "application/json; charset=utf-8",
2554
2619
  fileName: `${prefix}/families/${mapName}.json`,
2555
2620
  source: `${JSON.stringify(
2556
- prepareTileflowStyleFamilyForRendering(
2557
- createTileflowStyleFamily(
2558
- Object.fromEntries(
2559
- Object.keys(artifacts.styles[mapName]).map((theme) => [
2560
- theme,
2561
- JSON.parse(
2562
- String(
2563
- immutableStyles.find(
2564
- (file) => file.fileName === `${prefix}/styles/${mapName}/${theme}.json`
2565
- ).source
2566
- )
2621
+ prepareArtifactStyleFamily(
2622
+ mapName,
2623
+ Object.fromEntries(
2624
+ Object.keys(artifacts.styles[mapName]).map((theme) => [
2625
+ theme,
2626
+ JSON.parse(
2627
+ String(
2628
+ immutableStyles.find(
2629
+ (file) => file.fileName === `${prefix}/styles/${mapName}/${theme}.json`
2630
+ ).source
2567
2631
  )
2568
- ])
2569
- )
2632
+ )
2633
+ ])
2570
2634
  )
2571
2635
  )
2572
2636
  )}
@@ -2788,7 +2852,9 @@ function assertNoLocalTilesetsForProduction(artifacts) {
2788
2852
  if (artifacts.localTilesets?.length) throw new TileflowLocalTilesetProductionError();
2789
2853
  }
2790
2854
  function hasLocalTilesetSources(project) {
2791
- return Object.values(project.maps).some((map) => Object.keys(map.sources ?? {}).length > 0);
2855
+ return Object.values(project.maps).some(
2856
+ (map) => Object.values(map.sources ?? {}).some((source) => source.kind === "hosted-tileset")
2857
+ );
2792
2858
  }
2793
2859
  async function assertTileflowSelfHostedManifestTarget(manifestPath, options = {}) {
2794
2860
  if (options.overwriteHostedManifest) return;
@@ -24,7 +24,7 @@ var inspectionLimits = Object.freeze({
24
24
  maxValuesPerField: 16
25
25
  });
26
26
  var maxArchiveBytes = 8e9;
27
- var maximumDecodedBytes = 4 * 1024 * 1024 * 1024;
27
+ var maximumDecodedBytes = 8 * 1024 * 1024 * 1024;
28
28
  var minimumDecodedBytes = 64 * 1024 * 1024;
29
29
  var maxDecompressedSectionBytes = 16 * 1024 * 1024;
30
30
  var defaultMaximumDirectoryDepth = 32;
@@ -420,9 +420,20 @@ async function validatePmtilesDirectoryTree(source, header, budget, maximumDirec
420
420
  ];
421
421
  const countedDirectories = /* @__PURE__ */ new Set();
422
422
  const processedContexts = /* @__PURE__ */ new Set();
423
- const clusteredContents = /* @__PURE__ */ new Set();
424
423
  const decompressDirectory = createSectionDecompressor(budget);
425
- let clusteredEnd = null;
424
+ let clusteredEnd = 0;
425
+ const advanceClusteredFrontier = (offset, length) => {
426
+ const end = offset + length;
427
+ if (offset === clusteredEnd) {
428
+ clusteredEnd = end;
429
+ } else if (offset > clusteredEnd || end > clusteredEnd) {
430
+ throw inspectionError(
431
+ "TF_TILESET_ARCHIVE_INVALID",
432
+ "archive",
433
+ "PMTiles clustered contents are not contiguous in TileID order."
434
+ );
435
+ }
436
+ };
426
437
  let addressedTiles = 0;
427
438
  let totalEntries = 0;
428
439
  let tileEntries = 0;
@@ -430,20 +441,7 @@ async function validatePmtilesDirectoryTree(source, header, budget, maximumDirec
430
441
  signal?.throwIfAborted();
431
442
  const item = pending.pop();
432
443
  if (item.kind === "clustered-content") {
433
- const key = `${item.offset}:${item.length}`;
434
- if (clusteredContents.has(key)) continue;
435
- if (clusteredEnd === null ? item.offset !== 0 : item.offset !== clusteredEnd) {
436
- throw inspectionError(
437
- "TF_TILESET_ARCHIVE_INVALID",
438
- "archive",
439
- "PMTiles clustered contents are not contiguous in TileID order."
440
- );
441
- }
442
- clusteredContents.add(key);
443
- clusteredEnd = item.offset + item.length;
444
- assertParserMemory(
445
- processedContexts.size + countedDirectories.size + clusteredContents.size + pending.length
446
- );
444
+ advanceClusteredFrontier(item.offset, item.length);
447
445
  continue;
448
446
  }
449
447
  const current = item;
@@ -459,9 +457,7 @@ async function validatePmtilesDirectoryTree(source, header, budget, maximumDirec
459
457
  processedContexts.add(contextKey);
460
458
  const firstPhysicalVisit = !countedDirectories.has(current.key);
461
459
  countedDirectories.add(current.key);
462
- assertParserMemory(
463
- processedContexts.size + countedDirectories.size + clusteredContents.size + pending.length
464
- );
460
+ assertParserMemory(processedContexts.size + countedDirectories.size + pending.length);
465
461
  const response = await source.getBytes(current.offset, current.length, signal);
466
462
  if (response.data.byteLength !== current.length) {
467
463
  throw inspectionError("TF_TILESET_ARCHIVE_INVALID", "archive", "Short PMTiles directory.");
@@ -537,11 +533,15 @@ async function validatePmtilesDirectoryTree(source, header, budget, maximumDirec
537
533
  addressedTiles += entry.runLength;
538
534
  tileEntries += 1;
539
535
  if (header.clustered) {
540
- nextItems.push({
541
- kind: "clustered-content",
542
- length: entry.length,
543
- offset: entry.offset
544
- });
536
+ if (nextItems.length === 0) {
537
+ advanceClusteredFrontier(entry.offset, entry.length);
538
+ } else {
539
+ nextItems.push({
540
+ kind: "clustered-content",
541
+ length: entry.length,
542
+ offset: entry.offset
543
+ });
544
+ }
545
545
  }
546
546
  }
547
547
  if (!Number.isSafeInteger(addressedTiles) || !Number.isSafeInteger(tileEntries)) {
@@ -551,9 +551,7 @@ async function validatePmtilesDirectoryTree(source, header, budget, maximumDirec
551
551
  for (let index = nextItems.length - 1; index >= 0; index -= 1) {
552
552
  pending.push(nextItems[index]);
553
553
  }
554
- assertParserMemory(
555
- processedContexts.size + countedDirectories.size + clusteredContents.size + pending.length
556
- );
554
+ assertParserMemory(processedContexts.size + countedDirectories.size + pending.length);
557
555
  }
558
556
  if (header.numAddressedTiles !== 0 && addressedTiles !== header.numAddressedTiles || header.numTileEntries !== 0 && tileEntries !== header.numTileEntries) {
559
557
  throw inspectionError(
package/dist/server.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  parseTileflowLineBackgroundGlyphPath,
6
6
  tileflowArtifactSessionSchemaVersion,
7
7
  tileflowLineBackgroundGlyphRoute
8
- } from "./chunk-GXLY73PD.js";
8
+ } from "./chunk-3IHCBD7R.js";
9
9
  import {
10
10
  getTileflowAssetBasePath,
11
11
  getTileflowAssetFileName,
@@ -24,7 +24,7 @@ import {
24
24
  defaultTileflowConfigPath
25
25
  } from "./chunk-AQUGMUZW.js";
26
26
  import "./chunk-D4OE4ITL.js";
27
- import "./chunk-ONYQNLNA.js";
27
+ import "./chunk-6SLT6ONM.js";
28
28
 
29
29
  // src/server.ts
30
30
  import { open } from "fs/promises";
package/dist/tilesets.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  inspectTileflowPmtiles
3
- } from "./chunk-ONYQNLNA.js";
3
+ } from "./chunk-6SLT6ONM.js";
4
4
  export {
5
5
  inspectTileflowPmtiles
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/dev",
3
- "version": "0.1.0-alpha.41",
3
+ "version": "0.1.0-alpha.43",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Node development utilities for Tileflow configs and builds.",
6
6
  "type": "module",
@@ -83,7 +83,7 @@
83
83
  "dependencies": {
84
84
  "@mapbox/vector-tile": "3.0.0",
85
85
  "@maplibre/maplibre-gl-style-spec": "26.4.4",
86
- "@tileflow/core": ">=0.1.0-alpha.45 <0.1.0-beta.0",
86
+ "@tileflow/core": ">=0.1.0-alpha.48 <0.1.0-beta.0",
87
87
  "chokidar": "6.0.0",
88
88
  "fontkit": "2.0.4",
89
89
  "jiti": "^2.7.0",
@@ -95,14 +95,14 @@
95
95
  "three": "0.185.1"
96
96
  },
97
97
  "devDependencies": {
98
- "@tileflow/maps": "0.1.0-alpha.18"
98
+ "@tileflow/maps": "0.1.0-alpha.20"
99
99
  },
100
100
  "optionalDependencies": {
101
101
  "sharp": "0.35.5"
102
102
  },
103
103
  "scripts": {
104
104
  "build": "tsup src/artifacts.ts src/config.ts src/fonts.ts src/icons.ts src/inspect.ts src/preview.ts src/server.ts src/tilesets.ts src/validation.ts --format esm --dts --clean --platform node --external sharp && tsup --config tsup.inspector.config.ts",
105
- "test": "tsx --test test/*.test.ts",
105
+ "test": "tsx --test --test-concurrency=2 test/*.test.ts",
106
106
  "typecheck": "tsc -p tsconfig.json --noEmit",
107
107
  "lint": "tsc -p tsconfig.json --noEmit",
108
108
  "verify": "pnpm run typecheck && pnpm run test"