@tileflow/dev 0.1.0-alpha.27 → 0.1.0-alpha.29

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.
@@ -28,26 +28,26 @@ import {
28
28
  } from "./chunk-D4OE4ITL.js";
29
29
 
30
30
  // src/artifacts.ts
31
- import { createHash as createHash3 } from "crypto";
31
+ import { createHash as createHash4 } from "crypto";
32
32
  import { realpathSync as realpathSync2 } from "fs";
33
33
  import {
34
34
  copyFile as copyFile2,
35
- lstat as lstat2,
36
- mkdir as mkdir2,
35
+ lstat as lstat3,
36
+ mkdir as mkdir3,
37
37
  mkdtemp,
38
38
  open as open2,
39
- readFile,
39
+ readFile as readFile2,
40
40
  realpath as realpath2,
41
- rename,
42
- rm as rm2,
41
+ rename as rename2,
42
+ rm as rm3,
43
43
  unlink
44
44
  } from "fs/promises";
45
45
  import { createRequire } from "module";
46
- import { dirname as dirname2, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
46
+ import { dirname as dirname2, relative as relative2, resolve as resolve4, sep as sep2 } from "path";
47
47
  import {
48
48
  compareCodeUnits as compareCodeUnits2,
49
49
  getTileflowStyleFontFaces as getTileflowStyleFontFaces2,
50
- serializeCanonicalJson as serializeCanonicalJson4,
50
+ serializeCanonicalJson as serializeCanonicalJson3,
51
51
  tileflowMapIdSchema,
52
52
  tileflowThemeNameSchema
53
53
  } from "@tileflow/core";
@@ -62,17 +62,200 @@ import {
62
62
  import { parseTileflowRuntimeManifest } from "@tileflow/core/manifest";
63
63
  import {
64
64
  createTileflowNativeBuildRecord as createTileflowNativeBuildRecord2,
65
- createTileflowNativeDiagnostic as createTileflowNativeDiagnostic4,
65
+ createTileflowNativeDiagnostic as createTileflowNativeDiagnostic3,
66
66
  resolveTileflowRenderer,
67
67
  tileflowNativeBuildRecordFileName,
68
- TileflowNativeCompatibilityError as TileflowNativeCompatibilityError5
68
+ TileflowNativeCompatibilityError as TileflowNativeCompatibilityError4
69
69
  } from "@tileflow/core/native-profile";
70
70
 
71
+ // src/line-background-glyphs.ts
72
+ import { createHash, randomUUID } from "crypto";
73
+ import { lstat, mkdir, readFile, rename, rm, writeFile } from "fs/promises";
74
+ import { resolve } from "path";
75
+ import {
76
+ deriveTileflowLineBackgroundGlyphs,
77
+ parseTileflowLineBackgroundFontStack
78
+ } from "@tileflow/core";
79
+ var tileflowLineBackgroundGlyphRoute = "__glyphs";
80
+ var RANGE = /^\d{1,6}-\d{1,6}$/u;
81
+ var FONT_STACK = /^[\p{L}\p{N} _.,-]{1,256}$/u;
82
+ var MAP_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
83
+ var MAX_RANGE_BYTES = 8 * 1024 * 1024;
84
+ var MAX_DERIVED_ENTRIES = 512;
85
+ var CACHE_SEGMENTS = [".tileflow", "cache", "glyphs", "v1"];
86
+ function usesTileflowLineBackgroundGlyphs(style) {
87
+ return style.layers.some((layer) => {
88
+ const layout = layer.layout;
89
+ const font = layout?.["text-font"];
90
+ return Array.isArray(font) && font.length === 1 && typeof font[0] === "string" && parseTileflowLineBackgroundFontStack(font[0]) !== void 0;
91
+ });
92
+ }
93
+ function prepareTileflowLineBackgroundGlyphs(styles, options) {
94
+ const base = absoluteHttpUrl(options.assetBaseUrl);
95
+ if (!base) return { providers: {}, styles };
96
+ const providers = {};
97
+ const output = {};
98
+ for (const [mapName, themes] of Object.entries(styles)) {
99
+ const family = Object.values(themes);
100
+ const upstream = family.find((style) => typeof style.glyphs === "string")?.glyphs;
101
+ if (!MAP_NAME.test(mapName) || !upstream || !absoluteHttpUrl(upstream) || !family.some(usesTileflowLineBackgroundGlyphs) || family.some((style) => style.glyphs !== upstream)) {
102
+ output[mapName] = themes;
103
+ continue;
104
+ }
105
+ providers[mapName] = upstream;
106
+ const glyphs = `${base.replace(/\/+$/u, "")}/${tileflowLineBackgroundGlyphRoute}/${mapName}/{fontstack}/{range}.pbf`;
107
+ output[mapName] = Object.fromEntries(
108
+ Object.entries(themes).map(([themeName, style]) => [themeName, { ...style, glyphs }])
109
+ );
110
+ }
111
+ return { providers, styles: output };
112
+ }
113
+ function parseTileflowLineBackgroundGlyphPath(path) {
114
+ const match = /^\/__glyphs\/([^/]+)\/([^/]+)\/([^/]+)\.pbf$/u.exec(path);
115
+ if (!match) return void 0;
116
+ let fontStack;
117
+ try {
118
+ fontStack = decodeURIComponent(match[2]);
119
+ } catch {
120
+ return void 0;
121
+ }
122
+ if (!MAP_NAME.test(match[1]) || !FONT_STACK.test(fontStack) || !RANGE.test(match[3])) {
123
+ return void 0;
124
+ }
125
+ return { fontStack, mapName: match[1], range: match[3] };
126
+ }
127
+ function createTileflowLineBackgroundGlyphResponder(options) {
128
+ const fetchRange = options.fetch ?? globalThis.fetch;
129
+ const derived = /* @__PURE__ */ new Map();
130
+ const upstreamRanges = /* @__PURE__ */ new Map();
131
+ const readUpstream = (upstream, fontStack, range) => {
132
+ const key2 = `${upstream}
133
+ ${fontStack}
134
+ ${range}`;
135
+ let pending = upstreamRanges.get(key2);
136
+ if (!pending) {
137
+ pending = loadUpstreamRange(options.cwd, fetchRange, upstream, fontStack, range).finally(
138
+ () => upstreamRanges.delete(key2)
139
+ );
140
+ upstreamRanges.set(key2, pending);
141
+ }
142
+ return pending;
143
+ };
144
+ return async (upstream, fontStack, range) => {
145
+ if (!absoluteHttpUrl(upstream) || !FONT_STACK.test(fontStack) || !RANGE.test(range)) {
146
+ return notFound();
147
+ }
148
+ const backed = parseTileflowLineBackgroundFontStack(fontStack);
149
+ if (!backed) {
150
+ if (fontStack.split(",").some((stack) => parseTileflowLineBackgroundFontStack(stack))) {
151
+ return notFound();
152
+ }
153
+ return glyphResponse(await readUpstream(upstream, fontStack, range));
154
+ }
155
+ const key2 = `${upstream}
156
+ ${fontStack}
157
+ ${range}`;
158
+ let pending = derived.get(key2);
159
+ if (!pending) {
160
+ pending = readUpstream(upstream, backed.source, range).then(
161
+ (source) => source ? deriveTileflowLineBackgroundGlyphs(source, backed.metrics) : void 0
162
+ );
163
+ pending.catch(() => derived.delete(key2));
164
+ derived.set(key2, pending);
165
+ if (derived.size > MAX_DERIVED_ENTRIES) derived.delete(derived.keys().next().value);
166
+ }
167
+ return glyphResponse(await pending);
168
+ };
169
+ }
170
+ async function loadUpstreamRange(cwd, fetchRange, upstream, fontStack, range) {
171
+ const directory = await cacheDirectory(cwd, upstream);
172
+ const file = resolve(directory, `${digest(fontStack)}-${range}.pbf`);
173
+ const cached = await readFile(file).catch((error) => {
174
+ if (hasCode(error, "ENOENT")) return void 0;
175
+ throw error;
176
+ });
177
+ if (cached) return new Uint8Array(cached);
178
+ const url = upstream.replace("{fontstack}", encodeURIComponent(fontStack)).replace("{range}", range);
179
+ const response = await fetchRange(url, {
180
+ credentials: "omit",
181
+ headers: { Accept: "application/x-protobuf" },
182
+ redirect: "error",
183
+ signal: AbortSignal.timeout(3e4)
184
+ });
185
+ if (response.status === 404) return void 0;
186
+ if (response.status !== 200) {
187
+ throw new Error(`Glyph provider responded ${response.status} for ${fontStack} ${range}.`);
188
+ }
189
+ const length = Number(response.headers.get("content-length") ?? 0);
190
+ if (length > MAX_RANGE_BYTES) throw new Error(`Glyph range ${range} exceeds the size limit.`);
191
+ const bytes = new Uint8Array(await response.arrayBuffer());
192
+ if (bytes.byteLength > MAX_RANGE_BYTES)
193
+ throw new Error(`Glyph range ${range} exceeds the size limit.`);
194
+ const temporary = `${file}.${randomUUID()}.tmp`;
195
+ try {
196
+ await writeFile(temporary, bytes, { flag: "wx" });
197
+ await rename(temporary, file);
198
+ } catch {
199
+ await rm(temporary, { force: true }).catch(() => void 0);
200
+ }
201
+ return bytes;
202
+ }
203
+ async function cacheDirectory(cwd, upstream) {
204
+ let current = resolve(cwd);
205
+ for (const segment of [...CACHE_SEGMENTS, digest(upstream)]) {
206
+ current = resolve(current, segment);
207
+ try {
208
+ const stats = await lstat(current);
209
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
210
+ throw new Error(`Glyph cache path is unsafe: ${current}`);
211
+ }
212
+ } catch (error) {
213
+ if (!hasCode(error, "ENOENT")) throw error;
214
+ await mkdir(current).catch((mkdirError) => {
215
+ if (!hasCode(mkdirError, "EEXIST")) throw mkdirError;
216
+ });
217
+ }
218
+ }
219
+ return current;
220
+ }
221
+ function glyphResponse(bytes) {
222
+ if (!bytes) return notFound();
223
+ return new Response(new Uint8Array(bytes), {
224
+ headers: {
225
+ "Access-Control-Allow-Origin": "*",
226
+ "Cache-Control": "no-cache",
227
+ "Content-Type": "application/x-protobuf"
228
+ },
229
+ status: 200
230
+ });
231
+ }
232
+ function notFound() {
233
+ return new Response(JSON.stringify({ error: "Unknown glyph range." }), {
234
+ headers: { "Content-Type": "application/json; charset=utf-8" },
235
+ status: 404
236
+ });
237
+ }
238
+ function absoluteHttpUrl(value) {
239
+ if (!value) return void 0;
240
+ try {
241
+ const url = new URL(value.replace("{fontstack}", "stack").replace("{range}", "0-255"));
242
+ return url.protocol === "http:" || url.protocol === "https:" ? value : void 0;
243
+ } catch {
244
+ return void 0;
245
+ }
246
+ }
247
+ function digest(value) {
248
+ return createHash("sha256").update(value).digest("hex").slice(0, 32);
249
+ }
250
+ function hasCode(error, code) {
251
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
252
+ }
253
+
71
254
  // src/local-tilesets.ts
72
- import { randomUUID } from "crypto";
255
+ import { randomUUID as randomUUID2 } from "crypto";
73
256
  import { constants } from "fs";
74
- import { chmod, copyFile, lstat, mkdir, open, readdir, realpath, rm, stat } from "fs/promises";
75
- import { basename, resolve } from "path";
257
+ import { chmod, copyFile, lstat as lstat2, mkdir as mkdir2, open, readdir, realpath, rm as rm2, stat } from "fs/promises";
258
+ import { basename, resolve as resolve2 } from "path";
76
259
  import { compareCodeUnits } from "@tileflow/core";
77
260
  var minimumLocalPmtilesBytes = 127n;
78
261
  var maximumLocalPmtilesBytes = 8000000000n;
@@ -83,14 +266,14 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
83
266
  if (!hasSources) {
84
267
  return { dispose: async () => void 0, files: [], styles, watchPaths: [] };
85
268
  }
86
- const logicalProjectRoot = resolve(options.cwd);
269
+ const logicalProjectRoot = resolve2(options.cwd);
87
270
  const projectRoot = await realpath(logicalProjectRoot).catch(() => logicalProjectRoot);
88
- const snapshotStore = resolve(logicalProjectRoot, ".tileflow/cache/pmtiles-snapshots/v1");
271
+ const snapshotStore = resolve2(logicalProjectRoot, ".tileflow/cache/pmtiles-snapshots/v1");
89
272
  await assertSafeSnapshotStore(logicalProjectRoot, snapshotStore);
90
273
  await collectAbandonedSnapshotGenerations(snapshotStore);
91
- const generationId = `snapshot-${process.pid}-${randomUUID().replaceAll("-", "")}`;
92
- const generationDirectory = resolve(snapshotStore, generationId);
93
- await mkdir(generationDirectory);
274
+ const generationId = `snapshot-${process.pid}-${randomUUID2().replaceAll("-", "")}`;
275
+ const generationDirectory = resolve2(snapshotStore, generationId);
276
+ await mkdir2(generationDirectory);
94
277
  const bindings = /* @__PURE__ */ new Map();
95
278
  const files = /* @__PURE__ */ new Map();
96
279
  const snapshots = /* @__PURE__ */ new Map();
@@ -109,7 +292,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
109
292
  if (!isPathWithin(snapshotStore, generationDirectory)) {
110
293
  throw new Error("Local PMTiles snapshot generation escaped its store.");
111
294
  }
112
- await rm(generationDirectory, { force: true, recursive: true });
295
+ await rm2(generationDirectory, { force: true, recursive: true });
113
296
  };
114
297
  try {
115
298
  for (const mapName of Object.keys(project.maps).sort(compareCodeUnits)) {
@@ -117,7 +300,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
117
300
  for (const [sourceId, source] of Object.entries(map.sources ?? {}).sort(
118
301
  ([left], [right]) => compareCodeUnits(left, right)
119
302
  )) {
120
- const requestedPath = resolve(options.baseDirectory, source.local);
303
+ const requestedPath = resolve2(options.baseDirectory, source.local);
121
304
  const sourcePath = await realpath(requestedPath).catch(() => requestedPath);
122
305
  if (!isPathWithin(projectRoot, sourcePath)) {
123
306
  throw localTilesetError(
@@ -126,7 +309,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
126
309
  "Local hosted tileset must stay inside the project root."
127
310
  );
128
311
  }
129
- const sourceStat = await lstat(sourcePath).catch(() => null);
312
+ const sourceStat = await lstat2(sourcePath).catch(() => null);
130
313
  if (!sourceStat?.isFile() || sourceStat.isSymbolicLink()) {
131
314
  throw localTilesetError(
132
315
  "TF_LOCAL_TILESET_NOT_FOUND",
@@ -197,7 +380,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
197
380
  }
198
381
  async function createLocalTilesetSnapshot(sourcePath, generationDirectory, index) {
199
382
  const sourceHandle = await open(sourcePath, "r");
200
- const snapshotPath = resolve(generationDirectory, `${index}.pmtiles`);
383
+ const snapshotPath = resolve2(generationDirectory, `${index}.pmtiles`);
201
384
  try {
202
385
  const before = sourceIdentity(await sourceHandle.stat({ bigint: true }));
203
386
  if (before.size < minimumLocalPmtilesBytes || before.size > maximumLocalPmtilesBytes) {
@@ -325,32 +508,32 @@ async function collectAbandonedSnapshotGenerations(store) {
325
508
  if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
326
509
  const match = /^snapshot-(\d+)-[a-f0-9]{32}$/u.exec(entry.name);
327
510
  if (!match?.[1] || processIsAlive(Number(match[1]))) continue;
328
- const path = resolve(store, entry.name);
329
- if (isPathWithin(store, path)) await rm(path, { force: true, recursive: true });
511
+ const path = resolve2(store, entry.name);
512
+ if (isPathWithin(store, path)) await rm2(path, { force: true, recursive: true });
330
513
  }
331
514
  }
332
515
  async function assertSafeSnapshotStore(projectRoot, store) {
333
516
  const segments = [".tileflow", "cache", "pmtiles-snapshots", "v1"];
334
517
  let current = projectRoot;
335
518
  for (const segment of segments) {
336
- current = resolve(current, segment);
519
+ current = resolve2(current, segment);
337
520
  try {
338
- const value = await lstat(current);
521
+ const value = await lstat2(current);
339
522
  if (!value.isDirectory() || value.isSymbolicLink()) {
340
523
  throw new Error(`Local PMTiles snapshot path is unsafe: ${current}`);
341
524
  }
342
525
  } catch (error) {
343
526
  if (!hasErrorCode(error, "ENOENT")) throw error;
344
- await mkdir(current).catch((mkdirError) => {
527
+ await mkdir2(current).catch((mkdirError) => {
345
528
  if (!hasErrorCode(mkdirError, "EEXIST")) throw mkdirError;
346
529
  });
347
- const created = await lstat(current);
530
+ const created = await lstat2(current);
348
531
  if (!created.isDirectory() || created.isSymbolicLink()) {
349
532
  throw new Error(`Local PMTiles snapshot path is unsafe: ${current}`);
350
533
  }
351
534
  }
352
535
  }
353
- if (resolve(current) !== resolve(store)) {
536
+ if (resolve2(current) !== resolve2(store)) {
354
537
  throw new Error("Local PMTiles snapshot path escaped its project root.");
355
538
  }
356
539
  }
@@ -384,7 +567,7 @@ function hasErrorCode(error, code) {
384
567
  }
385
568
 
386
569
  // src/native-artifacts.ts
387
- import { createHash } from "crypto";
570
+ import { createHash as createHash2 } from "crypto";
388
571
  import {
389
572
  convertFilter,
390
573
  validateStyleMin
@@ -404,6 +587,114 @@ import {
404
587
  validateTileflowNativePreparedStyle
405
588
  } from "@tileflow/core/native-profile";
406
589
 
590
+ // src/native-layer-references.ts
591
+ var overlayKeys = [
592
+ "above-water",
593
+ "below-roads",
594
+ "above-roads",
595
+ "above-buildings",
596
+ "below-labels",
597
+ "above-labels"
598
+ ];
599
+ function object(value) {
600
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
601
+ return value;
602
+ }
603
+ function identifier(layer) {
604
+ if (typeof layer.id !== "string" || !layer.id.length) throw new Error();
605
+ return layer.id;
606
+ }
607
+ function rebindNativeLayerReferences(input, lowered, changes) {
608
+ try {
609
+ const originalIndexes = /* @__PURE__ */ new Map();
610
+ const finalIndexes = /* @__PURE__ */ new Map();
611
+ const starts = /* @__PURE__ */ new Map();
612
+ const transformed = /* @__PURE__ */ new Map();
613
+ let previous = -1;
614
+ for (const change of changes) {
615
+ if (!Number.isSafeInteger(change.inputLayer) || change.inputLayer <= previous || change.inputLayer >= input.layers.length || !Number.isSafeInteger(change.outputStart) || !Number.isSafeInteger(change.outputCount) || change.outputCount < 1 || change.outputCount > 32 || !Array.isArray(change.properties) || !["line-cap", "line-dasharray", "line-cap,line-dasharray"].includes(
616
+ change.properties.join(",")
617
+ ))
618
+ throw new Error();
619
+ previous = change.inputLayer;
620
+ transformed.set(change.inputLayer, change);
621
+ }
622
+ for (const [index, layer] of lowered.layers.entries()) {
623
+ const id = identifier(layer);
624
+ if (finalIndexes.has(id)) throw new Error();
625
+ finalIndexes.set(id, index);
626
+ }
627
+ let offset = 0;
628
+ for (const [index, layer] of input.layers.entries()) {
629
+ const id = identifier(layer);
630
+ if (originalIndexes.has(id)) throw new Error();
631
+ originalIndexes.set(id, index);
632
+ starts.set(id, offset);
633
+ const change = transformed.get(index);
634
+ if (change && (change.outputStart !== offset || layer.type !== "line")) throw new Error();
635
+ const count = change?.outputCount ?? 1;
636
+ if (offset + count > lowered.layers.length) throw new Error();
637
+ for (let branch = 0; branch < count; branch++) {
638
+ const candidate = lowered.layers[offset + branch];
639
+ if (!change && identifier(candidate) !== id) throw new Error();
640
+ if (candidate.type !== layer.type || candidate.source !== layer.source || candidate["source-layer"] !== layer["source-layer"])
641
+ throw new Error();
642
+ }
643
+ offset += count;
644
+ }
645
+ if (offset !== lowered.layers.length) throw new Error();
646
+ const metadata = lowered.metadata === void 0 ? void 0 : { ...object(lowered.metadata) };
647
+ const originalMetadata = input.metadata === void 0 ? void 0 : object(input.metadata);
648
+ if (originalMetadata?.["tileflow:overlay-placement-manifest"] !== void 0) {
649
+ if (!metadata) throw new Error();
650
+ const overlay = object(originalMetadata["tileflow:overlay-placement-manifest"]);
651
+ const anchors = object(overlay.anchors);
652
+ if (overlay.schemaVersion !== 1 || Object.keys(anchors).length !== overlayKeys.length || overlayKeys.some((key2) => !Object.hasOwn(anchors, key2)))
653
+ throw new Error();
654
+ const updated = {};
655
+ for (const key2 of overlayKeys) {
656
+ const anchor = anchors[key2];
657
+ if (anchor === null) {
658
+ updated[key2] = null;
659
+ continue;
660
+ }
661
+ if (typeof anchor !== "string" || !starts.has(anchor)) throw new Error();
662
+ updated[key2] = identifier(lowered.layers[starts.get(anchor)]);
663
+ }
664
+ metadata["tileflow:overlay-placement-manifest"] = { ...overlay, anchors: updated };
665
+ }
666
+ if (originalMetadata?.["tileflow:interaction-manifest"] !== void 0) {
667
+ if (!metadata) throw new Error();
668
+ const manifest = object(originalMetadata["tileflow:interaction-manifest"]);
669
+ if (manifest.version !== 2) throw new Error();
670
+ const domains = object(manifest.domains);
671
+ let rebound = manifest;
672
+ if (domains.poi !== void 0) {
673
+ const poi = object(domains.poi);
674
+ if (!Array.isArray(poi.layers) || poi.layers.length > 256) throw new Error();
675
+ const seen = /* @__PURE__ */ new Set();
676
+ const layers = poi.layers.map((value) => {
677
+ const entry = object(value);
678
+ if (typeof entry.layerId !== "string" || seen.has(entry.layerId)) throw new Error();
679
+ const index = originalIndexes.get(entry.layerId);
680
+ if (index === void 0 || index !== entry.priority || transformed.has(index) || !finalIndexes.has(entry.layerId))
681
+ throw new Error();
682
+ const original = input.layers[index];
683
+ if (original.source !== entry.source || original["source-layer"] !== entry.sourceLayer)
684
+ throw new Error();
685
+ seen.add(entry.layerId);
686
+ return { ...entry, priority: finalIndexes.get(entry.layerId) };
687
+ });
688
+ rebound = { ...manifest, domains: { ...domains, poi: { ...poi, layers } } };
689
+ }
690
+ metadata["tileflow:interaction-manifest"] = rebound;
691
+ }
692
+ return metadata === void 0 ? { ...lowered } : { ...lowered, metadata };
693
+ } catch {
694
+ return void 0;
695
+ }
696
+ }
697
+
407
698
  // src/native-lowering.ts
408
699
  var nativeLoweringLimits = Object.freeze({
409
700
  maximumDecisionDepth: 16,
@@ -430,7 +721,7 @@ var NativeLoweringError = class extends Error {
430
721
  function fail(path, reason = "shape") {
431
722
  throw new NativeLoweringError(path, reason);
432
723
  }
433
- function object(value) {
724
+ function object2(value) {
434
725
  return value !== null && typeof value === "object" && !Array.isArray(value);
435
726
  }
436
727
  function operation(value, name, length) {
@@ -871,21 +1162,21 @@ function lowerNativeStyleRepresentation(input, normalizeFilter = (filter) => fil
871
1162
  const originalLayers = input.layers;
872
1163
  const reserved = /* @__PURE__ */ new Set();
873
1164
  for (const [index, layer] of originalLayers.entries()) {
874
- if (!object(layer) || typeof layer.id !== "string" || reserved.has(layer.id))
1165
+ if (!object2(layer) || typeof layer.id !== "string" || reserved.has(layer.id))
875
1166
  fail(`/layers/${index}/id`);
876
1167
  reserved.add(layer.id);
877
1168
  }
878
1169
  let projection = "none";
879
1170
  if (input.projection !== void 0) {
880
- if (!object(input.projection) || Object.keys(input.projection).length !== 1 || typeof input.projection.type !== "string" || !["globe", "mercator"].includes(input.projection.type))
1171
+ if (!object2(input.projection) || Object.keys(input.projection).length !== 1 || typeof input.projection.type !== "string" || !["globe", "mercator"].includes(input.projection.type))
881
1172
  fail("/projection");
882
1173
  projection = input.projection.type === "globe" ? "globe-to-mercator" : "mercator-to-implicit";
883
1174
  }
884
1175
  const layers = [];
885
1176
  const transformations = [];
886
1177
  for (const [index, layer] of originalLayers.entries()) {
887
- const source = object(input.sources) && typeof layer.source === "string" ? input.sources[layer.source] : void 0;
888
- const lowered = lowerLayer(layer, index, object(source) && source.type === "vector");
1178
+ const source = object2(input.sources) && typeof layer.source === "string" ? input.sources[layer.source] : void 0;
1179
+ const lowered = lowerLayer(layer, index, object2(source) && source.type === "vector");
889
1180
  if (!lowered) {
890
1181
  layers.push(layer);
891
1182
  continue;
@@ -933,11 +1224,17 @@ function lowerNativeStyleRepresentation(input, normalizeFilter = (filter) => fil
933
1224
  function documentUrl(map, theme) {
934
1225
  return `https://artifacts.invalid/native/styles/${map}/${theme}.json`;
935
1226
  }
1227
+ function urlOptions(map, theme, policy) {
1228
+ return {
1229
+ documentUrl: documentUrl(map, theme),
1230
+ ...policy.developmentOrigin === void 0 ? {} : { developmentOrigin: policy.developmentOrigin }
1231
+ };
1232
+ }
936
1233
  function withContext(issue, map, theme) {
937
1234
  const prefix = `/maps/${map}/themes/${theme}/style`;
938
1235
  return { ...issue, path: prefix.length + issue.path.length <= 300 ? prefix + issue.path : prefix };
939
1236
  }
940
- function lowerTileflowNativeCompiledStyles(input) {
1237
+ function lowerTileflowNativeCompiledStyles(input, policy = {}) {
941
1238
  const styles = {};
942
1239
  const transformations = [];
943
1240
  for (const map of Object.keys(input).sort()) {
@@ -945,7 +1242,7 @@ function lowerTileflowNativeCompiledStyles(input) {
945
1242
  for (const theme of Object.keys(input[map]).sort()) {
946
1243
  const original = input[map][theme];
947
1244
  try {
948
- const options = { documentUrl: documentUrl(map, theme), deferFontClosure: true };
1245
+ const options = { ...urlOptions(map, theme, policy), deferFontClosure: true };
949
1246
  const pending = validateTileflowNativeStyle(original, options);
950
1247
  const blockers = pending.filter(
951
1248
  (issue) => issue.code !== "NATIVE_UNSUPPORTED_STYLE" || !(issue.path === "/projection" || /^\/layers\/\d+\/(?:layout\/line-cap|paint\/line-dasharray)(?:\/|$)/u.test(issue.path))
@@ -973,17 +1270,34 @@ function lowerTileflowNativeCompiledStyles(input) {
973
1270
  original,
974
1271
  (filter) => convertFilter(structuredClone(filter))
975
1272
  );
976
- const issues = validateTileflowNativePreparedStyle(lowered.style, options);
1273
+ const style = rebindNativeLayerReferences(
1274
+ original,
1275
+ lowered.style,
1276
+ lowered.layers
1277
+ );
1278
+ if (!style)
1279
+ throw new TileflowNativeCompatibilityError([
1280
+ withContext(
1281
+ {
1282
+ ...createTileflowNativeDiagnostic("NATIVE_UNSUPPORTED_STYLE", "/metadata"),
1283
+ message: "Tileflow POI interaction or overlay placement metadata does not match the compiled layers.",
1284
+ suggestion: "Rebuild with the Tileflow compiler; native lowering only rebinds POI priorities and overlay anchors that match the compiled layer order."
1285
+ },
1286
+ map,
1287
+ theme
1288
+ )
1289
+ ]);
1290
+ const issues = validateTileflowNativePreparedStyle(style, options);
977
1291
  if (issues.length)
978
1292
  throw new TileflowNativeCompatibilityError(
979
1293
  issues.map((issue) => withContext(issue, map, theme))
980
1294
  );
981
- styles[map][theme] = lowered.style;
1295
+ styles[map][theme] = style;
982
1296
  transformations.push({
983
1297
  map,
984
1298
  theme,
985
- inputStyleSha256: createHash("sha256").update(serializeCanonicalJson(original)).digest("hex"),
986
- loweredStyleSha256: createHash("sha256").update(serializeCanonicalJson(lowered.style)).digest("hex"),
1299
+ inputStyleSha256: createHash2("sha256").update(serializeCanonicalJson(original)).digest("hex"),
1300
+ loweredStyleSha256: createHash2("sha256").update(serializeCanonicalJson(style)).digest("hex"),
987
1301
  inputLayers: lowered.inputLayers,
988
1302
  outputLayers: lowered.outputLayers,
989
1303
  projection: lowered.projection,
@@ -1007,13 +1321,13 @@ function lowerTileflowNativeCompiledStyles(input) {
1007
1321
  }
1008
1322
  return { styles, transformations };
1009
1323
  }
1010
- function assertTileflowNativeCompiledStyles(project, styles) {
1324
+ function assertTileflowNativeCompiledStyles(project, styles, policy = {}) {
1011
1325
  const issues = [];
1012
1326
  for (const mapName of Object.keys(project.maps).sort()) {
1013
1327
  for (const theme of Object.keys(styles[mapName] ?? {}).sort()) {
1014
1328
  issues.push(
1015
1329
  ...validateTileflowNativePreparedStyle(styles[mapName][theme], {
1016
- documentUrl: documentUrl(mapName, theme),
1330
+ ...urlOptions(mapName, theme, policy),
1017
1331
  deferFontClosure: true
1018
1332
  }).map((issue) => withContext(issue, mapName, theme))
1019
1333
  );
@@ -1021,7 +1335,7 @@ function assertTileflowNativeCompiledStyles(project, styles) {
1021
1335
  }
1022
1336
  if (issues.length) throw new TileflowNativeCompatibilityError(issues);
1023
1337
  }
1024
- function prepareTileflowNativeStyles(input, assets) {
1338
+ function prepareTileflowNativeStyles(input, assets, policy = {}) {
1025
1339
  const issues = [];
1026
1340
  const result = {};
1027
1341
  for (const map of Object.keys(input).sort()) {
@@ -1035,7 +1349,7 @@ function prepareTileflowNativeStyles(input, assets) {
1035
1349
  for (const theme of Object.keys(input[map]).sort()) {
1036
1350
  const original = input[map][theme];
1037
1351
  const preflight = validateTileflowNativePreparedStyle(original, {
1038
- documentUrl: documentUrl(map, theme),
1352
+ ...urlOptions(map, theme, policy),
1039
1353
  deferFontClosure: true
1040
1354
  });
1041
1355
  if (preflight.length) {
@@ -1079,9 +1393,9 @@ function prepareTileflowNativeStyles(input, assets) {
1079
1393
  ...faces.length ? { "font-faces": nativeFaces } : {}
1080
1394
  };
1081
1395
  issues.push(
1082
- ...validateTileflowNativePreparedStyle(style, {
1083
- documentUrl: documentUrl(map, theme)
1084
- }).map((issue) => withContext(issue, map, theme))
1396
+ ...validateTileflowNativePreparedStyle(style, urlOptions(map, theme, policy)).map(
1397
+ (issue) => withContext(issue, map, theme)
1398
+ )
1085
1399
  );
1086
1400
  result[map][theme] = style;
1087
1401
  }
@@ -1097,10 +1411,10 @@ function isNativeFontAsset(asset) {
1097
1411
  if (!/\.(?:ttf|otf)$/u.test(asset.fileName) || !["00010000", "4f54544f"].includes(signature))
1098
1412
  return false;
1099
1413
  const expectedHash = /-([a-f0-9]{64})\.(?:ttf|otf)$/u.exec(asset.fileName)?.[1];
1100
- return expectedHash === createHash("sha256").update(bytes).digest("hex");
1414
+ return expectedHash === createHash2("sha256").update(bytes).digest("hex");
1101
1415
  }
1102
- function assertTileflowNativeGeneratedStyle(style, map, theme) {
1103
- const issues = validateTileflowNativePreparedStyle(style, { documentUrl: documentUrl(map, theme) });
1416
+ function assertTileflowNativeGeneratedStyle(style, map, theme, policy = {}) {
1417
+ const issues = validateTileflowNativePreparedStyle(style, urlOptions(map, theme, policy));
1104
1418
  if (issues.length) {
1105
1419
  throw new TileflowNativeCompatibilityError(
1106
1420
  issues.map((issue) => withContext(issue, map, theme))
@@ -1171,7 +1485,7 @@ function validNativeSprites(map, assets) {
1171
1485
  // src/session.ts
1172
1486
  import { watch } from "chokidar";
1173
1487
  import { realpathSync, statSync } from "fs";
1174
- import { basename as basename2, dirname, extname, isAbsolute, relative, resolve as resolve2, sep, win32 } from "path";
1488
+ import { basename as basename2, dirname, extname, isAbsolute, relative, resolve as resolve3, sep, win32 } from "path";
1175
1489
  import { tileflowIconMetadataFileName } from "@tileflow/core";
1176
1490
  import { TileflowNativeCompatibilityError as TileflowNativeCompatibilityError2 } from "@tileflow/core/native-profile";
1177
1491
  var tileflowArtifactSessionSchemaVersion = 1;
@@ -1224,13 +1538,13 @@ var TileflowArtifactSessionImpl = class {
1224
1538
  #watchedArtifactDirectories = /* @__PURE__ */ new Map();
1225
1539
  #watchedArtifactPaths = /* @__PURE__ */ new Set();
1226
1540
  constructor(options, buildArtifacts, discoverWatchPaths) {
1227
- this.#cwd = resolve2(options.cwd ?? process.cwd());
1228
- const configPath = resolve2(this.#cwd, options.config ?? "tileflow.config.ts");
1229
- this.#configPath = resolve2(canonicalWatchPath(dirname(configPath)), basename2(configPath));
1541
+ this.#cwd = resolve3(options.cwd ?? process.cwd());
1542
+ const configPath = resolve3(this.#cwd, options.config ?? "tileflow.config.ts");
1543
+ this.#configPath = resolve3(canonicalWatchPath(dirname(configPath)), basename2(configPath));
1230
1544
  this.#debounceMs = Math.max(0, Math.min(options.debounceMs ?? 75, 1e3));
1231
1545
  this.#watchEnabled = options.watch ?? false;
1232
1546
  this.#ignoredPaths = (options.ignoredPaths ?? []).map(
1233
- (path) => canonicalWatchPath(resolve2(this.#cwd, path))
1547
+ (path) => canonicalWatchPath(resolve3(this.#cwd, path))
1234
1548
  );
1235
1549
  this.#buildArtifacts = buildArtifacts;
1236
1550
  this.#discoverWatchPaths = discoverWatchPaths;
@@ -1239,6 +1553,7 @@ var TileflowArtifactSessionImpl = class {
1239
1553
  assetBaseUrl: options.assetBaseUrl,
1240
1554
  config: options.config,
1241
1555
  cwd: this.#cwd,
1556
+ ...options.developmentOrigin === void 0 ? {} : { developmentOrigin: options.developmentOrigin },
1242
1557
  // Trusted shared Icon Set resolution settings, supplied once by the owning command.
1243
1558
  ...options.icons ? { icons: options.icons } : {},
1244
1559
  inspection: options.inspection,
@@ -1463,7 +1778,7 @@ var TileflowArtifactSessionImpl = class {
1463
1778
  }
1464
1779
  #updateArtifactWatchPaths(paths) {
1465
1780
  if (!this.#watcher) return;
1466
- const next = new Set(paths.map((path) => canonicalWatchPath(resolve2(this.#cwd, path))));
1781
+ const next = new Set(paths.map((path) => canonicalWatchPath(resolve3(this.#cwd, path))));
1467
1782
  const previous = this.#watchedArtifactPaths;
1468
1783
  this.#watchedArtifactPaths = next;
1469
1784
  const previousDirectories = this.#watchedArtifactDirectories;
@@ -1528,7 +1843,7 @@ async function disposeArtifacts(artifacts) {
1528
1843
  await dispose?.();
1529
1844
  }
1530
1845
  function isSameOrInside(root, candidate) {
1531
- const path = relative(resolve2(root), resolve2(candidate));
1846
+ const path = relative(resolve3(root), resolve3(candidate));
1532
1847
  return path === "" || !isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`);
1533
1848
  }
1534
1849
  function directoryModificationTime(path) {
@@ -1546,15 +1861,15 @@ function resolveRawWatchPath(path, details) {
1546
1861
  const watchedPath = details.watchedPath;
1547
1862
  if (typeof watchedPath !== "string" || !isAbsolute(watchedPath)) return void 0;
1548
1863
  return canonicalWatchPath(
1549
- basename2(watchedPath) === path ? watchedPath : resolve2(watchedPath, path)
1864
+ basename2(watchedPath) === path ? watchedPath : resolve3(watchedPath, path)
1550
1865
  );
1551
1866
  }
1552
1867
  function canonicalWatchPath(path) {
1553
- const resolved = resolve2(path);
1868
+ const resolved = resolve3(path);
1554
1869
  let ancestor = resolved;
1555
1870
  while (true) {
1556
1871
  try {
1557
- return resolve2(realpathSync.native(ancestor), relative(ancestor, resolved));
1872
+ return resolve3(realpathSync.native(ancestor), relative(ancestor, resolved));
1558
1873
  } catch {
1559
1874
  const parent = dirname(ancestor);
1560
1875
  if (parent === ancestor) return resolved;
@@ -1661,15 +1976,15 @@ function removeSemanticResolutionPath(message, path) {
1661
1976
  return message.replace(` at ${path}:`, ":");
1662
1977
  }
1663
1978
  function localPathAliases(path) {
1664
- return [.../* @__PURE__ */ new Set([resolve2(path), canonicalPath(path)])].sort(
1979
+ return [.../* @__PURE__ */ new Set([resolve3(path), canonicalPath(path)])].sort(
1665
1980
  (left, right) => right.length - left.length
1666
1981
  );
1667
1982
  }
1668
1983
  function canonicalPath(path) {
1669
1984
  try {
1670
- return realpathSync.native(resolve2(path));
1985
+ return realpathSync.native(resolve3(path));
1671
1986
  } catch {
1672
- return resolve2(path);
1987
+ return resolve3(path);
1673
1988
  }
1674
1989
  }
1675
1990
  function normalizeDiagnostics(diagnostics) {
@@ -1705,8 +2020,8 @@ function boundDiagnosticText(value, limit) {
1705
2020
  }
1706
2021
 
1707
2022
  // src/hosted-native-artifacts.ts
1708
- import { createHash as createHash2 } from "crypto";
1709
- import { serializeCanonicalJson as serializeCanonicalJson3 } from "@tileflow/core";
2023
+ import { createHash as createHash3 } from "crypto";
2024
+ import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
1710
2025
  import {
1711
2026
  inferTileflowDataRequirements,
1712
2027
  inferTileflowSourceRequirements,
@@ -1714,135 +2029,17 @@ import {
1714
2029
  } from "@tileflow/core/build";
1715
2030
  import {
1716
2031
  createTileflowNativeBuildRecord,
1717
- TileflowNativeCompatibilityError as TileflowNativeCompatibilityError4,
1718
- createTileflowNativeDiagnostic as createTileflowNativeDiagnostic3
1719
- } from "@tileflow/core/native-profile";
1720
-
1721
- // src/native-hosted-provenance.ts
1722
- import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
1723
- import {
1724
- createTileflowNativeDiagnostic as createTileflowNativeDiagnostic2,
1725
- TileflowNativeCompatibilityError as TileflowNativeCompatibilityError3
2032
+ TileflowNativeCompatibilityError as TileflowNativeCompatibilityError3,
2033
+ createTileflowNativeDiagnostic as createTileflowNativeDiagnostic2
1726
2034
  } from "@tileflow/core/native-profile";
1727
- var overlayKeys = [
1728
- "above-water",
1729
- "below-roads",
1730
- "above-roads",
1731
- "above-buildings",
1732
- "below-labels",
1733
- "above-labels"
1734
- ];
1735
- function object2(value) {
1736
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
1737
- return value;
1738
- }
1739
- function identifier(layer) {
1740
- if (typeof layer.id !== "string" || !layer.id.length) throw new Error();
1741
- return layer.id;
1742
- }
1743
- function finalizeNativeHostedProvenance(input, lowered, changes) {
1744
- try {
1745
- const result = JSON.parse(serializeCanonicalJson2(lowered));
1746
- const originalIndexes = /* @__PURE__ */ new Map();
1747
- const finalIndexes = /* @__PURE__ */ new Map();
1748
- const starts = /* @__PURE__ */ new Map();
1749
- const transformed = /* @__PURE__ */ new Map();
1750
- let previous = -1;
1751
- for (const change of changes) {
1752
- if (!Number.isSafeInteger(change.inputLayer) || change.inputLayer <= previous || change.inputLayer >= input.layers.length || !Number.isSafeInteger(change.outputStart) || !Number.isSafeInteger(change.outputCount) || change.outputCount < 1 || change.outputCount > 32 || !Array.isArray(change.properties) || !["line-cap", "line-dasharray", "line-cap,line-dasharray"].includes(
1753
- change.properties.join(",")
1754
- ))
1755
- throw new Error();
1756
- previous = change.inputLayer;
1757
- transformed.set(change.inputLayer, change);
1758
- }
1759
- for (const [index, layer] of result.layers.entries()) {
1760
- const id = identifier(layer);
1761
- if (finalIndexes.has(id)) throw new Error();
1762
- finalIndexes.set(id, index);
1763
- }
1764
- let offset = 0;
1765
- for (const [index, layer] of input.layers.entries()) {
1766
- const id = identifier(layer);
1767
- if (originalIndexes.has(id)) throw new Error();
1768
- originalIndexes.set(id, index);
1769
- starts.set(id, offset);
1770
- const change = transformed.get(index);
1771
- if (change && (change.outputStart !== offset || layer.type !== "line")) throw new Error();
1772
- const count = change?.outputCount ?? 1;
1773
- if (offset + count > result.layers.length) throw new Error();
1774
- for (let branch = 0; branch < count; branch++) {
1775
- const candidate = result.layers[offset + branch];
1776
- if (!change && identifier(candidate) !== id) throw new Error();
1777
- if (candidate.type !== layer.type || candidate.source !== layer.source || candidate["source-layer"] !== layer["source-layer"])
1778
- throw new Error();
1779
- }
1780
- offset += count;
1781
- }
1782
- if (offset !== result.layers.length) throw new Error();
1783
- const metadata = result.metadata === void 0 ? void 0 : object2(result.metadata);
1784
- const originalMetadata = input.metadata === void 0 ? void 0 : object2(input.metadata);
1785
- if (originalMetadata?.["tileflow:overlay-placement-manifest"] !== void 0) {
1786
- if (!metadata) throw new Error();
1787
- const overlay = object2(originalMetadata["tileflow:overlay-placement-manifest"]);
1788
- const anchors = object2(overlay.anchors);
1789
- if (overlay.schemaVersion !== 1 || Object.keys(anchors).length !== overlayKeys.length || overlayKeys.some((key2) => !Object.hasOwn(anchors, key2)))
1790
- throw new Error();
1791
- const updated = {};
1792
- for (const key2 of overlayKeys) {
1793
- const anchor = anchors[key2];
1794
- if (anchor === null) {
1795
- updated[key2] = null;
1796
- continue;
1797
- }
1798
- if (typeof anchor !== "string" || !starts.has(anchor)) throw new Error();
1799
- updated[key2] = identifier(result.layers[starts.get(anchor)]);
1800
- }
1801
- metadata["tileflow:overlay-placement-manifest"] = { ...overlay, anchors: updated };
1802
- }
1803
- if (originalMetadata?.["tileflow:interaction-manifest"] !== void 0) {
1804
- if (!metadata) throw new Error();
1805
- const manifest = object2(
1806
- JSON.parse(serializeCanonicalJson2(originalMetadata["tileflow:interaction-manifest"]))
1807
- );
1808
- if (manifest.version !== 2) throw new Error();
1809
- const domains = object2(manifest.domains);
1810
- if (domains.poi !== void 0) {
1811
- const poi = object2(domains.poi);
1812
- if (!Array.isArray(poi.layers) || poi.layers.length > 256) throw new Error();
1813
- const seen = /* @__PURE__ */ new Set();
1814
- poi.layers = poi.layers.map((value) => {
1815
- const entry = object2(value);
1816
- if (typeof entry.layerId !== "string" || seen.has(entry.layerId)) throw new Error();
1817
- const index = originalIndexes.get(entry.layerId);
1818
- if (index === void 0 || index !== entry.priority || transformed.has(index) || !finalIndexes.has(entry.layerId))
1819
- throw new Error();
1820
- const original = input.layers[index];
1821
- if (original.source !== entry.source || original["source-layer"] !== entry.sourceLayer)
1822
- throw new Error();
1823
- seen.add(entry.layerId);
1824
- return { ...entry, priority: finalIndexes.get(entry.layerId) };
1825
- });
1826
- }
1827
- metadata["tileflow:interaction-manifest"] = manifest;
1828
- }
1829
- return result;
1830
- } catch {
1831
- throw new TileflowNativeCompatibilityError3([
1832
- createTileflowNativeDiagnostic2("NATIVE_UNSUPPORTED_STYLE", "/metadata")
1833
- ]);
1834
- }
1835
- }
1836
-
1837
- // src/hosted-native-artifacts.ts
1838
- var digest = (value) => createHash2("sha256").update(serializeCanonicalJson3(value)).digest("hex");
1839
- var invalidSource = () => new TileflowNativeCompatibilityError4([
1840
- createTileflowNativeDiagnostic3("NATIVE_UNSUPPORTED_SOURCE", "/sources")
2035
+ var digest2 = (value) => createHash3("sha256").update(serializeCanonicalJson2(value)).digest("hex");
2036
+ var invalidSource = () => new TileflowNativeCompatibilityError3([
2037
+ createTileflowNativeDiagnostic2("NATIVE_UNSUPPORTED_SOURCE", "/sources")
1841
2038
  ]);
1842
2039
  async function prepareTileflowHostedNativeDeployment(input) {
1843
- const webStyles = JSON.parse(serializeCanonicalJson3(input.styles));
2040
+ const webStyles = JSON.parse(serializeCanonicalJson2(input.styles));
1844
2041
  const validationStyles = JSON.parse(
1845
- serializeCanonicalJson3(webStyles)
2042
+ serializeCanonicalJson2(webStyles)
1846
2043
  );
1847
2044
  for (const style of Object.values(validationStyles)) {
1848
2045
  for (const [sourceId, binding] of Object.entries(input.teamSources)) {
@@ -1853,14 +2050,6 @@ async function prepareTileflowHostedNativeDeployment(input) {
1853
2050
  }
1854
2051
  }
1855
2052
  const lowered = lowerTileflowNativeCompiledStyles({ [input.mapId]: validationStyles });
1856
- for (const transformation of lowered.transformations) {
1857
- const name = transformation.theme;
1858
- lowered.styles[input.mapId][name] = finalizeNativeHostedProvenance(
1859
- validationStyles[name],
1860
- lowered.styles[input.mapId][name],
1861
- transformation.layers
1862
- );
1863
- }
1864
2053
  const projected = prepareTileflowNativeStyles(lowered.styles, input.assets)[input.mapId];
1865
2054
  for (const [name, style] of Object.entries(projected)) {
1866
2055
  for (const sourceId of Object.keys(input.teamSources)) {
@@ -1868,11 +2057,11 @@ async function prepareTileflowHostedNativeDeployment(input) {
1868
2057
  if (!source) throw invalidSource();
1869
2058
  source.url = `tileflow://hosted-sources/${sourceId}`;
1870
2059
  }
1871
- if (serializeCanonicalJson3(style.sources) !== serializeCanonicalJson3(webStyles[name].sources))
2060
+ if (serializeCanonicalJson2(style.sources) !== serializeCanonicalJson2(webStyles[name].sources))
1872
2061
  throw invalidSource();
1873
2062
  }
1874
2063
  const nativeBuild = JSON.parse(
1875
- serializeCanonicalJson3(input.buildManifest)
2064
+ serializeCanonicalJson2(input.buildManifest)
1876
2065
  );
1877
2066
  const mapBuild = nativeBuild.maps[input.mapId];
1878
2067
  if (!mapBuild) throw invalidSource();
@@ -1881,15 +2070,15 @@ async function prepareTileflowHostedNativeDeployment(input) {
1881
2070
  if (!theme) throw invalidSource();
1882
2071
  mapBuild.themes[name] = {
1883
2072
  ...theme,
1884
- styleSha256: digest(style),
2073
+ styleSha256: digest2(style),
1885
2074
  dataRequirements: inferTileflowDataRequirements(style),
1886
2075
  sourceRequirements: inferTileflowSourceRequirements(style)
1887
2076
  };
1888
2077
  }
1889
2078
  const transformations = lowered.transformations.map((item) => ({
1890
2079
  ...item,
1891
- inputStyleSha256: digest(webStyles[item.theme]),
1892
- loweredStyleSha256: digest({
2080
+ inputStyleSha256: digest2(webStyles[item.theme]),
2081
+ loweredStyleSha256: digest2({
1893
2082
  ...lowered.styles[input.mapId][item.theme],
1894
2083
  sources: webStyles[item.theme].sources
1895
2084
  })
@@ -1904,7 +2093,7 @@ async function prepareTileflowHostedNativeDeployment(input) {
1904
2093
  web: { buildManifest: input.buildManifest, styles: webStyles },
1905
2094
  native: {
1906
2095
  buildManifest: nativeBuild,
1907
- buildRecord: createTileflowNativeBuildRecord(digest(nativeBuild), transformations),
2096
+ buildRecord: createTileflowNativeBuildRecord(digest2(nativeBuild), transformations),
1908
2097
  styles: projected
1909
2098
  }
1910
2099
  }
@@ -1991,12 +2180,16 @@ function assertValidTileflowStyles(project, styles) {
1991
2180
  async function createTileflowArtifactPlan(prepared, options = {}) {
1992
2181
  const renderer = resolveTileflowRenderer(options.renderer);
1993
2182
  if (renderer === "native" && options.inspection) {
1994
- throw new TileflowNativeCompatibilityError5([
1995
- createTileflowNativeDiagnostic4("NATIVE_RENDERER_UNSUPPORTED", "/inspection")
2183
+ throw new TileflowNativeCompatibilityError4([
2184
+ createTileflowNativeDiagnostic3("NATIVE_RENDERER_UNSUPPORTED", "/inspection")
1996
2185
  ]);
1997
2186
  }
2187
+ assertNativeDevelopmentOrigin(options);
2188
+ const nativeUrls = {
2189
+ developmentOrigin: options.developmentOrigin
2190
+ };
1998
2191
  if (renderer === "native") {
1999
- assertTileflowNativeCompiledStyles(prepared.project, {});
2192
+ assertTileflowNativeCompiledStyles(prepared.project, {}, nativeUrls);
2000
2193
  } else if (options.target === "production" && hasLocalTilesetSources(prepared.project)) {
2001
2194
  throw new TileflowLocalTilesetProductionError();
2002
2195
  }
@@ -2009,9 +2202,10 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2009
2202
  apiBaseUrl: options.apiBaseUrl,
2010
2203
  mapAssets: prepared.mapAssets
2011
2204
  });
2012
- const nativeLowering = renderer === "native" ? lowerTileflowNativeCompiledStyles(compiledStyles) : void 0;
2205
+ const nativeLowering = renderer === "native" ? lowerTileflowNativeCompiledStyles(compiledStyles, nativeUrls) : void 0;
2013
2206
  const rendererStyles = nativeLowering?.styles ?? compiledStyles;
2014
- if (renderer === "native") assertTileflowNativeCompiledStyles(prepared.project, rendererStyles);
2207
+ if (renderer === "native")
2208
+ assertTileflowNativeCompiledStyles(prepared.project, rendererStyles, nativeUrls);
2015
2209
  const localTilesets = await prepareTileflowLocalTilesets(prepared.project, rendererStyles, {
2016
2210
  assetBaseUrl: resolveRendererAssetBaseUrl(options),
2017
2211
  baseDirectory: prepared.baseDirectory,
@@ -2025,14 +2219,17 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2025
2219
  target: "local"
2026
2220
  }).catch((error) => {
2027
2221
  if (renderer === "native" && error instanceof TileflowFontCompilationError) {
2028
- throw new TileflowNativeCompatibilityError5([
2029
- createTileflowNativeDiagnostic4("NATIVE_FONT_UNAVAILABLE", "/fonts")
2222
+ throw new TileflowNativeCompatibilityError4([
2223
+ createTileflowNativeDiagnostic3("NATIVE_FONT_UNAVAILABLE", "/fonts")
2030
2224
  ]);
2031
2225
  }
2032
2226
  throw error;
2033
2227
  });
2034
2228
  const assets = [...prepared.assets, ...preparedFonts.assets];
2035
- const styles = renderer === "native" ? prepareTileflowNativeStyles(preparedFonts.styles, assets) : preparedFonts.styles;
2229
+ const lineBackgroundGlyphs = renderer === "native" || options.target === "production" ? { providers: {}, styles: preparedFonts.styles } : prepareTileflowLineBackgroundGlyphs(preparedFonts.styles, {
2230
+ assetBaseUrl: resolveRendererAssetBaseUrl(options)
2231
+ });
2232
+ const styles = renderer === "native" ? prepareTileflowNativeStyles(preparedFonts.styles, assets, nativeUrls) : lineBackgroundGlyphs.styles;
2036
2233
  const provenance = await createTileflowBuildProvenance(prepared.cwd);
2037
2234
  const buildManifest = await createTileflowMapBuildManifest(
2038
2235
  Object.fromEntries(
@@ -2084,7 +2281,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2084
2281
  buildManifest,
2085
2282
  ...renderer === "native" ? {
2086
2283
  nativeBuild: createTileflowNativeBuildRecord2(
2087
- hashBytes(serializeCanonicalJson4(buildManifest)),
2284
+ hashBytes(serializeCanonicalJson3(buildManifest)),
2088
2285
  nativeLowering.transformations
2089
2286
  )
2090
2287
  } : {},
@@ -2092,6 +2289,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2092
2289
  manifest: stableManifest,
2093
2290
  project: prepared.project,
2094
2291
  ...localTilesets.files.length > 0 ? { localTilesets: localTilesets.files } : {},
2292
+ ...Object.keys(lineBackgroundGlyphs.providers).length > 0 ? { lineBackgroundGlyphs: lineBackgroundGlyphs.providers } : {},
2095
2293
  ...inspected ? { styleInspections: inspected.inspections } : {},
2096
2294
  styles,
2097
2295
  watchPaths: uniqueStrings([...inputs.files, ...inputs.directories])
@@ -2102,7 +2300,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2102
2300
  const generationArtifacts = { ...partial, manifest };
2103
2301
  return {
2104
2302
  ...generationArtifacts,
2105
- files: createGenerationArtifactFiles(generationArtifacts, generation),
2303
+ files: createGenerationArtifactFiles(generationArtifacts, generation, nativeUrls),
2106
2304
  inputs,
2107
2305
  project: prepared.project,
2108
2306
  schemaVersion: tileflowArtifactPlanSchemaVersion,
@@ -2115,6 +2313,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2115
2313
  }
2116
2314
  async function createTileflowBuildArtifacts(options = {}) {
2117
2315
  resolveTileflowRenderer(options.renderer);
2316
+ assertNativeDevelopmentOrigin(options);
2118
2317
  const loaded = await loadValidTileflowConfigWithInputs(
2119
2318
  options.config ?? defaultTileflowConfigPath,
2120
2319
  {
@@ -2141,7 +2340,7 @@ function getStableTileflowArtifactFiles(artifacts) {
2141
2340
  {
2142
2341
  contentType: "application/json; charset=utf-8",
2143
2342
  fileName: tileflowMapBuildManifestFileName,
2144
- source: `${serializeCanonicalJson4(artifacts.buildManifest)}
2343
+ source: `${serializeCanonicalJson3(artifacts.buildManifest)}
2145
2344
  `
2146
2345
  },
2147
2346
  {
@@ -2163,7 +2362,7 @@ function getStableTileflowArtifactFiles(artifacts) {
2163
2362
  {
2164
2363
  contentType: "application/json; charset=utf-8",
2165
2364
  fileName: tileflowNativeBuildRecordFileName,
2166
- source: `${serializeCanonicalJson4(artifacts.nativeBuild)}
2365
+ source: `${serializeCanonicalJson3(artifacts.nativeBuild)}
2167
2366
  `
2168
2367
  }
2169
2368
  ] : []
@@ -2216,7 +2415,7 @@ function createGenerationManifest(manifest, generation, assets) {
2216
2415
  )
2217
2416
  };
2218
2417
  }
2219
- function createGenerationArtifactFiles(artifacts, generation) {
2418
+ function createGenerationArtifactFiles(artifacts, generation, nativeUrls) {
2220
2419
  const prefix = `generations/${generation}`;
2221
2420
  const stableFiles = getStableTileflowArtifactFiles(artifacts);
2222
2421
  const immutableStyles = Object.entries(artifacts.styles).flatMap(
@@ -2236,7 +2435,7 @@ function createGenerationArtifactFiles(artifacts, generation) {
2236
2435
  (source) => retargetLocalFontAssetUrl(source, artifacts.assets, generation)
2237
2436
  );
2238
2437
  if (artifacts.nativeBuild)
2239
- assertTileflowNativeGeneratedStyle(generationStyle, mapName, themeName);
2438
+ assertTileflowNativeGeneratedStyle(generationStyle, mapName, themeName, nativeUrls);
2240
2439
  return {
2241
2440
  contentType: "application/json; charset=utf-8",
2242
2441
  fileName: `${prefix}/styles/${mapName}/${themeName}.json`,
@@ -2292,12 +2491,12 @@ function getMapBuildAssets(mapName, assets, fontAssets) {
2292
2491
  );
2293
2492
  }
2294
2493
  function hashBytes(source) {
2295
- return createHash3("sha256").update(typeof source === "string" ? Buffer.from(source, "utf8") : Buffer.from(source)).digest("hex");
2494
+ return createHash4("sha256").update(typeof source === "string" ? Buffer.from(source, "utf8") : Buffer.from(source)).digest("hex");
2296
2495
  }
2297
2496
  async function createTileflowBuildProvenance(cwd) {
2298
- const projectDirectory = resolve3(cwd);
2497
+ const projectDirectory = resolve4(cwd);
2299
2498
  const projectRequire = createRequire(
2300
- resolve3(projectDirectory, "__tileflow_build_provenance__.cjs")
2499
+ resolve4(projectDirectory, "__tileflow_build_provenance__.cjs")
2301
2500
  );
2302
2501
  const toolRequire = createRequire(import.meta.url);
2303
2502
  const packages = {};
@@ -2331,7 +2530,7 @@ async function readPackageVersion(expectedName, path) {
2331
2530
  if (!path) throw new Error(`Unable to resolve build package provenance for ${expectedName}.`);
2332
2531
  let parsed;
2333
2532
  try {
2334
- parsed = JSON.parse(await readFile(path, "utf8"));
2533
+ parsed = JSON.parse(await readFile2(path, "utf8"));
2335
2534
  } catch {
2336
2535
  throw new Error(`Unable to read build package provenance for ${expectedName}.`);
2337
2536
  }
@@ -2354,7 +2553,7 @@ async function findNearestLockfile(cwd) {
2354
2553
  try {
2355
2554
  return {
2356
2555
  format: candidate.format,
2357
- source: await readFile(resolve3(directory, candidate.fileName))
2556
+ source: await readFile2(resolve4(directory, candidate.fileName))
2358
2557
  };
2359
2558
  } catch (error) {
2360
2559
  if (!hasErrorCode2(error, "ENOENT")) throw error;
@@ -2430,7 +2629,7 @@ async function writeTileflowArtifactPlan(artifacts, options) {
2430
2629
  const outDir = artifacts.nativeBuild ? `${options.outDir.replace(/[\\/]$/u, "")}/native` : options.outDir;
2431
2630
  const output = await prepareTileflowOutputDirectory(cwd, outDir);
2432
2631
  const files = getTileflowArtifactFiles(artifacts);
2433
- await assertTileflowSelfHostedManifestTarget(resolve3(output.outDir, "manifest.json"), options);
2632
+ await assertTileflowSelfHostedManifestTarget(resolve4(output.outDir, "manifest.json"), options);
2434
2633
  await commitTileflowArtifactFiles(output, files);
2435
2634
  }
2436
2635
  function assertNoLocalTilesetsForProduction(artifacts) {
@@ -2443,7 +2642,7 @@ async function assertTileflowSelfHostedManifestTarget(manifestPath, options = {}
2443
2642
  if (options.overwriteHostedManifest) return;
2444
2643
  let source;
2445
2644
  try {
2446
- source = await readFile(resolve3(manifestPath), "utf8");
2645
+ source = await readFile2(resolve4(manifestPath), "utf8");
2447
2646
  } catch (error) {
2448
2647
  if (hasErrorCode2(error, "ENOENT")) return;
2449
2648
  throw error;
@@ -2451,7 +2650,7 @@ async function assertTileflowSelfHostedManifestTarget(manifestPath, options = {}
2451
2650
  try {
2452
2651
  const manifest = parseTileflowRuntimeManifest(JSON.parse(source));
2453
2652
  if (isHostedRuntimeManifest(manifest)) {
2454
- throw new TileflowHostedManifestOverwriteError(resolve3(manifestPath));
2653
+ throw new TileflowHostedManifestOverwriteError(resolve4(manifestPath));
2455
2654
  }
2456
2655
  } catch (error) {
2457
2656
  if (error instanceof TileflowHostedManifestOverwriteError) throw error;
@@ -2499,15 +2698,15 @@ async function commitTileflowArtifactFiles(output, files) {
2499
2698
  ...staleNames,
2500
2699
  tileflowArtifactInventoryFileName
2501
2700
  ]);
2502
- const stageDir = await mkdtemp(resolve3(outDir, ".tileflow-stage-"));
2503
- const newDir = resolve3(stageDir, "new");
2504
- const backupDir = resolve3(stageDir, "backup");
2701
+ const stageDir = await mkdtemp(resolve4(outDir, ".tileflow-stage-"));
2702
+ const newDir = resolve4(stageDir, "new");
2703
+ const backupDir = resolve4(stageDir, "backup");
2505
2704
  const backedUp = /* @__PURE__ */ new Set();
2506
2705
  const installed = /* @__PURE__ */ new Set();
2507
2706
  try {
2508
2707
  for (const file of stagedFiles) {
2509
2708
  const stagePath = managedPath(newDir, file.fileName);
2510
- await mkdir2(dirname2(stagePath), { recursive: true });
2709
+ await mkdir3(dirname2(stagePath), { recursive: true });
2511
2710
  await writeFileDurably(stagePath, file.source);
2512
2711
  }
2513
2712
  for (const name of affectedNames) {
@@ -2515,7 +2714,7 @@ async function commitTileflowArtifactFiles(output, files) {
2515
2714
  const targetPath = managedPath(outDir, name);
2516
2715
  if (!await isFile(targetPath)) continue;
2517
2716
  const backupPath = managedPath(backupDir, name);
2518
- await mkdir2(dirname2(backupPath), { recursive: true });
2717
+ await mkdir3(dirname2(backupPath), { recursive: true });
2519
2718
  await copyFile2(targetPath, backupPath);
2520
2719
  backedUp.add(name);
2521
2720
  }
@@ -2529,8 +2728,8 @@ async function commitTileflowArtifactFiles(output, files) {
2529
2728
  )) {
2530
2729
  const sourcePath = managedPath(newDir, name);
2531
2730
  const targetPath = managedPath(outDir, name);
2532
- await mkdir2(dirname2(targetPath), { recursive: true });
2533
- await rename(sourcePath, targetPath);
2731
+ await mkdir3(dirname2(targetPath), { recursive: true });
2732
+ await rename2(sourcePath, targetPath);
2534
2733
  installed.add(name);
2535
2734
  }
2536
2735
  for (const name of staleNames) {
@@ -2538,13 +2737,13 @@ async function commitTileflowArtifactFiles(output, files) {
2538
2737
  }
2539
2738
  const stagedInventoryPath = managedPath(newDir, tileflowArtifactInventoryFileName);
2540
2739
  const inventoryPath = managedPath(outDir, tileflowArtifactInventoryFileName);
2541
- await rename(stagedInventoryPath, inventoryPath);
2740
+ await rename2(stagedInventoryPath, inventoryPath);
2542
2741
  installed.add(tileflowArtifactInventoryFileName);
2543
2742
  } catch (error) {
2544
2743
  await rollbackManagedFiles(outDir, backupDir, affectedNames, backedUp, installed);
2545
2744
  throw error;
2546
2745
  } finally {
2547
- await rm2(stageDir, { force: true, recursive: true });
2746
+ await rm3(stageDir, { force: true, recursive: true });
2548
2747
  }
2549
2748
  }
2550
2749
  function getArtifactGeneration(files) {
@@ -2576,7 +2775,7 @@ async function rollbackManagedFiles(outDir, backupDir, affectedNames, backedUp,
2576
2775
  await removeManagedFile(targetPath);
2577
2776
  }
2578
2777
  if (backedUp.has(name)) {
2579
- await mkdir2(dirname2(targetPath), { recursive: true });
2778
+ await mkdir3(dirname2(targetPath), { recursive: true });
2580
2779
  await copyFile2(managedPath(backupDir, name), targetPath);
2581
2780
  }
2582
2781
  } catch (error) {
@@ -2591,7 +2790,7 @@ async function readTileflowArtifactInventory(outDir) {
2591
2790
  const inventoryPath = managedPath(outDir, tileflowArtifactInventoryFileName);
2592
2791
  let source;
2593
2792
  try {
2594
- source = await readFile(inventoryPath, "utf8");
2793
+ source = await readFile2(inventoryPath, "utf8");
2595
2794
  } catch (error) {
2596
2795
  if (hasErrorCode2(error, "ENOENT")) return void 0;
2597
2796
  throw error;
@@ -2625,7 +2824,7 @@ async function readTileflowArtifactInventory(outDir) {
2625
2824
  }
2626
2825
  async function assertManagedTargetIsSafe(outDir, fileName) {
2627
2826
  assertSafeManagedFileName(fileName);
2628
- const rootStats = await lstat2(outDir);
2827
+ const rootStats = await lstat3(outDir);
2629
2828
  if (rootStats.isSymbolicLink()) {
2630
2829
  throw new Error(`Tileflow refuses to write through a symbolic link: ${outDir}`);
2631
2830
  }
@@ -2635,9 +2834,9 @@ async function assertManagedTargetIsSafe(outDir, fileName) {
2635
2834
  const segments = fileName.split("/");
2636
2835
  let current = outDir;
2637
2836
  for (let index = 0; index < segments.length; index += 1) {
2638
- current = resolve3(current, segments[index]);
2837
+ current = resolve4(current, segments[index]);
2639
2838
  try {
2640
- const stats = await lstat2(current);
2839
+ const stats = await lstat3(current);
2641
2840
  if (stats.isSymbolicLink()) {
2642
2841
  throw new Error(`Tileflow refuses to write through a symbolic link: ${fileName}`);
2643
2842
  }
@@ -2654,12 +2853,12 @@ async function assertManagedTargetIsSafe(outDir, fileName) {
2654
2853
  }
2655
2854
  }
2656
2855
  async function prepareTileflowOutputDirectory(cwd, requestedOutDir) {
2657
- const logicalRoot = resolve3(cwd);
2658
- const logicalOutDir = resolve3(logicalRoot, requestedOutDir);
2856
+ const logicalRoot = resolve4(cwd);
2857
+ const logicalOutDir = resolve4(logicalRoot, requestedOutDir);
2659
2858
  if (!isPathWithin(logicalRoot, logicalOutDir)) {
2660
2859
  throw new Error(`Tileflow artifact output escapes its working directory: ${logicalOutDir}`);
2661
2860
  }
2662
- const rootStats = await lstat2(logicalRoot);
2861
+ const rootStats = await lstat3(logicalRoot);
2663
2862
  if (!rootStats.isDirectory()) {
2664
2863
  throw new Error(`Tileflow artifact working directory is not a directory: ${logicalRoot}`);
2665
2864
  }
@@ -2668,14 +2867,14 @@ async function prepareTileflowOutputDirectory(cwd, requestedOutDir) {
2668
2867
  const segments = relativeOutDir ? relativeOutDir.split(sep2) : [];
2669
2868
  let current = rootDir;
2670
2869
  for (const segment of segments) {
2671
- current = resolve3(current, segment);
2870
+ current = resolve4(current, segment);
2672
2871
  let stats;
2673
2872
  try {
2674
- stats = await lstat2(current);
2873
+ stats = await lstat3(current);
2675
2874
  } catch (error) {
2676
2875
  if (!hasErrorCode2(error, "ENOENT")) throw error;
2677
- await mkdir2(current);
2678
- stats = await lstat2(current);
2876
+ await mkdir3(current);
2877
+ stats = await lstat3(current);
2679
2878
  }
2680
2879
  if (stats.isSymbolicLink()) {
2681
2880
  throw new Error(`Tileflow refuses to write through a symbolic link: ${current}`);
@@ -2693,7 +2892,7 @@ async function assertTileflowOutputDirectoryIsSafe(output) {
2693
2892
  if (!isPathWithin(output.rootDir, output.outDir)) {
2694
2893
  throw new Error(`Tileflow artifact output escapes its working directory: ${output.outDir}`);
2695
2894
  }
2696
- const stats = await lstat2(output.outDir);
2895
+ const stats = await lstat3(output.outDir);
2697
2896
  if (stats.isSymbolicLink()) {
2698
2897
  throw new Error(`Tileflow refuses to write through a symbolic link: ${output.outDir}`);
2699
2898
  }
@@ -2722,7 +2921,7 @@ function assertTileflowArtifactFileName(fileName) {
2722
2921
  }
2723
2922
  function managedPath(root, fileName) {
2724
2923
  assertSafeManagedFileName(fileName);
2725
- const path = resolve3(root, ...fileName.split("/"));
2924
+ const path = resolve4(root, ...fileName.split("/"));
2726
2925
  if (!isPathWithin(root, path)) {
2727
2926
  throw new Error(`Unsafe Tileflow artifact file name: ${fileName}`);
2728
2927
  }
@@ -2739,7 +2938,7 @@ async function writeFileDurably(path, source) {
2739
2938
  }
2740
2939
  async function isFile(path) {
2741
2940
  try {
2742
- return (await lstat2(path)).isFile();
2941
+ return (await lstat3(path)).isFile();
2743
2942
  } catch (error) {
2744
2943
  if (hasErrorCode2(error, "ENOENT")) return false;
2745
2944
  throw error;
@@ -2747,7 +2946,7 @@ async function isFile(path) {
2747
2946
  }
2748
2947
  async function removeManagedFile(path) {
2749
2948
  try {
2750
- const stats = await lstat2(path);
2949
+ const stats = await lstat3(path);
2751
2950
  if (!stats.isFile()) throw new Error(`Refusing to remove non-file artifact target: ${path}`);
2752
2951
  await unlink(path);
2753
2952
  } catch (error) {
@@ -2755,7 +2954,7 @@ async function removeManagedFile(path) {
2755
2954
  }
2756
2955
  }
2757
2956
  function hashArtifactGeneration(files) {
2758
- const hash = createHash3("sha256");
2957
+ const hash = createHash4("sha256");
2759
2958
  for (const file of files) {
2760
2959
  const source = typeof file.source === "string" ? Buffer.from(file.source, "utf8") : Buffer.from(file.source);
2761
2960
  hash.update(`${file.fileName}\0${file.contentType}\0${source.byteLength}\0`, "utf8");
@@ -2763,6 +2962,13 @@ function hashArtifactGeneration(files) {
2763
2962
  }
2764
2963
  return hash.digest("hex");
2765
2964
  }
2965
+ function assertNativeDevelopmentOrigin(options) {
2966
+ if (options.developmentOrigin !== void 0 && (resolveTileflowRenderer(options.renderer) !== "native" || options.target === "production")) {
2967
+ throw new TileflowNativeCompatibilityError4([
2968
+ createTileflowNativeDiagnostic3("NATIVE_RENDERER_UNSUPPORTED", "/developmentOrigin")
2969
+ ]);
2970
+ }
2971
+ }
2766
2972
  function resolveRendererAssetBaseUrl(options) {
2767
2973
  const base = resolveAssetBaseUrl(options);
2768
2974
  return options.renderer === "native" ? nativePublicBase(base) : base;
@@ -2787,12 +2993,12 @@ function hasErrorCode2(error, code) {
2787
2993
  return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
2788
2994
  }
2789
2995
  function canonicalInputPath(path) {
2790
- const resolved = resolve3(path);
2996
+ const resolved = resolve4(path);
2791
2997
  try {
2792
2998
  return realpathSync2.native(resolved);
2793
2999
  } catch {
2794
3000
  try {
2795
- return resolve3(realpathSync2.native(dirname2(resolved)), resolved.split(/[\\/]/).at(-1));
3001
+ return resolve4(realpathSync2.native(dirname2(resolved)), resolved.split(/[\\/]/).at(-1));
2796
3002
  } catch {
2797
3003
  return resolved;
2798
3004
  }
@@ -2800,6 +3006,10 @@ function canonicalInputPath(path) {
2800
3006
  }
2801
3007
 
2802
3008
  export {
3009
+ tileflowLineBackgroundGlyphRoute,
3010
+ usesTileflowLineBackgroundGlyphs,
3011
+ parseTileflowLineBackgroundGlyphPath,
3012
+ createTileflowLineBackgroundGlyphResponder,
2803
3013
  prepareTileflowLocalTilesets,
2804
3014
  tileflowArtifactSessionSchemaVersion,
2805
3015
  createTileflowArtifactDiagnostics,