@tileflow/dev 0.1.0-alpha.28 → 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.
@@ -153,6 +153,12 @@ type TileflowBuildArtifactsOptions = {
153
153
  assetBaseUrl?: string;
154
154
  config?: string;
155
155
  cwd?: string;
156
+ /**
157
+ * Native local preview only: the exact HTTP origin serving these artifacts, such as
158
+ * `http://127.0.0.1:3333`. Native checks accept HTTP resources at this origin only; every other
159
+ * origin still requires HTTPS. It is never inferred, and web or production output rejects it.
160
+ */
161
+ developmentOrigin?: string;
156
162
  /**
157
163
  * Explicit shared Icon Set resolution settings for this build.
158
164
  *
@@ -206,7 +212,7 @@ type TileflowArtifactPlan = TileflowBuildArtifacts & {
206
212
  schemaVersion: typeof tileflowArtifactPlanSchemaVersion;
207
213
  sourceProject: TileflowSourceCatalog;
208
214
  };
209
- type CreateTileflowArtifactPlanOptions = Pick<TileflowBuildArtifactsOptions, 'apiBaseUrl' | 'assetBaseUrl' | 'inspection' | 'renderer' | 'styleBaseUrl' | 'target'> & {
215
+ type CreateTileflowArtifactPlanOptions = Pick<TileflowBuildArtifactsOptions, 'apiBaseUrl' | 'assetBaseUrl' | 'developmentOrigin' | 'inspection' | 'renderer' | 'styleBaseUrl' | 'target'> & {
210
216
  inputFiles?: readonly string[];
211
217
  };
212
218
  type WriteTileflowArtifactPlanOptions = {
package/dist/artifacts.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  usesTileflowLineBackgroundGlyphs,
28
28
  writeTileflowArtifactPlan,
29
29
  writeTileflowBuildArtifacts
30
- } from "./chunk-4HVIEMKM.js";
30
+ } from "./chunk-LXSFLPIU.js";
31
31
  import "./chunk-ONYQNLNA.js";
32
32
  import {
33
33
  getTileflowAssetBasePath,
@@ -47,7 +47,7 @@ import { dirname as dirname2, relative as relative2, resolve as resolve4, sep as
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,10 +62,10 @@ 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
71
  // src/line-background-glyphs.ts
@@ -587,6 +587,114 @@ import {
587
587
  validateTileflowNativePreparedStyle
588
588
  } from "@tileflow/core/native-profile";
589
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
+
590
698
  // src/native-lowering.ts
591
699
  var nativeLoweringLimits = Object.freeze({
592
700
  maximumDecisionDepth: 16,
@@ -613,7 +721,7 @@ var NativeLoweringError = class extends Error {
613
721
  function fail(path, reason = "shape") {
614
722
  throw new NativeLoweringError(path, reason);
615
723
  }
616
- function object(value) {
724
+ function object2(value) {
617
725
  return value !== null && typeof value === "object" && !Array.isArray(value);
618
726
  }
619
727
  function operation(value, name, length) {
@@ -1054,21 +1162,21 @@ function lowerNativeStyleRepresentation(input, normalizeFilter = (filter) => fil
1054
1162
  const originalLayers = input.layers;
1055
1163
  const reserved = /* @__PURE__ */ new Set();
1056
1164
  for (const [index, layer] of originalLayers.entries()) {
1057
- if (!object(layer) || typeof layer.id !== "string" || reserved.has(layer.id))
1165
+ if (!object2(layer) || typeof layer.id !== "string" || reserved.has(layer.id))
1058
1166
  fail(`/layers/${index}/id`);
1059
1167
  reserved.add(layer.id);
1060
1168
  }
1061
1169
  let projection = "none";
1062
1170
  if (input.projection !== void 0) {
1063
- 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))
1064
1172
  fail("/projection");
1065
1173
  projection = input.projection.type === "globe" ? "globe-to-mercator" : "mercator-to-implicit";
1066
1174
  }
1067
1175
  const layers = [];
1068
1176
  const transformations = [];
1069
1177
  for (const [index, layer] of originalLayers.entries()) {
1070
- const source = object(input.sources) && typeof layer.source === "string" ? input.sources[layer.source] : void 0;
1071
- 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");
1072
1180
  if (!lowered) {
1073
1181
  layers.push(layer);
1074
1182
  continue;
@@ -1116,11 +1224,17 @@ function lowerNativeStyleRepresentation(input, normalizeFilter = (filter) => fil
1116
1224
  function documentUrl(map, theme) {
1117
1225
  return `https://artifacts.invalid/native/styles/${map}/${theme}.json`;
1118
1226
  }
1227
+ function urlOptions(map, theme, policy) {
1228
+ return {
1229
+ documentUrl: documentUrl(map, theme),
1230
+ ...policy.developmentOrigin === void 0 ? {} : { developmentOrigin: policy.developmentOrigin }
1231
+ };
1232
+ }
1119
1233
  function withContext(issue, map, theme) {
1120
1234
  const prefix = `/maps/${map}/themes/${theme}/style`;
1121
1235
  return { ...issue, path: prefix.length + issue.path.length <= 300 ? prefix + issue.path : prefix };
1122
1236
  }
1123
- function lowerTileflowNativeCompiledStyles(input) {
1237
+ function lowerTileflowNativeCompiledStyles(input, policy = {}) {
1124
1238
  const styles = {};
1125
1239
  const transformations = [];
1126
1240
  for (const map of Object.keys(input).sort()) {
@@ -1128,7 +1242,7 @@ function lowerTileflowNativeCompiledStyles(input) {
1128
1242
  for (const theme of Object.keys(input[map]).sort()) {
1129
1243
  const original = input[map][theme];
1130
1244
  try {
1131
- const options = { documentUrl: documentUrl(map, theme), deferFontClosure: true };
1245
+ const options = { ...urlOptions(map, theme, policy), deferFontClosure: true };
1132
1246
  const pending = validateTileflowNativeStyle(original, options);
1133
1247
  const blockers = pending.filter(
1134
1248
  (issue) => issue.code !== "NATIVE_UNSUPPORTED_STYLE" || !(issue.path === "/projection" || /^\/layers\/\d+\/(?:layout\/line-cap|paint\/line-dasharray)(?:\/|$)/u.test(issue.path))
@@ -1156,17 +1270,34 @@ function lowerTileflowNativeCompiledStyles(input) {
1156
1270
  original,
1157
1271
  (filter) => convertFilter(structuredClone(filter))
1158
1272
  );
1159
- 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);
1160
1291
  if (issues.length)
1161
1292
  throw new TileflowNativeCompatibilityError(
1162
1293
  issues.map((issue) => withContext(issue, map, theme))
1163
1294
  );
1164
- styles[map][theme] = lowered.style;
1295
+ styles[map][theme] = style;
1165
1296
  transformations.push({
1166
1297
  map,
1167
1298
  theme,
1168
1299
  inputStyleSha256: createHash2("sha256").update(serializeCanonicalJson(original)).digest("hex"),
1169
- loweredStyleSha256: createHash2("sha256").update(serializeCanonicalJson(lowered.style)).digest("hex"),
1300
+ loweredStyleSha256: createHash2("sha256").update(serializeCanonicalJson(style)).digest("hex"),
1170
1301
  inputLayers: lowered.inputLayers,
1171
1302
  outputLayers: lowered.outputLayers,
1172
1303
  projection: lowered.projection,
@@ -1190,13 +1321,13 @@ function lowerTileflowNativeCompiledStyles(input) {
1190
1321
  }
1191
1322
  return { styles, transformations };
1192
1323
  }
1193
- function assertTileflowNativeCompiledStyles(project, styles) {
1324
+ function assertTileflowNativeCompiledStyles(project, styles, policy = {}) {
1194
1325
  const issues = [];
1195
1326
  for (const mapName of Object.keys(project.maps).sort()) {
1196
1327
  for (const theme of Object.keys(styles[mapName] ?? {}).sort()) {
1197
1328
  issues.push(
1198
1329
  ...validateTileflowNativePreparedStyle(styles[mapName][theme], {
1199
- documentUrl: documentUrl(mapName, theme),
1330
+ ...urlOptions(mapName, theme, policy),
1200
1331
  deferFontClosure: true
1201
1332
  }).map((issue) => withContext(issue, mapName, theme))
1202
1333
  );
@@ -1204,7 +1335,7 @@ function assertTileflowNativeCompiledStyles(project, styles) {
1204
1335
  }
1205
1336
  if (issues.length) throw new TileflowNativeCompatibilityError(issues);
1206
1337
  }
1207
- function prepareTileflowNativeStyles(input, assets) {
1338
+ function prepareTileflowNativeStyles(input, assets, policy = {}) {
1208
1339
  const issues = [];
1209
1340
  const result = {};
1210
1341
  for (const map of Object.keys(input).sort()) {
@@ -1218,7 +1349,7 @@ function prepareTileflowNativeStyles(input, assets) {
1218
1349
  for (const theme of Object.keys(input[map]).sort()) {
1219
1350
  const original = input[map][theme];
1220
1351
  const preflight = validateTileflowNativePreparedStyle(original, {
1221
- documentUrl: documentUrl(map, theme),
1352
+ ...urlOptions(map, theme, policy),
1222
1353
  deferFontClosure: true
1223
1354
  });
1224
1355
  if (preflight.length) {
@@ -1262,9 +1393,9 @@ function prepareTileflowNativeStyles(input, assets) {
1262
1393
  ...faces.length ? { "font-faces": nativeFaces } : {}
1263
1394
  };
1264
1395
  issues.push(
1265
- ...validateTileflowNativePreparedStyle(style, {
1266
- documentUrl: documentUrl(map, theme)
1267
- }).map((issue) => withContext(issue, map, theme))
1396
+ ...validateTileflowNativePreparedStyle(style, urlOptions(map, theme, policy)).map(
1397
+ (issue) => withContext(issue, map, theme)
1398
+ )
1268
1399
  );
1269
1400
  result[map][theme] = style;
1270
1401
  }
@@ -1282,8 +1413,8 @@ function isNativeFontAsset(asset) {
1282
1413
  const expectedHash = /-([a-f0-9]{64})\.(?:ttf|otf)$/u.exec(asset.fileName)?.[1];
1283
1414
  return expectedHash === createHash2("sha256").update(bytes).digest("hex");
1284
1415
  }
1285
- function assertTileflowNativeGeneratedStyle(style, map, theme) {
1286
- const issues = validateTileflowNativePreparedStyle(style, { documentUrl: documentUrl(map, theme) });
1416
+ function assertTileflowNativeGeneratedStyle(style, map, theme, policy = {}) {
1417
+ const issues = validateTileflowNativePreparedStyle(style, urlOptions(map, theme, policy));
1287
1418
  if (issues.length) {
1288
1419
  throw new TileflowNativeCompatibilityError(
1289
1420
  issues.map((issue) => withContext(issue, map, theme))
@@ -1422,6 +1553,7 @@ var TileflowArtifactSessionImpl = class {
1422
1553
  assetBaseUrl: options.assetBaseUrl,
1423
1554
  config: options.config,
1424
1555
  cwd: this.#cwd,
1556
+ ...options.developmentOrigin === void 0 ? {} : { developmentOrigin: options.developmentOrigin },
1425
1557
  // Trusted shared Icon Set resolution settings, supplied once by the owning command.
1426
1558
  ...options.icons ? { icons: options.icons } : {},
1427
1559
  inspection: options.inspection,
@@ -1889,7 +2021,7 @@ function boundDiagnosticText(value, limit) {
1889
2021
 
1890
2022
  // src/hosted-native-artifacts.ts
1891
2023
  import { createHash as createHash3 } from "crypto";
1892
- import { serializeCanonicalJson as serializeCanonicalJson3 } from "@tileflow/core";
2024
+ import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
1893
2025
  import {
1894
2026
  inferTileflowDataRequirements,
1895
2027
  inferTileflowSourceRequirements,
@@ -1897,135 +2029,17 @@ import {
1897
2029
  } from "@tileflow/core/build";
1898
2030
  import {
1899
2031
  createTileflowNativeBuildRecord,
1900
- TileflowNativeCompatibilityError as TileflowNativeCompatibilityError4,
1901
- createTileflowNativeDiagnostic as createTileflowNativeDiagnostic3
2032
+ TileflowNativeCompatibilityError as TileflowNativeCompatibilityError3,
2033
+ createTileflowNativeDiagnostic as createTileflowNativeDiagnostic2
1902
2034
  } from "@tileflow/core/native-profile";
1903
-
1904
- // src/native-hosted-provenance.ts
1905
- import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
1906
- import {
1907
- createTileflowNativeDiagnostic as createTileflowNativeDiagnostic2,
1908
- TileflowNativeCompatibilityError as TileflowNativeCompatibilityError3
1909
- } from "@tileflow/core/native-profile";
1910
- var overlayKeys = [
1911
- "above-water",
1912
- "below-roads",
1913
- "above-roads",
1914
- "above-buildings",
1915
- "below-labels",
1916
- "above-labels"
1917
- ];
1918
- function object2(value) {
1919
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
1920
- return value;
1921
- }
1922
- function identifier(layer) {
1923
- if (typeof layer.id !== "string" || !layer.id.length) throw new Error();
1924
- return layer.id;
1925
- }
1926
- function finalizeNativeHostedProvenance(input, lowered, changes) {
1927
- try {
1928
- const result = JSON.parse(serializeCanonicalJson2(lowered));
1929
- const originalIndexes = /* @__PURE__ */ new Map();
1930
- const finalIndexes = /* @__PURE__ */ new Map();
1931
- const starts = /* @__PURE__ */ new Map();
1932
- const transformed = /* @__PURE__ */ new Map();
1933
- let previous = -1;
1934
- for (const change of changes) {
1935
- 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(
1936
- change.properties.join(",")
1937
- ))
1938
- throw new Error();
1939
- previous = change.inputLayer;
1940
- transformed.set(change.inputLayer, change);
1941
- }
1942
- for (const [index, layer] of result.layers.entries()) {
1943
- const id = identifier(layer);
1944
- if (finalIndexes.has(id)) throw new Error();
1945
- finalIndexes.set(id, index);
1946
- }
1947
- let offset = 0;
1948
- for (const [index, layer] of input.layers.entries()) {
1949
- const id = identifier(layer);
1950
- if (originalIndexes.has(id)) throw new Error();
1951
- originalIndexes.set(id, index);
1952
- starts.set(id, offset);
1953
- const change = transformed.get(index);
1954
- if (change && (change.outputStart !== offset || layer.type !== "line")) throw new Error();
1955
- const count = change?.outputCount ?? 1;
1956
- if (offset + count > result.layers.length) throw new Error();
1957
- for (let branch = 0; branch < count; branch++) {
1958
- const candidate = result.layers[offset + branch];
1959
- if (!change && identifier(candidate) !== id) throw new Error();
1960
- if (candidate.type !== layer.type || candidate.source !== layer.source || candidate["source-layer"] !== layer["source-layer"])
1961
- throw new Error();
1962
- }
1963
- offset += count;
1964
- }
1965
- if (offset !== result.layers.length) throw new Error();
1966
- const metadata = result.metadata === void 0 ? void 0 : object2(result.metadata);
1967
- const originalMetadata = input.metadata === void 0 ? void 0 : object2(input.metadata);
1968
- if (originalMetadata?.["tileflow:overlay-placement-manifest"] !== void 0) {
1969
- if (!metadata) throw new Error();
1970
- const overlay = object2(originalMetadata["tileflow:overlay-placement-manifest"]);
1971
- const anchors = object2(overlay.anchors);
1972
- if (overlay.schemaVersion !== 1 || Object.keys(anchors).length !== overlayKeys.length || overlayKeys.some((key2) => !Object.hasOwn(anchors, key2)))
1973
- throw new Error();
1974
- const updated = {};
1975
- for (const key2 of overlayKeys) {
1976
- const anchor = anchors[key2];
1977
- if (anchor === null) {
1978
- updated[key2] = null;
1979
- continue;
1980
- }
1981
- if (typeof anchor !== "string" || !starts.has(anchor)) throw new Error();
1982
- updated[key2] = identifier(result.layers[starts.get(anchor)]);
1983
- }
1984
- metadata["tileflow:overlay-placement-manifest"] = { ...overlay, anchors: updated };
1985
- }
1986
- if (originalMetadata?.["tileflow:interaction-manifest"] !== void 0) {
1987
- if (!metadata) throw new Error();
1988
- const manifest = object2(
1989
- JSON.parse(serializeCanonicalJson2(originalMetadata["tileflow:interaction-manifest"]))
1990
- );
1991
- if (manifest.version !== 2) throw new Error();
1992
- const domains = object2(manifest.domains);
1993
- if (domains.poi !== void 0) {
1994
- const poi = object2(domains.poi);
1995
- if (!Array.isArray(poi.layers) || poi.layers.length > 256) throw new Error();
1996
- const seen = /* @__PURE__ */ new Set();
1997
- poi.layers = poi.layers.map((value) => {
1998
- const entry = object2(value);
1999
- if (typeof entry.layerId !== "string" || seen.has(entry.layerId)) throw new Error();
2000
- const index = originalIndexes.get(entry.layerId);
2001
- if (index === void 0 || index !== entry.priority || transformed.has(index) || !finalIndexes.has(entry.layerId))
2002
- throw new Error();
2003
- const original = input.layers[index];
2004
- if (original.source !== entry.source || original["source-layer"] !== entry.sourceLayer)
2005
- throw new Error();
2006
- seen.add(entry.layerId);
2007
- return { ...entry, priority: finalIndexes.get(entry.layerId) };
2008
- });
2009
- }
2010
- metadata["tileflow:interaction-manifest"] = manifest;
2011
- }
2012
- return result;
2013
- } catch {
2014
- throw new TileflowNativeCompatibilityError3([
2015
- createTileflowNativeDiagnostic2("NATIVE_UNSUPPORTED_STYLE", "/metadata")
2016
- ]);
2017
- }
2018
- }
2019
-
2020
- // src/hosted-native-artifacts.ts
2021
- var digest2 = (value) => createHash3("sha256").update(serializeCanonicalJson3(value)).digest("hex");
2022
- var invalidSource = () => new TileflowNativeCompatibilityError4([
2023
- 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")
2024
2038
  ]);
2025
2039
  async function prepareTileflowHostedNativeDeployment(input) {
2026
- const webStyles = JSON.parse(serializeCanonicalJson3(input.styles));
2040
+ const webStyles = JSON.parse(serializeCanonicalJson2(input.styles));
2027
2041
  const validationStyles = JSON.parse(
2028
- serializeCanonicalJson3(webStyles)
2042
+ serializeCanonicalJson2(webStyles)
2029
2043
  );
2030
2044
  for (const style of Object.values(validationStyles)) {
2031
2045
  for (const [sourceId, binding] of Object.entries(input.teamSources)) {
@@ -2036,14 +2050,6 @@ async function prepareTileflowHostedNativeDeployment(input) {
2036
2050
  }
2037
2051
  }
2038
2052
  const lowered = lowerTileflowNativeCompiledStyles({ [input.mapId]: validationStyles });
2039
- for (const transformation of lowered.transformations) {
2040
- const name = transformation.theme;
2041
- lowered.styles[input.mapId][name] = finalizeNativeHostedProvenance(
2042
- validationStyles[name],
2043
- lowered.styles[input.mapId][name],
2044
- transformation.layers
2045
- );
2046
- }
2047
2053
  const projected = prepareTileflowNativeStyles(lowered.styles, input.assets)[input.mapId];
2048
2054
  for (const [name, style] of Object.entries(projected)) {
2049
2055
  for (const sourceId of Object.keys(input.teamSources)) {
@@ -2051,11 +2057,11 @@ async function prepareTileflowHostedNativeDeployment(input) {
2051
2057
  if (!source) throw invalidSource();
2052
2058
  source.url = `tileflow://hosted-sources/${sourceId}`;
2053
2059
  }
2054
- if (serializeCanonicalJson3(style.sources) !== serializeCanonicalJson3(webStyles[name].sources))
2060
+ if (serializeCanonicalJson2(style.sources) !== serializeCanonicalJson2(webStyles[name].sources))
2055
2061
  throw invalidSource();
2056
2062
  }
2057
2063
  const nativeBuild = JSON.parse(
2058
- serializeCanonicalJson3(input.buildManifest)
2064
+ serializeCanonicalJson2(input.buildManifest)
2059
2065
  );
2060
2066
  const mapBuild = nativeBuild.maps[input.mapId];
2061
2067
  if (!mapBuild) throw invalidSource();
@@ -2174,12 +2180,16 @@ function assertValidTileflowStyles(project, styles) {
2174
2180
  async function createTileflowArtifactPlan(prepared, options = {}) {
2175
2181
  const renderer = resolveTileflowRenderer(options.renderer);
2176
2182
  if (renderer === "native" && options.inspection) {
2177
- throw new TileflowNativeCompatibilityError5([
2178
- createTileflowNativeDiagnostic4("NATIVE_RENDERER_UNSUPPORTED", "/inspection")
2183
+ throw new TileflowNativeCompatibilityError4([
2184
+ createTileflowNativeDiagnostic3("NATIVE_RENDERER_UNSUPPORTED", "/inspection")
2179
2185
  ]);
2180
2186
  }
2187
+ assertNativeDevelopmentOrigin(options);
2188
+ const nativeUrls = {
2189
+ developmentOrigin: options.developmentOrigin
2190
+ };
2181
2191
  if (renderer === "native") {
2182
- assertTileflowNativeCompiledStyles(prepared.project, {});
2192
+ assertTileflowNativeCompiledStyles(prepared.project, {}, nativeUrls);
2183
2193
  } else if (options.target === "production" && hasLocalTilesetSources(prepared.project)) {
2184
2194
  throw new TileflowLocalTilesetProductionError();
2185
2195
  }
@@ -2192,9 +2202,10 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2192
2202
  apiBaseUrl: options.apiBaseUrl,
2193
2203
  mapAssets: prepared.mapAssets
2194
2204
  });
2195
- const nativeLowering = renderer === "native" ? lowerTileflowNativeCompiledStyles(compiledStyles) : void 0;
2205
+ const nativeLowering = renderer === "native" ? lowerTileflowNativeCompiledStyles(compiledStyles, nativeUrls) : void 0;
2196
2206
  const rendererStyles = nativeLowering?.styles ?? compiledStyles;
2197
- if (renderer === "native") assertTileflowNativeCompiledStyles(prepared.project, rendererStyles);
2207
+ if (renderer === "native")
2208
+ assertTileflowNativeCompiledStyles(prepared.project, rendererStyles, nativeUrls);
2198
2209
  const localTilesets = await prepareTileflowLocalTilesets(prepared.project, rendererStyles, {
2199
2210
  assetBaseUrl: resolveRendererAssetBaseUrl(options),
2200
2211
  baseDirectory: prepared.baseDirectory,
@@ -2208,8 +2219,8 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2208
2219
  target: "local"
2209
2220
  }).catch((error) => {
2210
2221
  if (renderer === "native" && error instanceof TileflowFontCompilationError) {
2211
- throw new TileflowNativeCompatibilityError5([
2212
- createTileflowNativeDiagnostic4("NATIVE_FONT_UNAVAILABLE", "/fonts")
2222
+ throw new TileflowNativeCompatibilityError4([
2223
+ createTileflowNativeDiagnostic3("NATIVE_FONT_UNAVAILABLE", "/fonts")
2213
2224
  ]);
2214
2225
  }
2215
2226
  throw error;
@@ -2218,7 +2229,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2218
2229
  const lineBackgroundGlyphs = renderer === "native" || options.target === "production" ? { providers: {}, styles: preparedFonts.styles } : prepareTileflowLineBackgroundGlyphs(preparedFonts.styles, {
2219
2230
  assetBaseUrl: resolveRendererAssetBaseUrl(options)
2220
2231
  });
2221
- const styles = renderer === "native" ? prepareTileflowNativeStyles(preparedFonts.styles, assets) : lineBackgroundGlyphs.styles;
2232
+ const styles = renderer === "native" ? prepareTileflowNativeStyles(preparedFonts.styles, assets, nativeUrls) : lineBackgroundGlyphs.styles;
2222
2233
  const provenance = await createTileflowBuildProvenance(prepared.cwd);
2223
2234
  const buildManifest = await createTileflowMapBuildManifest(
2224
2235
  Object.fromEntries(
@@ -2270,7 +2281,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2270
2281
  buildManifest,
2271
2282
  ...renderer === "native" ? {
2272
2283
  nativeBuild: createTileflowNativeBuildRecord2(
2273
- hashBytes(serializeCanonicalJson4(buildManifest)),
2284
+ hashBytes(serializeCanonicalJson3(buildManifest)),
2274
2285
  nativeLowering.transformations
2275
2286
  )
2276
2287
  } : {},
@@ -2289,7 +2300,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2289
2300
  const generationArtifacts = { ...partial, manifest };
2290
2301
  return {
2291
2302
  ...generationArtifacts,
2292
- files: createGenerationArtifactFiles(generationArtifacts, generation),
2303
+ files: createGenerationArtifactFiles(generationArtifacts, generation, nativeUrls),
2293
2304
  inputs,
2294
2305
  project: prepared.project,
2295
2306
  schemaVersion: tileflowArtifactPlanSchemaVersion,
@@ -2302,6 +2313,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
2302
2313
  }
2303
2314
  async function createTileflowBuildArtifacts(options = {}) {
2304
2315
  resolveTileflowRenderer(options.renderer);
2316
+ assertNativeDevelopmentOrigin(options);
2305
2317
  const loaded = await loadValidTileflowConfigWithInputs(
2306
2318
  options.config ?? defaultTileflowConfigPath,
2307
2319
  {
@@ -2328,7 +2340,7 @@ function getStableTileflowArtifactFiles(artifacts) {
2328
2340
  {
2329
2341
  contentType: "application/json; charset=utf-8",
2330
2342
  fileName: tileflowMapBuildManifestFileName,
2331
- source: `${serializeCanonicalJson4(artifacts.buildManifest)}
2343
+ source: `${serializeCanonicalJson3(artifacts.buildManifest)}
2332
2344
  `
2333
2345
  },
2334
2346
  {
@@ -2350,7 +2362,7 @@ function getStableTileflowArtifactFiles(artifacts) {
2350
2362
  {
2351
2363
  contentType: "application/json; charset=utf-8",
2352
2364
  fileName: tileflowNativeBuildRecordFileName,
2353
- source: `${serializeCanonicalJson4(artifacts.nativeBuild)}
2365
+ source: `${serializeCanonicalJson3(artifacts.nativeBuild)}
2354
2366
  `
2355
2367
  }
2356
2368
  ] : []
@@ -2403,7 +2415,7 @@ function createGenerationManifest(manifest, generation, assets) {
2403
2415
  )
2404
2416
  };
2405
2417
  }
2406
- function createGenerationArtifactFiles(artifacts, generation) {
2418
+ function createGenerationArtifactFiles(artifacts, generation, nativeUrls) {
2407
2419
  const prefix = `generations/${generation}`;
2408
2420
  const stableFiles = getStableTileflowArtifactFiles(artifacts);
2409
2421
  const immutableStyles = Object.entries(artifacts.styles).flatMap(
@@ -2423,7 +2435,7 @@ function createGenerationArtifactFiles(artifacts, generation) {
2423
2435
  (source) => retargetLocalFontAssetUrl(source, artifacts.assets, generation)
2424
2436
  );
2425
2437
  if (artifacts.nativeBuild)
2426
- assertTileflowNativeGeneratedStyle(generationStyle, mapName, themeName);
2438
+ assertTileflowNativeGeneratedStyle(generationStyle, mapName, themeName, nativeUrls);
2427
2439
  return {
2428
2440
  contentType: "application/json; charset=utf-8",
2429
2441
  fileName: `${prefix}/styles/${mapName}/${themeName}.json`,
@@ -2950,6 +2962,13 @@ function hashArtifactGeneration(files) {
2950
2962
  }
2951
2963
  return hash.digest("hex");
2952
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
+ }
2953
2972
  function resolveRendererAssetBaseUrl(options) {
2954
2973
  const base = resolveAssetBaseUrl(options);
2955
2974
  return options.renderer === "native" ? nativePublicBase(base) : base;
@@ -4,7 +4,7 @@ import {
4
4
  parseTileflowLineBackgroundGlyphPath,
5
5
  tileflowArtifactSessionSchemaVersion,
6
6
  tileflowLineBackgroundGlyphRoute
7
- } from "./chunk-4HVIEMKM.js";
7
+ } from "./chunk-LXSFLPIU.js";
8
8
  import {
9
9
  normalizeTileflowBasePath
10
10
  } from "./chunk-UTRO4IBQ.js";
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  isTileflowRequestUrl,
32
32
  tileflowComparisonSchemaVersion,
33
33
  writeTileflowNodeResponse
34
- } from "./chunk-YOTMY5XT.js";
34
+ } from "./chunk-QYM2CUZB.js";
35
35
  import {
36
36
  TileflowHostedManifestOverwriteError,
37
37
  TileflowLocalTilesetProductionError,
@@ -61,7 +61,7 @@ import {
61
61
  usesTileflowLineBackgroundGlyphs,
62
62
  writeTileflowArtifactPlan,
63
63
  writeTileflowBuildArtifacts
64
- } from "./chunk-4HVIEMKM.js";
64
+ } from "./chunk-LXSFLPIU.js";
65
65
  import {
66
66
  inspectTileflowPmtiles,
67
67
  inspectTileflowPmtilesForLocalUse
package/dist/server.js CHANGED
@@ -9,11 +9,11 @@ import {
9
9
  isTileflowRequestUrl,
10
10
  tileflowComparisonSchemaVersion,
11
11
  writeTileflowNodeResponse
12
- } from "./chunk-YOTMY5XT.js";
12
+ } from "./chunk-QYM2CUZB.js";
13
13
  import {
14
14
  createTileflowArtifactDiagnostics,
15
15
  tileflowArtifactSessionSchemaVersion
16
- } from "./chunk-4HVIEMKM.js";
16
+ } from "./chunk-LXSFLPIU.js";
17
17
  import "./chunk-ONYQNLNA.js";
18
18
  import {
19
19
  getTileflowAssetBasePath,
@@ -73,6 +73,15 @@ layer ID, the lowering version and deterministic branch order, with collision ch
73
73
  whole input style. The original layer's replacements stay together; surrounding layers are not
74
74
  reordered. Existing sort-key expressions are retained, not simplified or replaced.
75
75
 
76
+ Replacements shift the physical index of every later layer, so lowering rebinds the style's layer
77
+ references from the recorded spans. Each `tileflow:interaction-manifest` POI `priority` becomes its
78
+ layer's final index. An overlay placement anchor naming an expanded layer moves to that layer's first
79
+ replacement, because anchors mark insertion-before boundaries. Metadata that the spans cannot prove,
80
+ such as a POI priority that differs from its compiled layer index, a POI entry whose source does not
81
+ match its layer or an anchor naming a missing layer, fails with `NATIVE_UNSUPPORTED_STYLE` at the
82
+ style's `/metadata` pointer rather than being guessed. Local builds, watched sessions and native
83
+ preview share this step with Hosted publication.
84
+
76
85
  Work is bounded per property by depth 16, 512 decision visits, 64 decision paths, 16 distinct
77
86
  outcomes and 64 dash elements; the product is limited to 32 physical layers and 32 zoom intervals
78
87
  per logical layer. Raw compiler input must fit 160,000 JSON nodes before any lowering. Its expanded
@@ -137,7 +146,8 @@ style SHA-256 values, input/output layer counts, projection normalization, and t
137
146
  output start/count and affected properties of each changed layer. Ordinals refer to the complete
138
147
  style layer arrays, including unchanged layers. These spans make the deterministic physical IDs
139
148
  traceable without duplicating layer definitions in the receipt. The input hash binds shared
140
- compiler output; the lowered hash precedes native font preparation and generation URL retargeting.
149
+ compiler output; the lowered hash includes the rebound layer references and precedes native font
150
+ preparation and generation URL retargeting.
141
151
  The build-manifest hash separately binds the final prepared styles and assets. All styles receive
142
152
  an entry, including styles for which no lowering was needed. Schema v1 build records do not imply
143
153
  this preparation policy and are not parsed as v2.
@@ -152,6 +162,13 @@ URLs remain relative to their owning documents. An explicit absolute or host-rel
152
162
  an inert `.invalid` document base only to check relative URL syntax; it does not publish that base
153
163
  or infer the application's real delivery origin.
154
164
 
165
+ A served local preview can use an absolute HTTP base, such as `http://127.0.0.1:3333`, only when it
166
+ also passes that exact origin as `developmentOrigin`. Native checks then accept HTTP resource URLs,
167
+ such as the sprite and fonts, with that scheme, host and port. Every other origin still requires
168
+ HTTPS, and browser protocols remain rejected. The option is never inferred from a base URL.
169
+ Web preparation, `target: 'production'` and `writeTileflowBuildArtifacts()` reject it with
170
+ `NATIVE_RENDERER_UNSUPPORTED` at `/developmentOrigin`, so written artifacts never depend on it.
171
+
155
172
  Omitting `renderer`, or specifying `renderer: 'web'`, preserves the existing web artifact bytes and
156
173
  output layout. The native record is absent from web plans.
157
174
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/dev",
3
- "version": "0.1.0-alpha.28",
3
+ "version": "0.1.0-alpha.29",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Node development utilities for Tileflow configs and builds.",
6
6
  "type": "module",
@@ -90,7 +90,7 @@
90
90
  "dependencies": {
91
91
  "@mapbox/vector-tile": "3.0.0",
92
92
  "@maplibre/maplibre-gl-style-spec": "24.8.5",
93
- "@tileflow/core": ">=0.1.0-alpha.30 <0.1.0-beta.0",
93
+ "@tileflow/core": ">=0.1.0-alpha.31 <0.1.0-beta.0",
94
94
  "chokidar": "4.0.3",
95
95
  "fflate": "0.8.3",
96
96
  "fontkit": "2.0.4",