tileflow 0.1.0-alpha.7 → 0.1.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,58 +7,59 @@ import { createHash as createHash4, randomBytes as randomBytes2 } from "crypto";
7
7
  import { existsSync, readFileSync, realpathSync } from "fs";
8
8
  import { readFile as readFile7, writeFile as writeFile2 } from "fs/promises";
9
9
  import { hostname } from "os";
10
- import { dirname as dirname11, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve7, sep as sep5 } from "path";
10
+ import { dirname as dirname12, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve8, sep as sep5 } from "path";
11
11
  import { createInterface } from "readline/promises";
12
12
  import pc6 from "picocolors";
13
13
  import { createLocalCoordinates, setupCoordinates } from "@tileflow/coordinates-runtime";
14
14
  import {
15
- auditTileflowMapThemeValues,
16
- getTileflowStyleFontFaces,
17
- parseResolvedTileflowMap as parseResolvedTileflowMap4,
15
+ auditTileflowMapThemeValues as auditTileflowMapThemeValues2,
16
+ getTileflowStyleFontFaces as getTileflowStyleFontFaces2,
17
+ parseResolvedTileflowMap as parseResolvedTileflowMap5,
18
18
  tileflowMapIdSchema as tileflowMapIdSchema2
19
19
  } from "@tileflow/core";
20
20
  import {
21
- createTileflowMapBuildManifest
21
+ createTileflowMapBuildManifest as createTileflowMapBuildManifest2
22
22
  } from "@tileflow/core/build";
23
23
  import {
24
- parseTileflowRuntimeManifest
24
+ parseTileflowRuntimeManifest as parseTileflowRuntimeManifest2
25
25
  } from "@tileflow/core/manifest";
26
+ import { resolveTileflowRenderer as resolveTileflowRenderer2 } from "@tileflow/core/native-profile";
26
27
  import {
27
28
  createTileflowArtifactDiagnostics as createTileflowArtifactDiagnostics3,
28
29
  createTileflowArtifactSession as createTileflowArtifactSession3,
29
- createTileflowBuildProvenance,
30
- createTileflowStyles,
31
- prepareTileflowLocalTilesets,
30
+ createTileflowBuildProvenance as createTileflowBuildProvenance2,
31
+ createTileflowStyles as createTileflowStyles2,
32
+ prepareTileflowLocalTilesets as prepareTileflowLocalTilesets2,
32
33
  writeTileflowBuildArtifacts
33
34
  } from "@tileflow/dev/artifacts";
34
35
  import {
35
- assertValidTileflowConfig as assertValidTileflowConfig2,
36
+ assertValidTileflowConfig as assertValidTileflowConfig3,
36
37
  defaultTileflowApiUrl,
37
38
  defaultTileflowConfigPath,
38
39
  defaultTileflowManifestPath,
39
- getTileflowMapNames as getTileflowMapNames4,
40
- loadTileflowConfigWithInputs as loadTileflowConfigWithInputs3,
40
+ getTileflowMapNames as getTileflowMapNames5,
41
+ loadTileflowConfigWithInputs as loadTileflowConfigWithInputs4,
41
42
  TileflowValidationError as TileflowValidationError5
42
43
  } from "@tileflow/dev/config";
43
44
  import {
44
45
  bindTileflowStyleFontBundle,
45
- prepareTileflowStyleFonts,
46
+ prepareTileflowStyleFonts as prepareTileflowStyleFonts2,
46
47
  TileflowFontCompilationError
47
48
  } from "@tileflow/dev/fonts";
48
49
  import {
49
- compileTileflowIconPackages as compileTileflowIconPackages2,
50
+ compileTileflowIconPackages as compileTileflowIconPackages3,
50
51
  TileflowIconCompilationError as TileflowIconCompilationError3
51
52
  } from "@tileflow/dev/icons";
52
53
  import { resolveTileflowPreview } from "@tileflow/dev/preview";
53
54
  import {
54
55
  createTileflowComparisonRequestHandler,
55
- createTileflowDevRequestHandler
56
+ createTileflowDevRequestHandler as createTileflowDevRequestHandler2
56
57
  } from "@tileflow/dev/server";
57
58
  import {
58
- createTileflowCommandFailureDocument as createTileflowCommandFailureDocument4,
59
- createTileflowCommandSummary as createTileflowCommandSummary2,
60
- createTileflowStructuredDiagnostics as createTileflowStructuredDiagnostics2,
61
- serializeTileflowCommandDocument as serializeTileflowCommandDocument4,
59
+ createTileflowCommandFailureDocument as createTileflowCommandFailureDocument5,
60
+ createTileflowCommandSummary as createTileflowCommandSummary3,
61
+ createTileflowStructuredDiagnostics as createTileflowStructuredDiagnostics3,
62
+ serializeTileflowCommandDocument as serializeTileflowCommandDocument5,
62
63
  TileflowStyleValidationError as TileflowStyleValidationError2
63
64
  } from "@tileflow/dev/validation";
64
65
 
@@ -385,14 +386,14 @@ async function runExplain(options, compileStyle) {
385
386
  });
386
387
  if (!selection) throw new Error("Explain selection was not resolved.");
387
388
  if (!output.result.ok) {
388
- const failure = createTileflowCommandFailureDocument(
389
+ const failure2 = createTileflowCommandFailureDocument(
389
390
  "explain",
390
391
  { diagnostics: output.structuredDiagnostics },
391
392
  process.cwd(),
392
393
  { code: "COMPILATION_FAILED", phase: "compilation" }
393
394
  );
394
395
  const document2 = {
395
- ...failure,
396
+ ...failure2,
396
397
  authoringManifestSchemaVersion: tileflowAuthoringManifestSchemaVersion,
397
398
  selection,
398
399
  compilation: output.compilation
@@ -422,12 +423,12 @@ async function runExplain(options, compileStyle) {
422
423
  if (options.json) process.stdout.write(serializeTileflowCommandDocument(document));
423
424
  else printHumanExplain(document);
424
425
  } catch (error) {
425
- const failure = createTileflowCommandFailureDocument("explain", error, process.cwd(), {
426
+ const failure2 = createTileflowCommandFailureDocument("explain", error, process.cwd(), {
426
427
  code: "EXPLAIN_FAILED",
427
428
  phase: "compilation"
428
429
  });
429
- if (options.json) process.stderr.write(serializeTileflowCommandDocument(failure));
430
- else printHumanCommandFailure(failure);
430
+ if (options.json) process.stderr.write(serializeTileflowCommandDocument(failure2));
431
+ else printHumanCommandFailure(failure2);
431
432
  process.exitCode = 1;
432
433
  }
433
434
  }
@@ -471,12 +472,12 @@ async function runSemanticDiff(options, defaultConfigPath2) {
471
472
  if (options.json) process.stdout.write(serializeTileflowCommandDocument(document));
472
473
  else printHumanSemanticDiff(difference);
473
474
  } catch (error) {
474
- const failure = createTileflowCommandFailureDocument("semantic-diff", error, process.cwd(), {
475
+ const failure2 = createTileflowCommandFailureDocument("semantic-diff", error, process.cwd(), {
475
476
  code: "SEMANTIC_DIFF_FAILED",
476
477
  phase: "semantic-diff"
477
478
  });
478
- if (options.json) process.stderr.write(serializeTileflowCommandDocument(failure));
479
- else printHumanCommandFailure(failure);
479
+ if (options.json) process.stderr.write(serializeTileflowCommandDocument(failure2));
480
+ else printHumanCommandFailure(failure2);
480
481
  process.exitCode = 1;
481
482
  }
482
483
  }
@@ -1215,14 +1216,14 @@ async function runCaptureWatchCommand(positionalScenes, options) {
1215
1216
  } catch (error) {
1216
1217
  if (signal.aborted || stopped) return;
1217
1218
  unresolvedFailure = true;
1218
- const failure = createTileflowCaptureFailureJson(error, cwd);
1219
+ const failure2 = createTileflowCaptureFailureJson(error, cwd);
1219
1220
  emit({
1220
1221
  event: "failed",
1221
1222
  generation,
1222
- code: failure.code,
1223
- phase: failure.phase,
1224
- diagnostics: failure.diagnostics,
1225
- ...failure.resources ? { resources: failure.resources } : {}
1223
+ code: failure2.code,
1224
+ phase: failure2.phase,
1225
+ diagnostics: failure2.diagnostics,
1226
+ ...failure2.resources ? { resources: failure2.resources } : {}
1226
1227
  });
1227
1228
  }
1228
1229
  };
@@ -1548,6 +1549,11 @@ function runGit(cwd, args) {
1548
1549
  });
1549
1550
  }
1550
1551
 
1552
+ // src/cli-version.ts
1553
+ function isRootCliVersionRequest(arguments_) {
1554
+ return arguments_.length === 1 && (arguments_[0] === "--version" || arguments_[0] === "-V");
1555
+ }
1556
+
1551
1557
  // src/config-inspect-command.ts
1552
1558
  import { inspectTileflowConfig } from "@tileflow/dev/inspect";
1553
1559
  import {
@@ -1566,18 +1572,18 @@ function registerConfigInspectCommand(inspect, dependencies) {
1566
1572
  }
1567
1573
  printHumanConfigInspection(document);
1568
1574
  } catch (error) {
1569
- const failure = createTileflowCommandFailureDocument2("inspect", error, process.cwd(), {
1575
+ const failure2 = createTileflowCommandFailureDocument2("inspect", error, process.cwd(), {
1570
1576
  code: "INSPECTION_FAILED",
1571
1577
  phase: "config-inspection"
1572
1578
  });
1573
1579
  if (options.json) {
1574
- process.stderr.write(serializeTileflowCommandDocument2(failure));
1580
+ process.stderr.write(serializeTileflowCommandDocument2(failure2));
1575
1581
  } else {
1576
- console.error(`${failure.message} [${failure.code}; ${failure.phase}]`);
1577
- for (const diagnostic of failure.diagnostics.slice(1)) {
1582
+ console.error(`${failure2.message} [${failure2.code}; ${failure2.phase}]`);
1583
+ for (const diagnostic of failure2.diagnostics.slice(1)) {
1578
1584
  console.error(`- ${diagnostic.path || "(root)"}: ${diagnostic.message}`);
1579
1585
  }
1580
- console.error(`Suggestion: ${failure.suggestion}`);
1586
+ console.error(`Suggestion: ${failure2.suggestion}`);
1581
1587
  }
1582
1588
  process.exitCode = 1;
1583
1589
  }
@@ -1657,19 +1663,19 @@ function registerCoordinatesCommands(program2, dependencies) {
1657
1663
  coordinates,
1658
1664
  "search",
1659
1665
  dependencies,
1660
- (options) => parseRequest("search", options, { query: options.query })
1666
+ (options) => parseCoordinatesRequest("search", { query: options.query })
1661
1667
  );
1662
1668
  registerOperation(
1663
1669
  coordinates,
1664
1670
  "describe",
1665
1671
  dependencies,
1666
- (options) => parseRequest("describe", options, { id: options.id })
1672
+ (options) => parseCoordinatesRequest("describe", { id: options.id })
1667
1673
  );
1668
1674
  registerOperation(
1669
1675
  coordinates,
1670
1676
  "operations",
1671
1677
  dependencies,
1672
- (options) => parseRequest("operations", options, { from: options.from, to: options.to })
1678
+ (options) => parseCoordinatesRequest("operations", { from: options.from, to: options.to })
1673
1679
  );
1674
1680
  registerOperation(
1675
1681
  coordinates,
@@ -1768,9 +1774,6 @@ function hasConvenienceOptions(command2, options) {
1768
1774
  const transform = options;
1769
1775
  return transform.from !== void 0 || transform.to !== void 0 || transform.positions !== void 0;
1770
1776
  }
1771
- function parseRequest(command2, options, request) {
1772
- return parseCoordinatesRequest(command2, request);
1773
- }
1774
1777
  function parseTransformRequest(options) {
1775
1778
  let positions;
1776
1779
  try {
@@ -1815,7 +1818,7 @@ async function readCoordinatesInput(input, signal) {
1815
1818
  async function readStandardInput(signal) {
1816
1819
  const chunks = [];
1817
1820
  let length = 0;
1818
- return new Promise((resolve8, reject) => {
1821
+ return new Promise((resolve9, reject) => {
1819
1822
  const finish = (result) => {
1820
1823
  process.stdin.removeListener("data", onData);
1821
1824
  process.stdin.removeListener("end", onEnd);
@@ -1837,7 +1840,7 @@ async function readStandardInput(signal) {
1837
1840
  }
1838
1841
  chunks.push(bytes);
1839
1842
  };
1840
- const onEnd = () => finish(() => resolve8(decodeInput(Buffer.concat(chunks))));
1843
+ const onEnd = () => finish(() => resolve9(decodeInput(Buffer.concat(chunks))));
1841
1844
  const onError = () => finish(() => reject(new CoordinatesInputError("INVALID_VALUE")));
1842
1845
  if (signal.aborted) {
1843
1846
  onAbort();
@@ -1895,10 +1898,10 @@ function serializeCoordinatesFailure(error, command2) {
1895
1898
  if (!(error instanceof CoordinatesContractError)) return void 0;
1896
1899
  const parsed = coordinatesFailureSchema.safeParse(error.toJSON());
1897
1900
  if (!parsed.success) return void 0;
1898
- const failure = parsed.data;
1901
+ const failure2 = parsed.data;
1899
1902
  return new CoordinatesContractError({
1900
- ...failure,
1901
- command: failure.command ?? command2 ?? null
1903
+ ...failure2,
1904
+ command: failure2.command ?? command2 ?? null
1902
1905
  }).toJSON();
1903
1906
  }
1904
1907
  function serializeSetupFailure(error) {
@@ -2220,6 +2223,7 @@ import { tileflowIconPackageLimits } from "@tileflow/core";
2220
2223
  var maximumHostedResponseBytes = 1024 * 1024;
2221
2224
  var safeTextSchema = z2.string().min(1).max(300).refine((value) => !/[\p{Cc}]/u.test(value));
2222
2225
  var safeIdentifierSchema = z2.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u);
2226
+ var safeStorageKeySchema = z2.string().min(1).max(512).regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u).refine((value) => value.split("/").every((segment) => segment !== "." && segment !== ".."));
2223
2227
  var publicHttpUrlSchema = z2.url().max(2048).refine((value) => {
2224
2228
  const url = new URL(value);
2225
2229
  return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash;
@@ -2255,7 +2259,7 @@ var hostedFontBundleResponseSchema = z2.object({
2255
2259
  });
2256
2260
  var hostedStatusStyleSchema = z2.object({
2257
2261
  environment: safeTextSchema,
2258
- key: safeIdentifierSchema,
2262
+ key: safeStorageKeySchema,
2259
2263
  mapId: safeIdentifierSchema,
2260
2264
  size: z2.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
2261
2265
  uploaded: z2.iso.datetime({ offset: true })
@@ -2346,7 +2350,7 @@ async function startDeviceAuthorization(appUrl, body, options = {}) {
2346
2350
  async function pollDeviceToken(appUrl, authorization, input, options = {}) {
2347
2351
  const expiresAt = Date.now() + authorization.expiresIn * 1e3;
2348
2352
  const intervalMs = Math.max(authorization.interval, 1) * 1e3;
2349
- const wait = input.sleep ?? ((milliseconds) => new Promise((resolve8) => setTimeout(resolve8, milliseconds)));
2353
+ const wait = input.sleep ?? ((milliseconds) => new Promise((resolve9) => setTimeout(resolve9, milliseconds)));
2350
2354
  while (Date.now() < expiresAt) {
2351
2355
  await wait(intervalMs);
2352
2356
  const response = await requestHostedJson(
@@ -2676,7 +2680,7 @@ async function withHostedResponse(apiUrl, path, init, options, consume) {
2676
2680
  }
2677
2681
  function raceWithAbort(operation, signal) {
2678
2682
  if (signal.aborted) return Promise.reject(signal.reason);
2679
- return new Promise((resolve8, reject) => {
2683
+ return new Promise((resolve9, reject) => {
2680
2684
  const cleanup = () => signal.removeEventListener("abort", onAbort);
2681
2685
  const onAbort = () => {
2682
2686
  cleanup();
@@ -2686,7 +2690,7 @@ function raceWithAbort(operation, signal) {
2686
2690
  operation.then(
2687
2691
  (value) => {
2688
2692
  cleanup();
2689
- resolve8(value);
2693
+ resolve9(value);
2690
2694
  },
2691
2695
  (error) => {
2692
2696
  cleanup();
@@ -2804,6 +2808,33 @@ function safeTransportError(error, fallback) {
2804
2808
  return fallback;
2805
2809
  }
2806
2810
 
2811
+ // src/hosted-native-deploy.ts
2812
+ import { dirname as dirname5 } from "path";
2813
+ import {
2814
+ getTileflowStyleFontFaces,
2815
+ parseResolvedTileflowMap as parseResolvedTileflowMap2,
2816
+ serializeCanonicalJson
2817
+ } from "@tileflow/core";
2818
+ import {
2819
+ createTileflowMapBuildManifest,
2820
+ parseTileflowRendererDeploymentArtifact,
2821
+ tileflowRendererDeploymentResponseSchema
2822
+ } from "@tileflow/core/build";
2823
+ import { parseTileflowRuntimeManifest } from "@tileflow/core/manifest";
2824
+ import {
2825
+ createTileflowBuildProvenance,
2826
+ createTileflowStyles,
2827
+ prepareTileflowHostedNativeDeployment,
2828
+ prepareTileflowLocalTilesets
2829
+ } from "@tileflow/dev/artifacts";
2830
+ import {
2831
+ assertValidTileflowConfig,
2832
+ getTileflowMapNames,
2833
+ loadTileflowConfigWithInputs as loadTileflowConfigWithInputs2
2834
+ } from "@tileflow/dev/config";
2835
+ import { prepareTileflowStyleFonts } from "@tileflow/dev/fonts";
2836
+ import { compileTileflowIconPackages } from "@tileflow/dev/icons";
2837
+
2807
2838
  // src/hosted-preflight.ts
2808
2839
  import {
2809
2840
  compareCodeUnits as compareCodeUnits4,
@@ -2868,46 +2899,312 @@ function cloneStyle(style) {
2868
2899
  return JSON.parse(JSON.stringify(style));
2869
2900
  }
2870
2901
 
2902
+ // src/hosted-native-deploy.ts
2903
+ function failure(message) {
2904
+ return Object.assign(new Error(message), { code: "TF_NATIVE_DEPLOYMENT_INVALID" });
2905
+ }
2906
+ function requireNativeTarget(options) {
2907
+ if (!options.mapId || !/^map_[A-Za-z0-9_-]{16}$/u.test(options.mapId))
2908
+ throw failure("--with-native requires one valid --map-id.");
2909
+ const apiOrigin = normalizeApiOrigin(options.apiUrl);
2910
+ if (!apiOrigin.startsWith("https://"))
2911
+ throw failure("Hosted Native deployment requires an HTTPS API origin.");
2912
+ return { apiOrigin, mapId: options.mapId };
2913
+ }
2914
+ async function prepareNativeHostedDeploy(options) {
2915
+ const { apiOrigin } = requireNativeTarget(options);
2916
+ const loaded = await withTileflowConfigSecretsHidden(
2917
+ () => loadTileflowConfigWithInputs2(options.config)
2918
+ );
2919
+ assertValidTileflowConfig(loaded.project);
2920
+ const names = getTileflowMapNames(loaded.project);
2921
+ const mapName = options.map ?? (names.length === 1 ? names[0] : void 0);
2922
+ if (!mapName || !names.includes(mapName))
2923
+ throw failure("Select one configured map with --map for this Native deployment.");
2924
+ const map = loaded.project.maps[mapName];
2925
+ const project = { ...loaded.project, maps: { [mapName]: map } };
2926
+ const baseDirectory = dirname5(loaded.configFile);
2927
+ const compiledIcons = await compileTileflowIconPackages(project, {
2928
+ baseDirectory,
2929
+ cwd: process.cwd(),
2930
+ target: "hosted",
2931
+ icons: {
2932
+ ...options.cacheDir ? { cacheRoot: options.cacheDir } : {},
2933
+ ...options.offline ? { offline: true } : {}
2934
+ }
2935
+ });
2936
+ const binding = compiledIcons.bindings.find((entry) => entry.mapName === mapName);
2937
+ const iconPackage = binding ? compiledIcons.packages.find((entry) => entry.contentHash === binding.packageHash) : void 0;
2938
+ const sprite = binding ? `${apiOrigin}/sprites/preflight/${binding.packageHash}/sprite` : void 0;
2939
+ const mapAssets = Object.fromEntries(
2940
+ compiledIcons.bindings.map((entry) => [
2941
+ entry.mapName,
2942
+ {
2943
+ icons: {
2944
+ ids: entry.iconIds,
2945
+ sprite: `${apiOrigin}/sprites/preflight/${entry.packageHash}/sprite`
2946
+ }
2947
+ }
2948
+ ])
2949
+ );
2950
+ const styles = createTileflowStyles(project, { apiBaseUrl: apiOrigin, mapAssets });
2951
+ const local = await prepareTileflowLocalTilesets(project, styles, {
2952
+ assetBaseUrl: apiOrigin,
2953
+ baseDirectory,
2954
+ cwd: process.cwd()
2955
+ });
2956
+ try {
2957
+ const fonts = await prepareTileflowStyleFonts(project, local.styles, {
2958
+ assetBaseUrl: `${apiOrigin}/fonts/preflight`,
2959
+ baseDirectory,
2960
+ cwd: process.cwd(),
2961
+ target: "hosted"
2962
+ });
2963
+ if (inspectTileflowHostedCompatibility(project, fonts.styles).length)
2964
+ throw failure("Hosted renderer deployment requires compatible Tileflow World sources.");
2965
+ if (Object.keys(fonts.bundles).length)
2966
+ throw failure(
2967
+ "Hosted deploy does not yet support package-owned web fonts. Use an explicit public glyph provider."
2968
+ );
2969
+ const assets = (iconPackage?.files ?? []).map((file) => ({
2970
+ contentType: file.contentType,
2971
+ fileName: `icons/${mapName}/${file.fileName}`,
2972
+ source: file.source
2973
+ }));
2974
+ const provenance = await createTileflowBuildProvenance(process.cwd());
2975
+ const resolved = parseResolvedTileflowMap2(map);
2976
+ const inputStyles = JSON.parse(
2977
+ serializeCanonicalJson(fonts.styles[mapName])
2978
+ );
2979
+ const createArtifact = async (selectedSprite) => {
2980
+ const selected = JSON.parse(
2981
+ serializeCanonicalJson(inputStyles)
2982
+ );
2983
+ if (binding) {
2984
+ if (!sprite || !selectedSprite) throw failure("Missing confirmed sprite binding.");
2985
+ for (const style of Object.values(selected)) {
2986
+ if (style.sprite !== sprite)
2987
+ throw failure("Compiled sprite identity changed before publication.");
2988
+ style.sprite = selectedSprite;
2989
+ }
2990
+ }
2991
+ const family = prepareTileflowHostedThemeFamily(mapName, map, selected);
2992
+ const buildManifest = await createTileflowMapBuildManifest(
2993
+ {
2994
+ [mapName]: {
2995
+ assets,
2996
+ lineage: project.mapMetadata?.[mapName]?.lineage ?? [
2997
+ { id: map.id, mapVersion: map.version }
2998
+ ],
2999
+ map,
3000
+ sourceAssets: {
3001
+ fonts: fonts.sourceIdentities[mapName] ?? [],
3002
+ icons: compiledIcons.sourceIdentities[mapName] ?? [],
3003
+ ...compiledIcons.compositions[mapName] ? { iconComposition: compiledIcons.compositions[mapName] } : {}
3004
+ },
3005
+ styles: family.styles
3006
+ }
3007
+ },
3008
+ { provenance }
3009
+ );
3010
+ return prepareTileflowHostedNativeDeployment({
3011
+ mapId: mapName,
3012
+ buildManifest,
3013
+ styles: family.styles,
3014
+ teamSources: family.teamSources,
3015
+ assets,
3016
+ ...resolved.view ? { view: resolved.view } : {}
3017
+ });
3018
+ };
3019
+ const artifact = await createArtifact(sprite);
3020
+ return {
3021
+ mapName,
3022
+ artifact,
3023
+ packages: compiledIcons.packages,
3024
+ ...binding ? { iconBinding: binding } : {},
3025
+ ...compiledIcons.compositions[mapName] ? { iconComposition: compiledIcons.compositions[mapName] } : {},
3026
+ async retarget(sprites) {
3027
+ return binding ? createArtifact(sprites.get(binding.packageHash)) : artifact;
3028
+ },
3029
+ dispose: local.dispose
3030
+ };
3031
+ } catch (error) {
3032
+ await local.dispose();
3033
+ throw error;
3034
+ }
3035
+ }
3036
+ async function runHostedNativeDeploy(options, ports) {
3037
+ const { apiOrigin, mapId } = requireNativeTarget(options);
3038
+ const prepared = await (ports.prepare ?? prepareNativeHostedDeploy)({
3039
+ ...options,
3040
+ apiUrl: apiOrigin
3041
+ });
3042
+ try {
3043
+ const preflight = await parseTileflowRendererDeploymentArtifact(prepared.artifact);
3044
+ if (preflight.mapId !== prepared.mapName)
3045
+ throw failure("The prepared map does not match its artifact.");
3046
+ const existing = await ports.loadManifest(options.manifest, {
3047
+ overwriteSelfHosted: options.overwriteSelfHostedManifest === true
3048
+ });
3049
+ const previousOrigin = existing?.apiUrl ?? (existing ? Object.values(existing.maps)[0]?.apiUrl : void 0);
3050
+ if (previousOrigin !== void 0 && normalizeApiOrigin(previousOrigin) !== apiOrigin)
3051
+ throw failure("Existing manifest belongs to a different Tileflow API origin.");
3052
+ const api = await ports.resolveApi(prepared.mapName);
3053
+ if (!api) return null;
3054
+ if (api.apiUrl !== apiOrigin || api.mapId !== mapId || !api.apiKey || api.apiKey.length > 8192 || /[\p{Cc}]/u.test(api.apiKey))
3055
+ throw failure("Authorization did not confirm the requested API and Map.");
3056
+ const sprites = /* @__PURE__ */ new Map();
3057
+ for (const icon of prepared.packages) {
3058
+ if (sprites.has(icon.contentHash)) continue;
3059
+ let uploaded;
3060
+ try {
3061
+ uploaded = await (ports.uploadIcon ?? uploadHostedIconPackage)(api, icon, ports.request);
3062
+ } catch {
3063
+ throw failure("Native deployment icon upload failed. The local manifest was preserved.");
3064
+ }
3065
+ if (!uploaded.ok)
3066
+ throw failure("Native deployment icon upload failed. Retry the same artifact.");
3067
+ const expected = `${apiOrigin}/sprites/${uploaded.value.id}/sprite`;
3068
+ if (uploaded.value.contentHash !== icon.contentHash || uploaded.value.spriteUrl !== expected)
3069
+ throw failure("Icon publication did not confirm the owned resource and origin.");
3070
+ sprites.set(icon.contentHash, expected);
3071
+ }
3072
+ const artifact = await parseTileflowRendererDeploymentArtifact(
3073
+ await prepared.retarget(sprites)
3074
+ );
3075
+ if (artifact.mapId !== preflight.mapId || artifact.renderers.web.buildManifest.maps[artifact.mapId].mapRevisionSha256 !== preflight.renderers.web.buildManifest.maps[preflight.mapId].mapRevisionSha256)
3076
+ throw failure("Authored map identity changed after preflight.");
3077
+ const iconPackage = prepared.iconBinding ? prepared.packages.find((entry) => entry.contentHash === prepared.iconBinding.packageHash) : void 0;
3078
+ if (prepared.iconComposition && prepared.iconComposition.packageHash !== iconPackage?.contentHash)
3079
+ throw failure("Icon composition does not match the confirmed effective package.");
3080
+ let response;
3081
+ try {
3082
+ response = await requestHostedJson(
3083
+ apiOrigin,
3084
+ "/v1/styles",
3085
+ {
3086
+ method: "POST",
3087
+ headers: {
3088
+ Authorization: `Bearer ${api.apiKey}`,
3089
+ "X-Tileflow-Map-Id": mapId,
3090
+ "Content-Type": "application/json"
3091
+ },
3092
+ body: serializeCanonicalJson({
3093
+ artifact,
3094
+ environment: prepared.mapName,
3095
+ managedMapId: mapId,
3096
+ usageMode: "session",
3097
+ source: ports.source,
3098
+ ...iconPackage && prepared.iconBinding ? {
3099
+ iconPackage: {
3100
+ contentHash: iconPackage.contentHash,
3101
+ label: prepared.iconBinding.label
3102
+ }
3103
+ } : {},
3104
+ ...prepared.iconComposition ? { iconComposition: prepared.iconComposition } : {}
3105
+ })
3106
+ },
3107
+ ports.request
3108
+ );
3109
+ } catch {
3110
+ throw failure(
3111
+ "Renderer deployment response was unavailable. Retry the same artifact; the local manifest was preserved."
3112
+ );
3113
+ }
3114
+ if (!response.ok || !response.json)
3115
+ throw failure("Renderer deployment failed. The local manifest was preserved.");
3116
+ const parsed = tileflowRendererDeploymentResponseSchema.safeParse(response.body);
3117
+ if (!parsed.success)
3118
+ throw failure("Invalid renderer deployment response. The local manifest was preserved.");
3119
+ const result = parsed.data;
3120
+ const names = Object.keys(artifact.renderers.web.styles).sort();
3121
+ const expectedManifestUrl = `${apiOrigin}/maps/${mapId}/native/manifest.json`;
3122
+ if (result.mapId !== mapId || result.renderers.native.manifestUrl !== expectedManifestUrl || names.join("\0") !== Object.keys(result.renderers.web.themes).sort().join("\0") || names.join("\0") !== Object.keys(result.renderers.native.themes).sort().join("\0"))
3123
+ throw failure(
3124
+ "Renderer deployment did not confirm the requested Map and complete theme families."
3125
+ );
3126
+ for (const name of names) {
3127
+ if (result.renderers.web.themes[name].styleUrl !== `${apiOrigin}/maps/${mapId}/${name}.json` || result.renderers.native.themes[name].styleUrl !== `${apiOrigin}/maps/${mapId}/native/v${result.version}/${name}.json`)
3128
+ throw failure("Renderer deployment returned an unexpected delivery route.");
3129
+ }
3130
+ const build = artifact.renderers.web.buildManifest.maps[artifact.mapId];
3131
+ const manifest = parseTileflowRuntimeManifest({
3132
+ apiUrl: apiOrigin,
3133
+ version: 1,
3134
+ maps: {
3135
+ ...existing?.maps ?? {},
3136
+ [prepared.mapName]: {
3137
+ defaultTheme: build.defaultTheme,
3138
+ environment: prepared.mapName,
3139
+ mapId,
3140
+ ...build.systemThemes ? { systemThemes: build.systemThemes } : {},
3141
+ ...artifact.view ? { view: artifact.view } : {},
3142
+ usageMode: "session",
3143
+ worldGeneration: "v1",
3144
+ themes: Object.fromEntries(
3145
+ names.map((name) => [
3146
+ name,
3147
+ {
3148
+ colorScheme: build.themes[name].colorScheme,
3149
+ fontFaces: getTileflowStyleFontFaces(
3150
+ artifact.renderers.web.styles[name]
3151
+ ),
3152
+ revision: build.themes[name].styleSha256,
3153
+ ...result.renderers.web.themes[name]
3154
+ }
3155
+ ])
3156
+ )
3157
+ }
3158
+ }
3159
+ });
3160
+ const manifestPath = await ports.writeManifest(options.manifest, manifest);
3161
+ return Object.freeze({
3162
+ manifestPath,
3163
+ mapName: prepared.mapName,
3164
+ mapId,
3165
+ deploymentId: result.deploymentId,
3166
+ version: result.version,
3167
+ changed: result.changed,
3168
+ nativeManifestUrl: expectedManifestUrl
3169
+ });
3170
+ } finally {
3171
+ await prepared.dispose();
3172
+ }
3173
+ }
3174
+
2871
3175
  // src/icon-diff-command.ts
2872
- import { dirname as dirname6, resolve as resolve4 } from "path";
2873
- import { z as z4 } from "zod";
3176
+ import { dirname as dirname7, resolve as resolve4 } from "path";
3177
+ import { z as z3 } from "zod";
2874
3178
  import {
2875
3179
  diffTileflowIconPackageManifests,
2876
3180
  hashTileflowIconPackageManifest,
2877
3181
  tileflowIconPackageContentHashSchema,
2878
3182
  tileflowIconPackageLabelSchema,
2879
- tileflowIconPackageLimits as tileflowIconPackageLimits3,
3183
+ tileflowIconPackageLimits as tileflowIconPackageLimits2,
2880
3184
  tileflowIconPackageManifestSchema,
2881
3185
  tileflowMapIdSchema
2882
3186
  } from "@tileflow/core";
2883
3187
  import {
2884
- assertValidTileflowConfig,
2885
- getTileflowMapNames,
2886
- loadTileflowConfigWithInputs as loadTileflowConfigWithInputs2
3188
+ assertValidTileflowConfig as assertValidTileflowConfig2,
3189
+ getTileflowMapNames as getTileflowMapNames2,
3190
+ loadTileflowConfigWithInputs as loadTileflowConfigWithInputs3
2887
3191
  } from "@tileflow/dev/config";
2888
3192
  import {
2889
- compileTileflowIconPackages
3193
+ compileTileflowIconPackages as compileTileflowIconPackages2
2890
3194
  } from "@tileflow/dev/icons";
2891
3195
 
2892
3196
  // src/icon-diff-report.ts
2893
3197
  import { randomUUID as randomUUID2 } from "crypto";
2894
3198
  import { mkdir as mkdir3, readFile as readFile3, rename as rename3, unlink as unlink3, writeFile } from "fs/promises";
2895
- import { basename as basename2, dirname as dirname5, join } from "path";
2896
- import { z as z3 } from "zod";
3199
+ import { basename as basename2, dirname as dirname6, join } from "path";
2897
3200
  import {
2898
3201
  compareCodeUnits as compareCodeUnits5,
2899
3202
  sha256Hex,
2900
- tileflowIconIdSchema,
2901
- tileflowIconPackageLimits as tileflowIconPackageLimits2
3203
+ tileflowIconSpriteIndexSchema
2902
3204
  } from "@tileflow/core";
2903
- var spriteEntrySchema = z3.object({
2904
- height: z3.number().int().positive().max(tileflowIconPackageLimits2.maxAtlasDimension),
2905
- pixelRatio: z3.union([z3.literal(1), z3.literal(2)]),
2906
- width: z3.number().int().positive().max(tileflowIconPackageLimits2.maxAtlasDimension),
2907
- x: z3.number().int().nonnegative().max(tileflowIconPackageLimits2.maxAtlasDimension),
2908
- y: z3.number().int().nonnegative().max(tileflowIconPackageLimits2.maxAtlasDimension)
2909
- }).strict();
2910
- var spriteIndexSchema = z3.record(tileflowIconIdSchema, spriteEntrySchema);
3205
+ import {
3206
+ renderTileflowIconAtlasPreview
3207
+ } from "@tileflow/dev/icons";
2911
3208
  async function writeIconDiffReport(input) {
2912
3209
  const [before, after] = await Promise.all([
2913
3210
  input.baseline?.package ? loadRemoteSprite(input.baseline.package) : null,
@@ -2945,18 +3242,20 @@ function loadCompiledSprite(iconPackage) {
2945
3242
  iconPackage.manifest.sprites.twoX
2946
3243
  );
2947
3244
  }
2948
- function reportSpriteFromFiles(files, oneX, twoX) {
3245
+ async function reportSpriteFromFiles(files, oneX, twoX) {
2949
3246
  const oneXJson = requiredFile(files, "sprite.json");
2950
3247
  const oneXPng = requiredFile(files, "sprite.png");
2951
3248
  const twoXJson = requiredFile(files, "sprite@2x.json");
2952
3249
  const twoXPng = requiredFile(files, "sprite@2x.png");
3250
+ const indexOneX = parseIndex(oneXJson, 1, oneX.width, oneX.height);
3251
+ const indexTwoX = parseIndex(twoXJson, 2, twoX.width, twoX.height);
2953
3252
  return {
2954
- indexOneX: parseIndex(oneXJson, 1, oneX.width, oneX.height),
2955
- indexTwoX: parseIndex(twoXJson, 2, twoX.width, twoX.height),
2956
- oneXDataUrl: pngDataUrl(oneXPng),
3253
+ indexOneX,
3254
+ indexTwoX,
3255
+ oneXDataUrl: pngDataUrl(await renderTileflowIconAtlasPreview(oneXPng, indexOneX)),
2957
3256
  oneXHeight: oneX.height,
2958
3257
  oneXWidth: oneX.width,
2959
- twoXDataUrl: pngDataUrl(twoXPng),
3258
+ twoXDataUrl: pngDataUrl(await renderTileflowIconAtlasPreview(twoXPng, indexTwoX)),
2960
3259
  twoXHeight: twoX.height,
2961
3260
  twoXWidth: twoX.width
2962
3261
  };
@@ -2968,7 +3267,7 @@ function parseIndex(source, pixelRatio, atlasWidth, atlasHeight) {
2968
3267
  } catch {
2969
3268
  throw new Error("Sprite report index is not valid UTF-8 JSON");
2970
3269
  }
2971
- const parsed = spriteIndexSchema.safeParse(value);
3270
+ const parsed = tileflowIconSpriteIndexSchema.safeParse(value);
2972
3271
  if (!parsed.success) {
2973
3272
  throw new Error("Sprite report index does not match the MapLibre schema");
2974
3273
  }
@@ -3363,9 +3662,9 @@ async function writeAtomicReport(path, html, force) {
3363
3662
  } catch (error) {
3364
3663
  if (!isMissingFile3(error)) throw error;
3365
3664
  }
3366
- await mkdir3(dirname5(path), { recursive: true });
3665
+ await mkdir3(dirname6(path), { recursive: true });
3367
3666
  const temporaryPath = join(
3368
- dirname5(path),
3667
+ dirname6(path),
3369
3668
  `.${basename2(path)}.${process.pid}.${randomUUID2()}.tmp`
3370
3669
  );
3371
3670
  try {
@@ -3394,56 +3693,56 @@ function isMissingFile3(error) {
3394
3693
 
3395
3694
  // src/icon-diff-command.ts
3396
3695
  var environmentSchema = tileflowMapIdSchema;
3397
- var publicHttpUrlSchema2 = z4.url().max(2048).refine((value) => {
3696
+ var publicHttpUrlSchema2 = z3.url().max(2048).refine((value) => {
3398
3697
  const url = new URL(value);
3399
3698
  return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password;
3400
3699
  });
3401
- var iconPackageBaselineResponseSchema = z4.object({
3402
- baseline: z4.object({
3403
- deployedAt: z4.iso.datetime({ offset: true }),
3404
- deploymentId: z4.string().min(1).max(128),
3405
- package: z4.object({
3700
+ var iconPackageBaselineResponseSchema = z3.object({
3701
+ baseline: z3.object({
3702
+ deployedAt: z3.iso.datetime({ offset: true }),
3703
+ deploymentId: z3.string().min(1).max(128),
3704
+ package: z3.object({
3406
3705
  contentHash: tileflowIconPackageContentHashSchema,
3407
3706
  label: tileflowIconPackageLabelSchema,
3408
3707
  manifest: tileflowIconPackageManifestSchema,
3409
3708
  spriteUrl: publicHttpUrlSchema2,
3410
- totalBytes: z4.number().int().positive().max(tileflowIconPackageLimits3.maxGeneratedPackageBytes)
3709
+ totalBytes: z3.number().int().positive().max(tileflowIconPackageLimits2.maxGeneratedPackageBytes)
3411
3710
  }).strict().nullable(),
3412
- version: z4.number().int().positive()
3711
+ version: z3.number().int().positive()
3413
3712
  }).strict().nullable(),
3414
3713
  environment: environmentSchema,
3415
- schemaVersion: z4.literal(1)
3714
+ schemaVersion: z3.literal(1)
3416
3715
  }).strict();
3417
- var packageSummarySchema = z4.object({
3716
+ var packageSummarySchema = z3.object({
3418
3717
  contentHash: tileflowIconPackageContentHashSchema,
3419
- iconCount: z4.number().int().nonnegative().max(tileflowIconPackageLimits3.maxIconCount),
3718
+ iconCount: z3.number().int().nonnegative().max(tileflowIconPackageLimits2.maxIconCount),
3420
3719
  label: tileflowIconPackageLabelSchema,
3421
- totalBytes: z4.number().int().nonnegative().max(tileflowIconPackageLimits3.maxGeneratedPackageBytes)
3720
+ totalBytes: z3.number().int().nonnegative().max(tileflowIconPackageLimits2.maxGeneratedPackageBytes)
3422
3721
  }).strict();
3423
- var tileflowIconDiffDocumentSchema = z4.object({
3424
- schemaVersion: z4.literal(1),
3722
+ var tileflowIconDiffDocumentSchema = z3.object({
3723
+ schemaVersion: z3.literal(1),
3425
3724
  environment: environmentSchema,
3426
- baseline: z4.object({
3427
- deploymentId: z4.string(),
3725
+ baseline: z3.object({
3726
+ deploymentId: z3.string(),
3428
3727
  package: packageSummarySchema.nullable(),
3429
- version: z4.number().int().positive()
3728
+ version: z3.number().int().positive()
3430
3729
  }).strict().nullable(),
3431
- proposed: z4.object({
3730
+ proposed: z3.object({
3432
3731
  package: packageSummarySchema.nullable()
3433
3732
  }).strict(),
3434
- icons: z4.object({
3435
- added: z4.array(z4.string()),
3436
- removed: z4.array(z4.string()),
3437
- modified: z4.array(z4.string()),
3438
- unchangedCount: z4.number().int().nonnegative()
3733
+ icons: z3.object({
3734
+ added: z3.array(z3.string()),
3735
+ removed: z3.array(z3.string()),
3736
+ modified: z3.array(z3.string()),
3737
+ unchangedCount: z3.number().int().nonnegative()
3439
3738
  }).strict(),
3440
- generatedBytes: z4.object({
3441
- before: z4.number().int().nonnegative(),
3442
- after: z4.number().int().nonnegative(),
3443
- delta: z4.number().int()
3739
+ generatedBytes: z3.object({
3740
+ before: z3.number().int().nonnegative(),
3741
+ after: z3.number().int().nonnegative(),
3742
+ delta: z3.number().int()
3444
3743
  }).strict(),
3445
- artifacts: z4.object({ report: z4.string().nullable() }).strict(),
3446
- hasChanges: z4.boolean()
3744
+ artifacts: z3.object({ report: z3.string().nullable() }).strict(),
3745
+ hasChanges: z3.boolean()
3447
3746
  }).strict();
3448
3747
  function registerIconDiffCommand(icons, dependencies) {
3449
3748
  icons.command("diff").description("Preview a local icon package against an active hosted revision").requiredOption("--against <environment>", "named map environment to compare").option("-c, --config <path>", "config path", dependencies.defaultConfigPath).option("--api-url <url>", "Tileflow API URL", process.env.TILEFLOW_API_URL).option("--api-key <key>", "Tileflow API key", process.env.TILEFLOW_API_KEY).requiredOption("--map-id <id>", "managed Map destination").option("--json", "print deterministic schema-version-1 JSON").option("--cache-dir <path>", "verified Icon Set artifact cache root").option("--offline", "fail a locked Icon Set cache miss instead of hydrating it").option("--report <path>", "write a self-contained HTML visual report").option("--open", "open an explicitly requested report").option("--force", "replace a different explicitly requested report").action(async (options) => {
@@ -3467,11 +3766,11 @@ async function runIconDiff(options, dependencies) {
3467
3766
  }
3468
3767
  const environment = environmentSchema.parse(options.against);
3469
3768
  const loaded = await withTileflowConfigSecretsHidden(
3470
- () => loadTileflowConfigWithInputs2(options.config)
3769
+ () => loadTileflowConfigWithInputs3(options.config)
3471
3770
  );
3472
3771
  const project = loaded.project;
3473
- assertValidTileflowConfig(project);
3474
- const mapNames = getTileflowMapNames(project);
3772
+ assertValidTileflowConfig2(project);
3773
+ const mapNames = getTileflowMapNames2(project);
3475
3774
  if (!Object.hasOwn(project.maps, environment)) {
3476
3775
  throw new Error(
3477
3776
  `Unknown map environment "${environment}". Available maps: ${mapNames.join(", ") || "(none)"}`
@@ -3486,8 +3785,8 @@ async function runIconDiff(options, dependencies) {
3486
3785
  ...options.cacheDir ? { cacheRoot: options.cacheDir } : {},
3487
3786
  ...options.offline ? { offline: true } : {}
3488
3787
  };
3489
- const compiled = await compileTileflowIconPackages(selectedProject, {
3490
- baseDirectory: dirname6(loaded.configFile),
3788
+ const compiled = await compileTileflowIconPackages2(selectedProject, {
3789
+ baseDirectory: dirname7(loaded.configFile),
3491
3790
  cwd: process.cwd(),
3492
3791
  ...Object.keys(icons).length > 0 ? { icons } : {},
3493
3792
  target: "hosted"
@@ -3631,10 +3930,10 @@ function formatSignedBytes(bytes) {
3631
3930
  }
3632
3931
 
3633
3932
  // src/icon-list-command.ts
3634
- import { dirname as dirname7 } from "path";
3933
+ import { dirname as dirname8 } from "path";
3635
3934
  import { compareCodeUnits as compareCodeUnits6 } from "@tileflow/core";
3636
3935
  import {
3637
- getTileflowMapNames as getTileflowMapNames2,
3936
+ getTileflowMapNames as getTileflowMapNames3,
3638
3937
  loadValidTileflowConfigWithInputs as loadValidTileflowConfigWithInputs2,
3639
3938
  TileflowValidationError as TileflowValidationError3
3640
3939
  } from "@tileflow/dev/config";
@@ -3675,7 +3974,7 @@ async function runIconList(options) {
3675
3974
  () => loadValidTileflowConfigWithInputs2(options.config)
3676
3975
  );
3677
3976
  const project = loaded.project;
3678
- const mapIds = getTileflowMapNames2(project).sort(compareCodeUnits6);
3977
+ const mapIds = getTileflowMapNames3(project).sort(compareCodeUnits6);
3679
3978
  if (options.map && !Object.hasOwn(project.maps, options.map)) {
3680
3979
  throw new Error(
3681
3980
  `Unknown map "${options.map}". Available maps: ${mapIds.join(", ") || "(none)"}`
@@ -3686,7 +3985,7 @@ async function runIconList(options) {
3686
3985
  ...options.offline ? { offline: true } : {}
3687
3986
  };
3688
3987
  const inspection = await inspectTileflowIconCatalogs(project, {
3689
- baseDirectory: dirname7(loaded.configFile),
3988
+ baseDirectory: dirname8(loaded.configFile),
3690
3989
  cwd: process.cwd(),
3691
3990
  ...Object.keys(icons).length > 0 ? { icons } : {},
3692
3991
  ...options.map ? { mapNames: [options.map] } : {}
@@ -3710,6 +4009,18 @@ function createMapJson(map, catalogs) {
3710
4009
  kind: "sources",
3711
4010
  contributors: mapIcons.contributors.map(createContributorJson),
3712
4011
  finalIds: [...mapIcons.iconIds],
4012
+ ...catalog.icons.some((icon) => icon.appearance) ? {
4013
+ appearances: Object.fromEntries(
4014
+ catalog.icons.flatMap(
4015
+ (icon) => icon.appearance ? [[icon.id, icon.appearance]] : []
4016
+ )
4017
+ )
4018
+ } : {},
4019
+ ...catalog.icons.some((icon) => icon.layout) ? {
4020
+ layouts: Object.fromEntries(
4021
+ catalog.icons.flatMap((icon) => icon.layout ? [[icon.id, icon.layout]] : [])
4022
+ )
4023
+ } : {},
3713
4024
  insideWorkingTree: catalog.insideWorkingTree,
3714
4025
  replacements: catalog.replacements.map((replacement) => ({
3715
4026
  id: replacement.id,
@@ -3773,18 +4084,18 @@ function printIssues(heading, issues) {
3773
4084
  }
3774
4085
 
3775
4086
  // src/icon-lock-command.ts
3776
- import { dirname as dirname8 } from "path";
4087
+ import { dirname as dirname9 } from "path";
3777
4088
  import pc3 from "picocolors";
3778
4089
  import {
3779
4090
  collectTileflowIconSetReferences,
3780
4091
  compareCodeUnits as compareCodeUnits7,
3781
- parseResolvedTileflowMap as parseResolvedTileflowMap2,
4092
+ parseResolvedTileflowMap as parseResolvedTileflowMap3,
3782
4093
  parseTileflowIconsLockfile,
3783
4094
  tileflowIconSetReferenceSchema as tileflowIconSetReferenceSchema2,
3784
4095
  tileflowIconsLockfileName
3785
4096
  } from "@tileflow/core";
3786
4097
  import {
3787
- getTileflowMapNames as getTileflowMapNames3,
4098
+ getTileflowMapNames as getTileflowMapNames4,
3788
4099
  loadValidTileflowConfigWithInputs as loadValidTileflowConfigWithInputs3,
3789
4100
  TileflowValidationError as TileflowValidationError4
3790
4101
  } from "@tileflow/dev/config";
@@ -3792,7 +4103,7 @@ import { readTileflowIconsLockfileText, writeTileflowIconsLockfile } from "@tile
3792
4103
 
3793
4104
  // src/hosted-team.ts
3794
4105
  import pc from "picocolors";
3795
- import { serializeCanonicalJson } from "@tileflow/core";
4106
+ import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
3796
4107
  async function resolveTeamAuthority(options, scopes, dependencies) {
3797
4108
  let apiOrigin;
3798
4109
  try {
@@ -3872,13 +4183,13 @@ function authorizedTeamRequest(authority, path, method, init = {}) {
3872
4183
  });
3873
4184
  }
3874
4185
  function emitJson(value) {
3875
- process.stdout.write(`${serializeCanonicalJson(value)}
4186
+ process.stdout.write(`${serializeCanonicalJson2(value)}
3876
4187
  `);
3877
4188
  }
3878
4189
  function emitFailure(json, code, message, context = {}) {
3879
4190
  if (json) {
3880
4191
  process.stderr.write(
3881
- `${serializeCanonicalJson({ error: { code, ...context, message }, ok: false, schemaVersion: 1 })}
4192
+ `${serializeCanonicalJson2({ error: { code, ...context, message }, ok: false, schemaVersion: 1 })}
3882
4193
  `
3883
4194
  );
3884
4195
  } else {
@@ -3893,8 +4204,9 @@ function safeMessage(error) {
3893
4204
  // src/icon-set-command.ts
3894
4205
  import { isAbsolute as isAbsolute2 } from "path";
3895
4206
  import pc2 from "picocolors";
3896
- import { z as z5 } from "zod";
4207
+ import { z as z4 } from "zod";
3897
4208
  import {
4209
+ tileflowIconPackageLimits as tileflowIconPackageLimits3,
3898
4210
  tileflowIconSetPackageIdSchema,
3899
4211
  tileflowIconSetPinSchema,
3900
4212
  tileflowIconSetReferenceSchema
@@ -4338,27 +4650,27 @@ function isIconSetSlug(value) {
4338
4650
  function isIdempotencyKey(value) {
4339
4651
  return value.length >= 8 && value.length <= 128 && /^[A-Za-z0-9._:-]+$/u.test(value);
4340
4652
  }
4341
- var cursorSchema = z5.string().min(1).max(2048).nullable();
4342
- var isoDateSchema = z5.iso.datetime({ offset: true });
4343
- var setSchema = z5.object({
4344
- id: z5.string().regex(/^ics_[A-Za-z0-9_-]{16}$/u),
4653
+ var cursorSchema = z4.string().min(1).max(2048).nullable();
4654
+ var isoDateSchema = z4.iso.datetime({ offset: true });
4655
+ var setSchema = z4.object({
4656
+ id: z4.string().regex(/^ics_[A-Za-z0-9_-]{16}$/u),
4345
4657
  reference: tileflowIconSetReferenceSchema,
4346
- name: z5.string().max(200),
4347
- description: z5.string().max(2e3),
4658
+ name: z4.string().max(200),
4659
+ description: z4.string().max(2e3),
4348
4660
  archivedAt: isoDateSchema.nullable(),
4349
- latestVersion: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
4661
+ latestVersion: z4.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
4350
4662
  createdAt: isoDateSchema,
4351
4663
  updatedAt: isoDateSchema
4352
4664
  }).strict();
4353
- var revisionBaseSchema = z5.object({
4354
- id: z5.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4665
+ var revisionBaseSchema = z4.object({
4666
+ id: z4.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4355
4667
  reference: tileflowIconSetReferenceSchema,
4356
- version: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4668
+ version: z4.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4357
4669
  publishedAt: isoDateSchema,
4358
4670
  purgedAt: isoDateSchema.nullable(),
4359
- iconCount: z5.number().int().min(0).max(256),
4360
- totalBytes: z5.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4361
- publisher: z5.object({ kind: z5.enum(["credential", "membership"]), id: z5.string().max(200).nullable() }).strict()
4671
+ iconCount: z4.number().int().min(0).max(tileflowIconPackageLimits3.maxIconCount),
4672
+ totalBytes: z4.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4673
+ publisher: z4.object({ kind: z4.enum(["credential", "membership"]), id: z4.string().max(200).nullable() }).strict()
4362
4674
  }).strict();
4363
4675
  var revisionSchema = revisionBaseSchema.extend({ pin: tileflowIconSetPinSchema.nullable() }).transform(({ id, reference, version, publishedAt, purgedAt, iconCount, totalBytes, pin }) => ({
4364
4676
  iconCount,
@@ -4382,53 +4694,53 @@ var revisionSummarySchema = revisionBaseSchema.extend({ packageId: tileflowIconS
4382
4694
  version
4383
4695
  })
4384
4696
  );
4385
- var catalogListResponseSchema = z5.object({
4386
- schemaVersion: z5.literal(1),
4387
- sets: z5.array(setSchema).max(pageSize),
4697
+ var catalogListResponseSchema = z4.object({
4698
+ schemaVersion: z4.literal(1),
4699
+ sets: z4.array(setSchema).max(pageSize),
4388
4700
  nextCursor: cursorSchema.optional()
4389
4701
  }).strict();
4390
- var catalogDetailResponseSchema = z5.object({ schemaVersion: z5.literal(1), set: setSchema }).strict();
4391
- var versionsResponseSchema = z5.object({
4392
- schemaVersion: z5.literal(1),
4393
- versions: z5.array(revisionSummarySchema).max(pageSize),
4702
+ var catalogDetailResponseSchema = z4.object({ schemaVersion: z4.literal(1), set: setSchema }).strict();
4703
+ var versionsResponseSchema = z4.object({
4704
+ schemaVersion: z4.literal(1),
4705
+ versions: z4.array(revisionSummarySchema).max(pageSize),
4394
4706
  nextCursor: cursorSchema.optional()
4395
4707
  }).strict();
4396
- var revisionResponseSchema = z5.object({
4397
- schemaVersion: z5.literal(1),
4398
- archived: z5.boolean(),
4708
+ var revisionResponseSchema = z4.object({
4709
+ schemaVersion: z4.literal(1),
4710
+ archived: z4.boolean(),
4399
4711
  revision: revisionSchema
4400
4712
  }).strict();
4401
- var publishResponseSchema = z5.object({ schemaVersion: z5.literal(1), changed: z5.boolean(), revision: revisionSchema }).strict();
4402
- var usesResponseSchema = z5.object({
4403
- schemaVersion: z5.literal(1),
4404
- uses: z5.array(
4405
- z5.object({
4406
- deploymentId: z5.string().min(1).max(160),
4407
- deploymentVersion: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4408
- mapId: z5.string().min(1).max(160),
4409
- mapName: z5.string().max(200).nullable(),
4410
- mapState: z5.string().max(64),
4411
- versionId: z5.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4412
- version: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4413
- ordinal: z5.number().int().min(0).max(31),
4414
- relationship: z5.enum(["active", "retained"])
4713
+ var publishResponseSchema = z4.object({ schemaVersion: z4.literal(1), changed: z4.boolean(), revision: revisionSchema }).strict();
4714
+ var usesResponseSchema = z4.object({
4715
+ schemaVersion: z4.literal(1),
4716
+ uses: z4.array(
4717
+ z4.object({
4718
+ deploymentId: z4.string().min(1).max(160),
4719
+ deploymentVersion: z4.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4720
+ mapId: z4.string().min(1).max(160),
4721
+ mapName: z4.string().max(200).nullable(),
4722
+ mapState: z4.string().max(64),
4723
+ versionId: z4.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4724
+ version: z4.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4725
+ ordinal: z4.number().int().min(0).max(31),
4726
+ relationship: z4.enum(["active", "retained"])
4415
4727
  }).strict()
4416
4728
  ).max(pageSize),
4417
4729
  nextCursor: cursorSchema.optional(),
4418
- coverage: z5.literal("known-hosted-deployments"),
4419
- includesUndeployedRepositoryLocks: z5.literal(false)
4730
+ coverage: z4.literal("known-hosted-deployments"),
4731
+ includesUndeployedRepositoryLocks: z4.literal(false)
4420
4732
  }).strict();
4421
- var purgeResponseSchema = z5.object({
4422
- schemaVersion: z5.literal(1),
4423
- result: z5.object({
4424
- schemaVersion: z5.literal(1),
4425
- versionId: z5.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4426
- version: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4427
- purged: z5.boolean(),
4428
- knownRetainedDeployments: z5.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4429
- physicalBytesReleased: z5.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4430
- unknownRepositoryLocks: z5.boolean(),
4431
- warning: z5.string().max(400)
4733
+ var purgeResponseSchema = z4.object({
4734
+ schemaVersion: z4.literal(1),
4735
+ result: z4.object({
4736
+ schemaVersion: z4.literal(1),
4737
+ versionId: z4.string().regex(/^icv_[A-Za-z0-9_-]{16}$/u),
4738
+ version: z4.number().int().positive().max(Number.MAX_SAFE_INTEGER),
4739
+ purged: z4.boolean(),
4740
+ knownRetainedDeployments: z4.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4741
+ physicalBytesReleased: z4.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
4742
+ unknownRepositoryLocks: z4.boolean(),
4743
+ warning: z4.string().max(400)
4432
4744
  }).strict()
4433
4745
  }).strict();
4434
4746
 
@@ -4467,7 +4779,7 @@ function registerIconLockCommands(program2, dependencies) {
4467
4779
  const loaded = await withTileflowConfigSecretsHidden(
4468
4780
  () => loadValidTileflowConfigWithInputs3(options.config)
4469
4781
  );
4470
- baseDirectory = dirname8(loaded.configFile);
4782
+ baseDirectory = dirname9(loaded.configFile);
4471
4783
  declared = collectDeclaredReferences(loaded.project);
4472
4784
  } catch (error) {
4473
4785
  return emitFailure(
@@ -4620,8 +4932,8 @@ function withLockOptions(command2, dependencies) {
4620
4932
  function collectDeclaredReferences(project) {
4621
4933
  const references = [];
4622
4934
  const seen = /* @__PURE__ */ new Set();
4623
- for (const mapName of getTileflowMapNames3(project).sort(compareCodeUnits7)) {
4624
- const sources = parseResolvedTileflowMap2(project.maps[mapName]).icons ?? [];
4935
+ for (const mapName of getTileflowMapNames4(project).sort(compareCodeUnits7)) {
4936
+ const sources = parseResolvedTileflowMap3(project.maps[mapName]).icons ?? [];
4625
4937
  for (const reference of collectTileflowIconSetReferences(sources)) {
4626
4938
  if (seen.has(reference)) continue;
4627
4939
  seen.add(reference);
@@ -4669,7 +4981,7 @@ async function readCurrentPins(contents) {
4669
4981
  import { readFile as readFile4 } from "fs/promises";
4670
4982
  import { fileURLToPath } from "url";
4671
4983
  import {
4672
- serializeCanonicalJson as serializeCanonicalJson2,
4984
+ serializeCanonicalJson as serializeCanonicalJson3,
4673
4985
  tileflowAuthoringManifest
4674
4986
  } from "@tileflow/core";
4675
4987
  import {
@@ -4697,21 +5009,21 @@ async function runLanguageCommand(command2, options, operation) {
4697
5009
  try {
4698
5010
  await operation();
4699
5011
  } catch (error) {
4700
- const failure = createTileflowCommandFailureDocument3(command2, error, process.cwd(), {
5012
+ const failure2 = createTileflowCommandFailureDocument3(command2, error, process.cwd(), {
4701
5013
  code: command2 === "language-manifest" ? "LANGUAGE_MANIFEST_FAILED" : "LANGUAGE_SCHEMA_FAILED",
4702
5014
  phase: "language-discovery"
4703
5015
  });
4704
- if (options.json) process.stderr.write(serializeTileflowCommandDocument3(failure));
5016
+ if (options.json) process.stderr.write(serializeTileflowCommandDocument3(failure2));
4705
5017
  else {
4706
- console.error(`${failure.message} [${failure.code}; ${failure.phase}]`);
4707
- console.error(`Suggestion: ${failure.suggestion}`);
5018
+ console.error(`${failure2.message} [${failure2.code}; ${failure2.phase}]`);
5019
+ console.error(`Suggestion: ${failure2.suggestion}`);
4708
5020
  }
4709
5021
  process.exitCode = 1;
4710
5022
  }
4711
5023
  }
4712
5024
  function printManifest(manifest, options) {
4713
5025
  if (options.json) {
4714
- process.stdout.write(`${serializeCanonicalJson2(manifest)}
5026
+ process.stdout.write(`${serializeCanonicalJson3(manifest)}
4715
5027
  `);
4716
5028
  return;
4717
5029
  }
@@ -4722,7 +5034,7 @@ function printManifest(manifest, options) {
4722
5034
  }
4723
5035
  function printSchema(schema, options) {
4724
5036
  if (options.json) {
4725
- process.stdout.write(`${serializeCanonicalJson2(schema)}
5037
+ process.stdout.write(`${serializeCanonicalJson3(schema)}
4726
5038
  `);
4727
5039
  return;
4728
5040
  }
@@ -4742,6 +5054,62 @@ function isRecord(value) {
4742
5054
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
4743
5055
  }
4744
5056
 
5057
+ // src/native-preview-command.ts
5058
+ import { tileflowNativeProfile } from "@tileflow/core/native-profile";
5059
+ import {
5060
+ createTileflowDevRequestHandler
5061
+ } from "@tileflow/dev/server";
5062
+ var tileflowNativePreviewBasePath = "/native";
5063
+ var tileflowNativePreviewProfile = tileflowNativeProfile.id;
5064
+ function getTileflowNativePreviewManifestUrl(origin) {
5065
+ return `${origin}${tileflowNativePreviewBasePath}/manifest.json`;
5066
+ }
5067
+ function resolveTileflowNativePreviewSelection(manifest, options) {
5068
+ const mapNames = Object.keys(manifest.maps).sort();
5069
+ const mapName = options.map ?? (mapNames.length === 1 ? mapNames[0] : void 0);
5070
+ if (!mapName || !Object.hasOwn(manifest.maps, mapName)) {
5071
+ throw new Error(
5072
+ options.map ? "The selected map is not present in the native artifact manifest." : "Select one configured map with --map for native artifact preview."
5073
+ );
5074
+ }
5075
+ const map = manifest.maps[mapName];
5076
+ const themeName = options.theme ?? map.defaultTheme;
5077
+ if (!Object.hasOwn(map.themes, themeName)) {
5078
+ throw new Error("The selected theme is not present in the native artifact manifest.");
5079
+ }
5080
+ return Object.freeze({ mapName, themeName });
5081
+ }
5082
+ var nativePreviewUnavailablePaths = /* @__PURE__ */ new Set([
5083
+ `${tileflowNativePreviewBasePath}/__events`,
5084
+ `${tileflowNativePreviewBasePath}/__status`
5085
+ ]);
5086
+ function createTileflowNativePreviewRequestHandler(options) {
5087
+ const delegate = createTileflowDevRequestHandler({
5088
+ ...options,
5089
+ basePath: tileflowNativePreviewBasePath
5090
+ });
5091
+ const notFound = () => new Response(JSON.stringify({ error: "Not found" }), {
5092
+ headers: { "Content-Type": "application/json; charset=utf-8" },
5093
+ status: 404
5094
+ });
5095
+ const handler = async (request) => {
5096
+ let pathname;
5097
+ try {
5098
+ pathname = new URL(request.url).pathname;
5099
+ } catch {
5100
+ return notFound();
5101
+ }
5102
+ if (pathname === tileflowNativePreviewBasePath || pathname === `${tileflowNativePreviewBasePath}/` || nativePreviewUnavailablePaths.has(pathname) || pathname.startsWith(`${tileflowNativePreviewBasePath}/__runtime/`) || pathname.startsWith(`${tileflowNativePreviewBasePath}/__inspection/`)) {
5103
+ return notFound();
5104
+ }
5105
+ return delegate(request);
5106
+ };
5107
+ return Object.assign(handler, {
5108
+ close: delegate.close,
5109
+ refresh: delegate.refresh
5110
+ });
5111
+ }
5112
+
4745
5113
  // src/open-external.ts
4746
5114
  import { spawn as spawnChild } from "child_process";
4747
5115
  import { platform as hostPlatform } from "os";
@@ -5056,17 +5424,126 @@ function safeMessage2(error) {
5056
5424
  return error instanceof Error && error.message.length <= 300 ? error.message : "Tileflow auth state is unavailable.";
5057
5425
  }
5058
5426
 
5427
+ // src/renderer-artifact-command.ts
5428
+ import { resolve as resolve5 } from "path";
5429
+ import { auditTileflowMapThemeValues } from "@tileflow/core";
5430
+ import {
5431
+ createTileflowNativeDiagnostic,
5432
+ resolveTileflowRenderer,
5433
+ TileflowNativeCompatibilityError
5434
+ } from "@tileflow/core/native-profile";
5435
+ import {
5436
+ createTileflowBuildArtifacts,
5437
+ disposeTileflowBuildArtifacts,
5438
+ writeTileflowArtifactPlan
5439
+ } from "@tileflow/dev/artifacts";
5440
+ import {
5441
+ createTileflowCommandFailureDocument as createTileflowCommandFailureDocument4,
5442
+ createTileflowCommandSummary as createTileflowCommandSummary2,
5443
+ createTileflowStructuredDiagnostics as createTileflowStructuredDiagnostics2,
5444
+ serializeTileflowCommandDocument as serializeTileflowCommandDocument4
5445
+ } from "@tileflow/dev/validation";
5446
+ async function runRendererArtifactCommand(command2, options) {
5447
+ let artifacts;
5448
+ try {
5449
+ const renderer = resolveTileflowRenderer(options.renderer);
5450
+ if (options.target !== "local" && options.target !== "hosted") {
5451
+ throw Object.assign(new Error("Expected a local or hosted target."), {
5452
+ code: "INVALID_TARGET",
5453
+ phase: "command-validation",
5454
+ path: "target"
5455
+ });
5456
+ }
5457
+ if (renderer === "native" && options.target === "hosted") {
5458
+ throw new TileflowNativeCompatibilityError([
5459
+ createTileflowNativeDiagnostic("NATIVE_RENDERER_UNSUPPORTED", "/target")
5460
+ ]);
5461
+ }
5462
+ if (command2 === "build" && options.target === "hosted") {
5463
+ throw Object.assign(
5464
+ new Error("Build prepares local artifacts; Hosted publication uses deploy."),
5465
+ {
5466
+ code: "HOSTED_INCOMPATIBLE",
5467
+ phase: "command-validation",
5468
+ path: "target",
5469
+ suggestion: "Use validate --target hosted for web preflight, or build --target local."
5470
+ }
5471
+ );
5472
+ }
5473
+ artifacts = await withTileflowConfigSecretsHidden(
5474
+ () => createTileflowBuildArtifacts({
5475
+ apiBaseUrl: options.apiBaseUrl,
5476
+ config: options.config,
5477
+ ...options.icons ? { icons: options.icons } : {},
5478
+ renderer,
5479
+ styleBaseUrl: ".",
5480
+ target: "production"
5481
+ })
5482
+ );
5483
+ const outDir = options.out ?? "dist/tileflow";
5484
+ if (command2 === "build") await writeTileflowArtifactPlan(artifacts, { outDir });
5485
+ const summary = createTileflowCommandSummary2({
5486
+ code: command2 === "validate" ? "VALIDATION_OK" : "BUILD_OK",
5487
+ command: command2,
5488
+ message: command2 === "validate" ? "Tileflow artifact validation passed." : "Built Tileflow artifacts.",
5489
+ ok: true,
5490
+ phase: command2 === "validate" ? "validation" : "build",
5491
+ severity: "info",
5492
+ suggestion: renderer === "native" ? "Use the prepared native manifest with a separately qualified native runtime." : "Serve the prepared artifact directory."
5493
+ });
5494
+ const warnings = Object.values(artifacts.project.maps).flatMap(
5495
+ (map) => auditTileflowMapThemeValues(map).filter(({ severity }) => severity === "warning")
5496
+ );
5497
+ const diagnostics = warnings.length ? createTileflowStructuredDiagnostics2({ diagnostics: warnings }, process.cwd(), {
5498
+ code: "VALIDATION_WARNING",
5499
+ phase: "theme-audit"
5500
+ }) : [];
5501
+ const document = {
5502
+ ...summary,
5503
+ target: options.target,
5504
+ renderer,
5505
+ ...artifacts.nativeBuild ? { profile: artifacts.nativeBuild.profile, validation: "static-artifacts" } : {},
5506
+ maps: Object.keys(artifacts.project.maps).sort(),
5507
+ diagnostics
5508
+ };
5509
+ if (options.json) process.stdout.write(serializeTileflowCommandDocument4(document));
5510
+ else {
5511
+ console.log(summary.message);
5512
+ for (const issue of diagnostics) console.warn(`${issue.path}: ${issue.message}`);
5513
+ if (artifacts.nativeBuild)
5514
+ console.log("Profile: native-v1 (static artifacts; no device qualification).");
5515
+ if (command2 === "build")
5516
+ console.log(`Output: ${resolve5(outDir, ...renderer === "native" ? ["native"] : [])}`);
5517
+ }
5518
+ } catch (error) {
5519
+ const document = createTileflowCommandFailureDocument4(command2, error, process.cwd(), {
5520
+ code: command2 === "validate" ? "VALIDATION_FAILED" : "BUILD_FAILED",
5521
+ phase: "artifact-preparation"
5522
+ });
5523
+ if (options.json) process.stderr.write(serializeTileflowCommandDocument4(document));
5524
+ else {
5525
+ for (const issue of document.diagnostics) {
5526
+ console.error(`${issue.code} ${issue.path || "(root)"}: ${issue.message}`);
5527
+ console.error(`Suggestion: ${issue.suggestion}`);
5528
+ }
5529
+ }
5530
+ process.exitCode = 1;
5531
+ } finally {
5532
+ if (artifacts) await disposeTileflowBuildArtifacts(artifacts);
5533
+ }
5534
+ }
5535
+
5059
5536
  // src/tileset-command.ts
5060
5537
  import pc5 from "picocolors";
5061
- import { serializeCanonicalJson as serializeCanonicalJson4 } from "@tileflow/core";
5538
+ import { z as z6 } from "zod";
5539
+ import { serializeCanonicalJson as serializeCanonicalJson5 } from "@tileflow/core";
5062
5540
  import { inspectTileflowPmtiles } from "@tileflow/dev/tilesets";
5063
- import { z as z7 } from "zod";
5064
5541
 
5065
5542
  // src/tileset-upload.ts
5066
5543
  import { createHash } from "crypto";
5067
5544
  import { open as open4, stat } from "fs/promises";
5068
- import { z as z6 } from "zod";
5069
- import { serializeCanonicalJson as serializeCanonicalJson3 } from "@tileflow/core";
5545
+ import { z as z5 } from "zod";
5546
+ import { serializeCanonicalJson as serializeCanonicalJson4 } from "@tileflow/core";
5070
5547
  var teamTilesetPartSize = 16777216;
5071
5548
  var maximumTeamTilesetBytes = 4e9;
5072
5549
  var authorizationBatchSize = 16;
@@ -5206,7 +5683,7 @@ async function prepareTeamTilesetUpload(file) {
5206
5683
  };
5207
5684
  return Object.freeze({
5208
5685
  byteCount: identity.size,
5209
- contentHash: createHash("sha256").update(serializeCanonicalJson3(contentIdentity)).digest("hex"),
5686
+ contentHash: createHash("sha256").update(serializeCanonicalJson4(contentIdentity)).digest("hex"),
5210
5687
  contentHashAlgorithm: "sha256-fixed-parts-v1",
5211
5688
  identity,
5212
5689
  partSize: teamTilesetPartSize,
@@ -5222,7 +5699,7 @@ function createTeamTilesetUploadIdempotencyKey(tilesetId, upload) {
5222
5699
  );
5223
5700
  }
5224
5701
  return createHash("sha256").update(
5225
- serializeCanonicalJson3({
5702
+ serializeCanonicalJson4({
5226
5703
  byteCount: upload.byteCount,
5227
5704
  contentHash: upload.contentHash,
5228
5705
  contentHashAlgorithm: upload.contentHashAlgorithm,
@@ -5626,36 +6103,36 @@ function asRecord3(value) {
5626
6103
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
5627
6104
  }
5628
6105
  function defaultSleep(milliseconds) {
5629
- return new Promise((resolve8) => setTimeout(resolve8, milliseconds));
5630
- }
5631
- var identifierSchema = z6.string().min(20).max(80).regex(/^[A-Za-z0-9_-]+$/u);
5632
- var uploadPartStatusSchema = z6.object({
5633
- byteCount: z6.number().int().min(1).max(teamTilesetPartSize),
5634
- partNumber: z6.number().int().min(1).max(239),
5635
- uploaded: z6.boolean(),
5636
- validationState: z6.enum(["mismatch", "pending", "processing", "valid"])
6106
+ return new Promise((resolve9) => setTimeout(resolve9, milliseconds));
6107
+ }
6108
+ var identifierSchema = z5.string().min(20).max(80).regex(/^[A-Za-z0-9_-]+$/u);
6109
+ var uploadPartStatusSchema = z5.object({
6110
+ byteCount: z5.number().int().min(1).max(teamTilesetPartSize),
6111
+ partNumber: z5.number().int().min(1).max(239),
6112
+ uploaded: z5.boolean(),
6113
+ validationState: z5.enum(["mismatch", "pending", "processing", "valid"])
5637
6114
  }).strict();
5638
- var publishedVersionSchema = z6.object({
5639
- byteCount: z6.number().int().min(1).max(maximumTeamTilesetBytes),
5640
- contentHash: z6.string().regex(/^[0-9a-f]{64}$/u),
5641
- contentHashAlgorithm: z6.literal("sha256-fixed-parts-v1"),
5642
- publishedVersion: z6.number().int().positive().max(Number.MAX_SAFE_INTEGER),
5643
- schemaVersion: z6.literal(1),
5644
- state: z6.literal("published"),
6115
+ var publishedVersionSchema = z5.object({
6116
+ byteCount: z5.number().int().min(1).max(maximumTeamTilesetBytes),
6117
+ contentHash: z5.string().regex(/^[0-9a-f]{64}$/u),
6118
+ contentHashAlgorithm: z5.literal("sha256-fixed-parts-v1"),
6119
+ publishedVersion: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
6120
+ schemaVersion: z5.literal(1),
6121
+ state: z5.literal("published"),
5645
6122
  versionId: identifierSchema.regex(/^tsv_[A-Za-z0-9_-]+$/u)
5646
6123
  }).strict();
5647
- var uploadControlSchema = z6.object({
5648
- byteCount: z6.number().int().min(1).max(maximumTeamTilesetBytes),
5649
- contentHash: z6.string().regex(/^[0-9a-f]{64}$/u),
5650
- contentHashAlgorithm: z6.literal("sha256-fixed-parts-v1"),
5651
- expiresAt: z6.iso.datetime({ offset: true }),
5652
- failure: z6.object({ code: z6.string().regex(/^TF_[A-Z0-9_]{1,96}$/u) }).strict().nullable(),
5653
- partCount: z6.number().int().min(1).max(239),
5654
- parts: z6.array(uploadPartStatusSchema).max(239),
5655
- partSize: z6.literal(teamTilesetPartSize),
5656
- publishedVersion: z6.null(),
5657
- schemaVersion: z6.literal(1),
5658
- state: z6.enum([
6124
+ var uploadControlSchema = z5.object({
6125
+ byteCount: z5.number().int().min(1).max(maximumTeamTilesetBytes),
6126
+ contentHash: z5.string().regex(/^[0-9a-f]{64}$/u),
6127
+ contentHashAlgorithm: z5.literal("sha256-fixed-parts-v1"),
6128
+ expiresAt: z5.iso.datetime({ offset: true }),
6129
+ failure: z5.object({ code: z5.string().regex(/^TF_[A-Z0-9_]{1,96}$/u) }).strict().nullable(),
6130
+ partCount: z5.number().int().min(1).max(239),
6131
+ parts: z5.array(uploadPartStatusSchema).max(239),
6132
+ partSize: z5.literal(teamTilesetPartSize),
6133
+ publishedVersion: z5.null(),
6134
+ schemaVersion: z5.literal(1),
6135
+ state: z5.enum([
5659
6136
  "aborted",
5660
6137
  "aborting",
5661
6138
  "expired",
@@ -5668,32 +6145,32 @@ var uploadControlSchema = z6.object({
5668
6145
  "uploading",
5669
6146
  "validating"
5670
6147
  ]),
5671
- uploadId: z6.string().min(20).max(80).regex(/^tsu_[A-Za-z0-9_-]+$/u),
5672
- versionId: z6.null()
6148
+ uploadId: z5.string().min(20).max(80).regex(/^tsu_[A-Za-z0-9_-]+$/u),
6149
+ versionId: z5.null()
5673
6150
  }).strict();
5674
- var uploadSessionSchema = z6.union([publishedVersionSchema, uploadControlSchema]);
5675
- var authorizationSchema = z6.object({
5676
- expiresAt: z6.iso.datetime({ offset: true }),
5677
- headers: z6.object({
5678
- "Content-Length": z6.string().regex(/^[1-9][0-9]{0,9}$/u),
5679
- "Content-MD5": z6.string().regex(/^[A-Za-z0-9+/]{22}==$/u)
6151
+ var uploadSessionSchema = z5.union([publishedVersionSchema, uploadControlSchema]);
6152
+ var authorizationSchema = z5.object({
6153
+ expiresAt: z5.iso.datetime({ offset: true }),
6154
+ headers: z5.object({
6155
+ "Content-Length": z5.string().regex(/^[1-9][0-9]{0,9}$/u),
6156
+ "Content-MD5": z5.string().regex(/^[A-Za-z0-9+/]{22}==$/u)
5680
6157
  }).strict(),
5681
- method: z6.literal("PUT"),
5682
- partNumber: z6.number().int().min(1).max(239),
5683
- url: z6.url().max(8192).refine((value) => {
6158
+ method: z5.literal("PUT"),
6159
+ partNumber: z5.number().int().min(1).max(239),
6160
+ url: z5.url().max(8192).refine((value) => {
5684
6161
  const url = new URL(value);
5685
6162
  return url.protocol === "https:" && !url.username && !url.password && !url.hash;
5686
6163
  })
5687
6164
  }).strict();
5688
- var authorizationResponseSchema = z6.object({
5689
- authorizations: z6.array(authorizationSchema).min(1).max(16),
5690
- schemaVersion: z6.literal(1)
6165
+ var authorizationResponseSchema = z5.object({
6166
+ authorizations: z5.array(authorizationSchema).min(1).max(16),
6167
+ schemaVersion: z5.literal(1)
5691
6168
  }).strict();
5692
- var partReceiptResponseSchema = z6.object({
5693
- changed: z6.boolean(),
5694
- etag: z6.string().regex(/^[0-9a-f]{32}$/u),
5695
- partNumber: z6.number().int().min(1).max(239),
5696
- schemaVersion: z6.literal(1)
6169
+ var partReceiptResponseSchema = z5.object({
6170
+ changed: z5.boolean(),
6171
+ etag: z5.string().regex(/^[0-9a-f]{32}$/u),
6172
+ partNumber: z5.number().int().min(1).max(239),
6173
+ schemaVersion: z5.literal(1)
5697
6174
  }).strict();
5698
6175
 
5699
6176
  // src/tileset-command.ts
@@ -5713,7 +6190,7 @@ function registerTilesetCommands(program2, dependencies) {
5713
6190
  sample: options.sample
5714
6191
  });
5715
6192
  if (options.json) {
5716
- process.stdout.write(`${serializeCanonicalJson4(inspection)}
6193
+ process.stdout.write(`${serializeCanonicalJson5(inspection)}
5717
6194
  `);
5718
6195
  return;
5719
6196
  }
@@ -5736,7 +6213,7 @@ function registerTilesetCommands(program2, dependencies) {
5736
6213
  const message = error instanceof Error ? error.message : "Tileset inspection failed.";
5737
6214
  if (options.json) {
5738
6215
  process.stderr.write(
5739
- `${serializeCanonicalJson4({ error: { code, message, path }, ok: false, schemaVersion: 1 })}
6216
+ `${serializeCanonicalJson5({ error: { code, message, path }, ok: false, schemaVersion: 1 })}
5740
6217
  `
5741
6218
  );
5742
6219
  } else {
@@ -5987,69 +6464,69 @@ function inspectionOptionError(message) {
5987
6464
  function asRecord4(value) {
5988
6465
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
5989
6466
  }
5990
- var safeIdentifierSchema2 = z7.string().min(1).max(160).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u);
5991
- var physicalTilesetIdSchema = z7.string().min(20).max(80).regex(/^tls_[A-Za-z0-9_-]+$/u);
5992
- var cursorSchema2 = z7.string().min(1).max(2048).nullable();
5993
- var tilesetInventoryItemSchema = z7.object({
5994
- currentVersion: z7.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
5995
- hasCurrent: z7.boolean(),
6467
+ var safeIdentifierSchema2 = z6.string().min(1).max(160).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u);
6468
+ var physicalTilesetIdSchema = z6.string().min(20).max(80).regex(/^tls_[A-Za-z0-9_-]+$/u);
6469
+ var cursorSchema2 = z6.string().min(1).max(2048).nullable();
6470
+ var tilesetInventoryItemSchema = z6.object({
6471
+ currentVersion: z6.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
6472
+ hasCurrent: z6.boolean(),
5996
6473
  id: physicalTilesetIdSchema,
5997
- logicalName: z7.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u),
5998
- name: z7.string().min(1).max(200),
5999
- retainedBytes: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6000
- retainedDeploymentCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6001
- status: z7.enum(["active", "purging", "retired"]),
6002
- updatedAt: z7.iso.datetime({ offset: true }),
6003
- usedByMapCount: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER)
6474
+ logicalName: z6.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u),
6475
+ name: z6.string().min(1).max(200),
6476
+ retainedBytes: z6.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6477
+ retainedDeploymentCount: z6.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6478
+ status: z6.enum(["active", "purging", "retired"]),
6479
+ updatedAt: z6.iso.datetime({ offset: true }),
6480
+ usedByMapCount: z6.number().int().min(0).max(Number.MAX_SAFE_INTEGER)
6004
6481
  }).strict();
6005
- var tilesetListResponseSchema = z7.object({
6482
+ var tilesetListResponseSchema = z6.object({
6006
6483
  nextCursor: cursorSchema2.optional(),
6007
- schemaVersion: z7.literal(1),
6008
- tilesets: z7.array(tilesetInventoryItemSchema).max(100)
6484
+ schemaVersion: z6.literal(1),
6485
+ tilesets: z6.array(tilesetInventoryItemSchema).max(100)
6009
6486
  }).strict();
6010
- var tilesetDependencySchema = z7.object({
6011
- active: z7.boolean(),
6487
+ var tilesetDependencySchema = z6.object({
6488
+ active: z6.boolean(),
6012
6489
  deploymentId: safeIdentifierSchema2,
6013
- deploymentVersion: z7.number().int().positive().max(Number.MAX_SAFE_INTEGER),
6014
- environment: z7.string().min(1).max(64),
6490
+ deploymentVersion: z6.number().int().positive().max(Number.MAX_SAFE_INTEGER),
6491
+ environment: z6.string().min(1).max(64),
6015
6492
  mapId: safeIdentifierSchema2,
6016
6493
  sourceId: safeIdentifierSchema2
6017
6494
  }).strict();
6018
- var tilesetDetailResponseSchema = z7.object({
6019
- schemaVersion: z7.literal(1),
6020
- tileset: z7.object({
6021
- attribution: z7.string().max(4096).nullable(),
6022
- currentVersion: z7.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
6023
- dependencies: z7.array(tilesetDependencySchema).max(25),
6495
+ var tilesetDetailResponseSchema = z6.object({
6496
+ schemaVersion: z6.literal(1),
6497
+ tileset: z6.object({
6498
+ attribution: z6.string().max(4096).nullable(),
6499
+ currentVersion: z6.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
6500
+ dependencies: z6.array(tilesetDependencySchema).max(25),
6024
6501
  dependencyNextCursor: cursorSchema2,
6025
6502
  id: physicalTilesetIdSchema,
6026
- name: z7.string().min(1).max(200),
6027
- slug: z7.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u),
6028
- state: z7.enum(["active", "purging", "purged"])
6503
+ name: z6.string().min(1).max(200),
6504
+ slug: z6.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u),
6505
+ state: z6.enum(["active", "purging", "purged"])
6029
6506
  }).strict()
6030
6507
  }).strict();
6031
- var purgeDependencySchema = z7.object({
6508
+ var purgeDependencySchema = z6.object({
6032
6509
  deploymentId: safeIdentifierSchema2,
6033
6510
  mapId: safeIdentifierSchema2,
6034
6511
  sourceId: safeIdentifierSchema2
6035
6512
  }).strict();
6036
- var tilesetInUseResponseSchema = z7.object({
6037
- code: z7.literal("TF_TILESET_IN_USE"),
6038
- dependencies: z7.array(purgeDependencySchema).max(32),
6039
- error: z7.literal("Tileset is used by retained Map deployments"),
6513
+ var tilesetInUseResponseSchema = z6.object({
6514
+ code: z6.literal("TF_TILESET_IN_USE"),
6515
+ dependencies: z6.array(purgeDependencySchema).max(32),
6516
+ error: z6.literal("Tileset is used by retained Map deployments"),
6040
6517
  nextCursor: cursorSchema2
6041
6518
  }).strict();
6042
- var tilesetPurgeResponseSchema = z7.object({
6043
- deliveryFence: z7.enum(["complete", "pending"]),
6044
- pendingVersions: z7.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6045
- reclamation: z7.enum(["complete", "pending"]),
6046
- state: z7.enum(["purged", "purging"]),
6519
+ var tilesetPurgeResponseSchema = z6.object({
6520
+ deliveryFence: z6.enum(["complete", "pending"]),
6521
+ pendingVersions: z6.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
6522
+ reclamation: z6.enum(["complete", "pending"]),
6523
+ state: z6.enum(["purged", "purging"]),
6047
6524
  tilesetId: physicalTilesetIdSchema
6048
6525
  }).strict();
6049
6526
 
6050
6527
  // src/visual-command.ts
6051
6528
  import { lstat as lstat4, readFile as readFile6 } from "fs/promises";
6052
- import { dirname as dirname10, isAbsolute as isAbsolute4, parse as parse2, relative as relative4, resolve as resolve6, sep as sep4 } from "path";
6529
+ import { dirname as dirname11, isAbsolute as isAbsolute4, parse as parse2, relative as relative4, resolve as resolve7, sep as sep4 } from "path";
6053
6530
  import {
6054
6531
  analyzeTileflowCaptureReference,
6055
6532
  compareTileflowCaptureToBaseline,
@@ -6068,7 +6545,7 @@ import { compareCodeUnits as compareCodeUnits9 } from "@tileflow/core";
6068
6545
  // src/visual-compare-command.ts
6069
6546
  import { createHash as createHash3 } from "crypto";
6070
6547
  import { lstat as lstat3, readFile as readFile5, realpath } from "fs/promises";
6071
- import { basename as basename3, dirname as dirname9, extname, isAbsolute as isAbsolute3, parse, relative as relative3, resolve as resolve5, sep as sep3 } from "path";
6548
+ import { basename as basename3, dirname as dirname10, extname, isAbsolute as isAbsolute3, parse, relative as relative3, resolve as resolve6, sep as sep3 } from "path";
6072
6549
  import {
6073
6550
  compareTileflowCapturesForReview,
6074
6551
  createTileflowCaptureSession as createTileflowCaptureSession2,
@@ -6079,14 +6556,14 @@ import {
6079
6556
  import {
6080
6557
  compareCodeUnits as compareCodeUnits8,
6081
6558
  normalizeTileflowCaptureScene as normalizeTileflowCaptureScene2,
6082
- parseResolvedTileflowMap as parseResolvedTileflowMap3,
6559
+ parseResolvedTileflowMap as parseResolvedTileflowMap4,
6083
6560
  resolveThemeSelection,
6084
6561
  tileflowCaptureSceneLimits
6085
6562
  } from "@tileflow/core";
6086
6563
  import {
6087
6564
  createTileflowArtifactDiagnostics as createTileflowArtifactDiagnostics2,
6088
6565
  createTileflowArtifactSession as createTileflowArtifactSession2,
6089
- createTileflowBuildArtifacts
6566
+ createTileflowBuildArtifacts as createTileflowBuildArtifacts2
6090
6567
  } from "@tileflow/dev/artifacts";
6091
6568
 
6092
6569
  // src/visual-compare-report.ts
@@ -6381,15 +6858,15 @@ async function parseVisualComparePlan(options) {
6381
6858
  }
6382
6859
  async function createArtifactPair(plan) {
6383
6860
  const cwd = process.cwd();
6384
- const leftPath = portablePathIdentity(resolve5(cwd, plan.config));
6385
- const rightPath = portablePathIdentity(resolve5(cwd, plan.againstConfig));
6386
- const left = await createTileflowBuildArtifacts({
6861
+ const leftPath = portablePathIdentity(resolve6(cwd, plan.config));
6862
+ const rightPath = portablePathIdentity(resolve6(cwd, plan.againstConfig));
6863
+ const left = await createTileflowBuildArtifacts2({
6387
6864
  assetBaseUrl: tileflowSyntheticAssetOrigin2,
6388
6865
  config: plan.config,
6389
6866
  cwd
6390
6867
  });
6391
6868
  if (leftPath === rightPath) return [left, left];
6392
- const right = await createTileflowBuildArtifacts({
6869
+ const right = await createTileflowBuildArtifacts2({
6393
6870
  assetBaseUrl: tileflowSyntheticAssetOrigin2,
6394
6871
  config: plan.againstConfig,
6395
6872
  cwd
@@ -6534,7 +7011,7 @@ async function prepareVisualCompareOutput(plan, leftArtifacts, rightArtifacts, c
6534
7011
  files,
6535
7012
  incompatible,
6536
7013
  nextAssets: inventory.assets.map((asset) => ({
6537
- path: resolve5(plan.output.assetDirectory, asset.path),
7014
+ path: resolve6(plan.output.assetDirectory, asset.path),
6538
7015
  sha256: asset.sha256
6539
7016
  })),
6540
7017
  removePaths: [...new Set(removePaths)].filter((path) => !filePaths.has(path))
@@ -6553,7 +7030,7 @@ async function writePreparedVisualCompareOutput(output, prepared) {
6553
7030
  async function runVisualCompareWatch(plan, openReport) {
6554
7031
  const cwd = process.cwd();
6555
7032
  const controller = installSignalAbortController();
6556
- const sameConfig = portablePathIdentity(resolve5(cwd, plan.config)) === portablePathIdentity(resolve5(cwd, plan.againstConfig));
7033
+ const sameConfig = portablePathIdentity(resolve6(cwd, plan.config)) === portablePathIdentity(resolve6(cwd, plan.againstConfig));
6557
7034
  let leftSession;
6558
7035
  let rightSession;
6559
7036
  let captureSession;
@@ -6810,7 +7287,7 @@ function resolveVisualCompareSide(artifacts, config, requestedMap, requestedThem
6810
7287
  `Unknown ${role} map "${map}". Available maps: ${availableMaps.join(", ") || "(none)"}.`
6811
7288
  );
6812
7289
  }
6813
- const resolvedMap = parseResolvedTileflowMap3(candidate);
7290
+ const resolvedMap = parseResolvedTileflowMap4(candidate);
6814
7291
  const theme = resolveThemeSelection(resolvedMap, requestedTheme).name;
6815
7292
  if (!artifacts.styles[map]?.[theme]) {
6816
7293
  throw new Error(`The ${role} map theme "${map}/${theme}" was not compiled.`);
@@ -6862,11 +7339,11 @@ function requireCapture(captures, scene, role) {
6862
7339
  return capture;
6863
7340
  }
6864
7341
  async function resolveVisualCompareOutput(cwd, value, managed, force, watch, zooms) {
6865
- const reportPath = resolve5(cwd, value);
7342
+ const reportPath = resolve6(cwd, value);
6866
7343
  if (extname(reportPath).toLowerCase() !== ".html") {
6867
7344
  throw new Error("--report must name an .html file.");
6868
7345
  }
6869
- const reportDirectory = dirname9(reportPath);
7346
+ const reportDirectory = dirname10(reportPath);
6870
7347
  if (reportDirectory === cwd || reportDirectory === parse(reportPath).root) {
6871
7348
  throw new Error("Visual compare output must use a dedicated subdirectory.");
6872
7349
  }
@@ -6876,7 +7353,7 @@ async function resolveVisualCompareOutput(cwd, value, managed, force, watch, zoo
6876
7353
  const stem = reportPath.slice(0, -".html".length);
6877
7354
  const documentPath = `${stem}.json`;
6878
7355
  const assetDirectory = `${stem}.assets`;
6879
- const inventoryPath = resolve5(assetDirectory, tileflowVisualCompareInventoryFileName);
7356
+ const inventoryPath = resolve6(assetDirectory, tileflowVisualCompareInventoryFileName);
6880
7357
  const boundary = isInside(cwd, reportDirectory) ? cwd : reportDirectory;
6881
7358
  await assertNoSymlinkComponents(reportDirectory, boundary);
6882
7359
  await assertNoSymlinkComponents(assetDirectory, boundary);
@@ -6916,16 +7393,16 @@ async function resolveVisualCompareOutput(cwd, value, managed, force, watch, zoo
6916
7393
  function visualCompareRowPaths(output, index, zoom, includeDiff) {
6917
7394
  const prefix = `${String(index + 1).padStart(2, "0")}-z${zoomSlug(zoom)}`;
6918
7395
  return {
6919
- leftPath: resolve5(output.assetDirectory, `${prefix}.left.png`),
6920
- rightPath: resolve5(output.assetDirectory, `${prefix}.right.png`),
6921
- leftReceiptPath: resolve5(output.assetDirectory, `${prefix}.left.receipt.json`),
6922
- rightReceiptPath: resolve5(output.assetDirectory, `${prefix}.right.receipt.json`),
6923
- diffPath: includeDiff ? resolve5(output.assetDirectory, `${prefix}.diff.png`) : void 0
7396
+ leftPath: resolve6(output.assetDirectory, `${prefix}.left.png`),
7397
+ rightPath: resolve6(output.assetDirectory, `${prefix}.right.png`),
7398
+ leftReceiptPath: resolve6(output.assetDirectory, `${prefix}.left.receipt.json`),
7399
+ rightReceiptPath: resolve6(output.assetDirectory, `${prefix}.right.receipt.json`),
7400
+ diffPath: includeDiff ? resolve6(output.assetDirectory, `${prefix}.diff.png`) : void 0
6924
7401
  };
6925
7402
  }
6926
7403
  function sideJson(side, cwd) {
6927
7404
  return {
6928
- config: relativePath(cwd, resolve5(cwd, side.config)),
7405
+ config: relativePath(cwd, resolve6(cwd, side.config)),
6929
7406
  label: side.label,
6930
7407
  map: side.map,
6931
7408
  theme: side.theme
@@ -6933,13 +7410,13 @@ function sideJson(side, cwd) {
6933
7410
  }
6934
7411
  function watchSideLabel(cwd, config, map, theme) {
6935
7412
  const selection = map ? `${map} / ${theme ?? "default theme"}` : `singular map / ${theme ?? "default theme"}`;
6936
- return `${relativePath(cwd, resolve5(cwd, config))} (${selection})`;
7413
+ return `${relativePath(cwd, resolve6(cwd, config))} (${selection})`;
6937
7414
  }
6938
7415
  async function assertVisualCompareOutputDoesNotOverlapInputs(plan, leftArtifacts, rightArtifacts) {
6939
7416
  const cwd = process.cwd();
6940
7417
  const inputs = mergeVisualCompareInputPaths([
6941
- { kind: "file", path: resolve5(cwd, plan.config) },
6942
- { kind: "file", path: resolve5(cwd, plan.againstConfig) },
7418
+ { kind: "file", path: resolve6(cwd, plan.config) },
7419
+ { kind: "file", path: resolve6(cwd, plan.againstConfig) },
6943
7420
  ...visualCompareArtifactInputPaths(leftArtifacts),
6944
7421
  ...visualCompareArtifactInputPaths(rightArtifacts)
6945
7422
  ]);
@@ -7014,7 +7491,7 @@ function serializeVisualCompareInventory(inventory) {
7014
7491
  `;
7015
7492
  }
7016
7493
  async function readVisualCompareInventory(assetDirectory, inventoryPath, boundary) {
7017
- await assertNoSymlinkComponents(dirname9(inventoryPath), boundary);
7494
+ await assertNoSymlinkComponents(dirname10(inventoryPath), boundary);
7018
7495
  let info;
7019
7496
  try {
7020
7497
  info = await lstat3(inventoryPath);
@@ -7037,8 +7514,8 @@ async function readVisualCompareInventory(assetDirectory, inventoryPath, boundar
7037
7514
  const inventory = validateVisualCompareInventory(parsed);
7038
7515
  const assets = [];
7039
7516
  for (const asset of inventory.assets) {
7040
- const path = resolve5(assetDirectory, asset.path);
7041
- await assertNoSymlinkComponents(dirname9(path), boundary);
7517
+ const path = resolve6(assetDirectory, asset.path);
7518
+ await assertNoSymlinkComponents(dirname10(path), boundary);
7042
7519
  let assetInfo;
7043
7520
  try {
7044
7521
  assetInfo = await lstat3(path);
@@ -7109,17 +7586,17 @@ function sha256Source(source) {
7109
7586
  return createHash3("sha256").update(typeof source === "string" ? Buffer.from(source, "utf8") : Buffer.from(source)).digest("hex");
7110
7587
  }
7111
7588
  async function canonicalPathIdentity(path) {
7112
- const absolute = resolve5(path);
7589
+ const absolute = resolve6(path);
7113
7590
  let current = absolute;
7114
7591
  const missingSegments = [];
7115
7592
  while (true) {
7116
7593
  try {
7117
7594
  const existing = await realpath(current);
7118
- const canonical = resolve5(existing, ...missingSegments.reverse()).normalize("NFC");
7595
+ const canonical = resolve6(existing, ...missingSegments.reverse()).normalize("NFC");
7119
7596
  return process.platform === "win32" ? canonical.toLowerCase() : canonical;
7120
7597
  } catch (error) {
7121
7598
  if (!isMissingPathComponent(error)) throw error;
7122
- const parent = dirname9(current);
7599
+ const parent = dirname10(current);
7123
7600
  if (parent === current) {
7124
7601
  const canonical = absolute.normalize("NFC");
7125
7602
  return process.platform === "win32" ? canonical.toLowerCase() : canonical;
@@ -7191,7 +7668,7 @@ function formatCoordinate(value) {
7191
7668
  return String(Math.round(value * 1e6) / 1e6);
7192
7669
  }
7193
7670
  function portablePathIdentity(path) {
7194
- const normalized = resolve5(path).normalize("NFC");
7671
+ const normalized = resolve6(path).normalize("NFC");
7195
7672
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
7196
7673
  }
7197
7674
  function isInside(parent, child) {
@@ -7304,14 +7781,14 @@ async function runVisualAnalyze(scene, options) {
7304
7781
  validateVisualSelection([scene]);
7305
7782
  const region = options.region === void 0 ? void 0 : parseTileflowVisualRegion(options.region);
7306
7783
  const cwd = process.cwd();
7307
- const referencePath = resolve6(cwd, options.reference);
7784
+ const referencePath = resolve7(cwd, options.reference);
7308
7785
  const referencePng = await readVisualReference(referencePath);
7309
7786
  const referenceDimensions = validateTileflowVisualReferencePng(referencePng);
7310
7787
  if (region) assertTileflowVisualRegionFits(region, referenceDimensions, "reference PNG");
7311
7788
  const outputDirectory = await resolveVisualDirectory(cwd, options.outputDir, "output");
7312
- const actualPath = resolve6(outputDirectory.path, `${scene}.actual.png`);
7313
- const managedDiffPath = resolve6(outputDirectory.path, `${scene}.diff.png`);
7314
- const reportPath = resolve6(outputDirectory.path, `${scene}.analysis.json`);
7789
+ const actualPath = resolve7(outputDirectory.path, `${scene}.actual.png`);
7790
+ const managedDiffPath = resolve7(outputDirectory.path, `${scene}.diff.png`);
7791
+ const reportPath = resolve7(outputDirectory.path, `${scene}.analysis.json`);
7315
7792
  assertReferenceIsReadOnly(referencePath, [actualPath, managedDiffPath, reportPath]);
7316
7793
  const controller = installSignalAbortController();
7317
7794
  const session = createTileflowCaptureSession3({
@@ -7400,15 +7877,15 @@ async function runVisualDiff(scenes, options) {
7400
7877
  capture,
7401
7878
  files.kind === "complete" ? files.baseline : void 0
7402
7879
  );
7403
- const actualPath = resolve6(outputDirectory.path, `${capture.scene}.actual.png`);
7404
- const diffPath = comparison.diffPng ? resolve6(outputDirectory.path, `${capture.scene}.diff.png`) : void 0;
7880
+ const actualPath = resolve7(outputDirectory.path, `${capture.scene}.actual.png`);
7881
+ const diffPath = comparison.diffPng ? resolve7(outputDirectory.path, `${capture.scene}.diff.png`) : void 0;
7405
7882
  prepared.push({
7406
7883
  capture,
7407
7884
  comparison,
7408
7885
  baselinePath: files.pngPath,
7409
7886
  actualPath,
7410
7887
  diffPath,
7411
- reportPath: resolve6(outputDirectory.path, `${capture.scene}.visual.json`)
7888
+ reportPath: resolve7(outputDirectory.path, `${capture.scene}.visual.json`)
7412
7889
  });
7413
7890
  }
7414
7891
  const document = createTileflowVisualDiffJson(prepared, cwd);
@@ -7428,7 +7905,7 @@ async function runVisualDiff(scenes, options) {
7428
7905
  }
7429
7906
  ]),
7430
7907
  removePaths: prepared.flatMap(
7431
- (item) => item.diffPath ? [] : [resolve6(outputDirectory.path, `${item.capture.scene}.diff.png`)]
7908
+ (item) => item.diffPath ? [] : [resolve7(outputDirectory.path, `${item.capture.scene}.diff.png`)]
7432
7909
  )
7433
7910
  });
7434
7911
  if (options.json) {
@@ -7549,7 +8026,7 @@ async function resolvePreviousBaseline(capture, files) {
7549
8026
  }
7550
8027
  }
7551
8028
  async function readBaselineFiles(directory, scene) {
7552
- const pngPath = resolve6(directory.path, `${scene}.png`);
8029
+ const pngPath = resolve7(directory.path, `${scene}.png`);
7553
8030
  const receiptPath = captureReceiptPath(pngPath);
7554
8031
  const [png, receipt] = await Promise.all([
7555
8032
  readOptionalArtifact(pngPath, directory.boundary, tileflowVisualArtifactLimits.maximumPngBytes),
@@ -7564,7 +8041,7 @@ async function readBaselineFiles(directory, scene) {
7564
8041
  return { kind: "complete", pngPath, receiptPath, baseline: { png, receipt } };
7565
8042
  }
7566
8043
  async function readOptionalArtifact(path, boundary, maximumBytes) {
7567
- await assertNoSymlinkComponents(dirname10(path), boundary);
8044
+ await assertNoSymlinkComponents(dirname11(path), boundary);
7568
8045
  let info;
7569
8046
  try {
7570
8047
  info = await lstat4(path);
@@ -7609,12 +8086,12 @@ async function readVisualReference(path) {
7609
8086
  return new Uint8Array(await readFile6(path));
7610
8087
  }
7611
8088
  async function resolveVisualDirectory(cwd, value, kind) {
7612
- const path = resolve6(cwd, value);
8089
+ const path = resolve7(cwd, value);
7613
8090
  if (path === cwd || path === parse2(path).root) {
7614
8091
  throw new Error(`Visual ${kind} directory must be a dedicated subdirectory.`);
7615
8092
  }
7616
8093
  if (kind === "baseline") {
7617
- for (const managed of [resolve6(cwd, ".tileflow/captures"), resolve6(cwd, ".tileflow/diffs")]) {
8094
+ for (const managed of [resolve7(cwd, ".tileflow/captures"), resolve7(cwd, ".tileflow/diffs")]) {
7618
8095
  if (pathsOverlap2(path, managed)) {
7619
8096
  throw new Error("Visual baselines must not overlap Tileflow-managed capture/diff outputs.");
7620
8097
  }
@@ -7650,7 +8127,7 @@ function assertReferenceIsReadOnly(referencePath, outputPaths) {
7650
8127
  }
7651
8128
  }
7652
8129
  function portablePathIdentity2(path) {
7653
- return resolve6(path).normalize("NFC").toLowerCase();
8130
+ return resolve7(path).normalize("NFC").toLowerCase();
7654
8131
  }
7655
8132
  function isInside2(parent, child) {
7656
8133
  const path = relative4(parent, child);
@@ -7669,13 +8146,14 @@ var defaultApiUrl = defaultTileflowApiUrl;
7669
8146
  var defaultAppUrl = "https://tileflow.dev";
7670
8147
  var defaultConfigPath = defaultTileflowConfigPath;
7671
8148
  var defaultManifestPath = defaultTileflowManifestPath;
7672
- program.name("tileflow").description("Beautiful maps from config.").version(packageJson.version).showHelpAfterError(pc6.gray("\nRun tileflow <command> --help for usage.")).showSuggestionAfterError();
8149
+ program.name("tileflow").description("Beautiful maps from config.").showHelpAfterError(pc6.gray("\nRun tileflow <command> --help for usage.")).showSuggestionAfterError();
8150
+ program.addHelpText("after", "\n -V, --version output the version number\n");
7673
8151
  registerLanguageCommand(program);
7674
8152
  registerTilesetCommands(program, { defaultApiUrl, loadAuthConfig });
7675
8153
  registerIconSetCommands(program, { defaultApiUrl, loadAuthConfig });
7676
8154
  program.command("init").description("Create a starter tileflow.config.ts").option("-f, --force", "overwrite an existing config").action(async (options) => {
7677
- const configPath = resolve7(process.cwd(), defaultConfigPath);
7678
- const ignorePath = resolve7(process.cwd(), ".gitignore");
8155
+ const configPath = resolve8(process.cwd(), defaultConfigPath);
8156
+ const ignorePath = resolve8(process.cwd(), ".gitignore");
7679
8157
  if (existsSync(configPath) && !options.force) {
7680
8158
  logWarning(`${pathLabel(defaultConfigPath)} already exists.`);
7681
8159
  printNextSteps([`Run ${command("tileflow init --force")} to replace it.`]);
@@ -7782,15 +8260,22 @@ program.command("whoami").description("Show the authenticated Tileflow account")
7782
8260
  logSuccess("Tileflow CLI is authenticated.");
7783
8261
  printAccountDetails(selected.session);
7784
8262
  });
7785
- program.command("validate").description("Validate a Tileflow config").option("-c, --config <path>", "config path", defaultConfigPath).option("--target <target>", "validation target: local or hosted", "local").option(
8263
+ program.command("validate").description("Validate a Tileflow config").option("-c, --config <path>", "config path", defaultConfigPath).option("--target <target>", "validation target: local or hosted", "local").option("--renderer <renderer>", "artifact renderer: web or native", "web").option(
7786
8264
  "--api-base-url <url>",
7787
8265
  "Tileflow API base URL used to resolve official map assets",
7788
8266
  process.env.TILEFLOW_API_URL ?? defaultApiUrl
7789
8267
  ).option("--cache-dir <path>", "verified Icon Set artifact cache root").option("--offline", "fail a locked Icon Set cache miss instead of hydrating it").option("--json", "print deterministic schema-version-1 JSON").action(
7790
8268
  async (options) => {
8269
+ if (options.renderer !== "web") {
8270
+ await runRendererArtifactCommand("validate", {
8271
+ ...options,
8272
+ icons: resolveIconOptions(options)
8273
+ });
8274
+ return;
8275
+ }
7791
8276
  if (options.target !== "local" && options.target !== "hosted") {
7792
8277
  if (options.json) {
7793
- const failure = createTileflowCommandFailureDocument4(
8278
+ const failure2 = createTileflowCommandFailureDocument5(
7794
8279
  "validate",
7795
8280
  {
7796
8281
  code: "INVALID_TARGET",
@@ -7807,7 +8292,7 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7807
8292
  process.cwd(),
7808
8293
  { code: "INVALID_TARGET", phase: "command-validation" }
7809
8294
  );
7810
- process.stderr.write(serializeTileflowCommandDocument4(failure));
8295
+ process.stderr.write(serializeTileflowCommandDocument5(failure2));
7811
8296
  process.exitCode = 1;
7812
8297
  return;
7813
8298
  }
@@ -7822,15 +8307,15 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7822
8307
  try {
7823
8308
  if (!options.json) logInfo(`Validating ${pathLabel(options.config)}.`);
7824
8309
  const loaded = await withTileflowConfigSecretsHidden(
7825
- () => loadTileflowConfigWithInputs3(options.config)
8310
+ () => loadTileflowConfigWithInputs4(options.config)
7826
8311
  );
7827
8312
  const project = loaded.project;
7828
- const baseDirectory = dirname11(loaded.configFile);
8313
+ const baseDirectory = dirname12(loaded.configFile);
7829
8314
  failureDefaults = { code: "CONFIG_INVALID", phase: "config-validation" };
7830
- assertValidTileflowConfig2(project);
7831
- const mapNames = getTileflowMapNames4(project).sort();
8315
+ assertValidTileflowConfig3(project);
8316
+ const mapNames = getTileflowMapNames5(project).sort();
7832
8317
  failureDefaults = { code: "ICON_COMPILATION_FAILED", phase: "icon-compilation" };
7833
- const compiledIcons = await compileTileflowIconPackages2(project, {
8318
+ const compiledIcons = await compileTileflowIconPackages3(project, {
7834
8319
  baseDirectory,
7835
8320
  cwd: process.cwd(),
7836
8321
  icons: resolveIconOptions(options),
@@ -7841,18 +8326,18 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7841
8326
  (binding) => options.target === "hosted" ? `${normalizeUrl(options.apiBaseUrl)}/sprites/preflight/${binding.packageHash}/sprite` : `/tileflow/icons/${binding.mapName}/sprite`
7842
8327
  );
7843
8328
  failureDefaults = { code: "STYLE_INVALID", phase: "style-validation" };
7844
- const compiledStyles = createTileflowStyles(project, {
8329
+ const compiledStyles = createTileflowStyles2(project, {
7845
8330
  apiBaseUrl: options.apiBaseUrl,
7846
8331
  mapAssets
7847
8332
  });
7848
8333
  failureDefaults = { code: "TF_LOCAL_TILESET_INVALID", phase: "local-tileset-resolution" };
7849
- const localTilesets = await prepareTileflowLocalTilesets(project, compiledStyles, {
8334
+ const localTilesets = await prepareTileflowLocalTilesets2(project, compiledStyles, {
7850
8335
  assetBaseUrl: "/tileflow",
7851
8336
  baseDirectory,
7852
8337
  cwd: process.cwd()
7853
8338
  });
7854
8339
  failureDefaults = { code: "FONT_COMPILATION_FAILED", phase: "font-compilation" };
7855
- const { styles } = await prepareTileflowStyleFonts(project, localTilesets.styles, {
8340
+ const { styles } = await prepareTileflowStyleFonts2(project, localTilesets.styles, {
7856
8341
  assetBaseUrl: "/tileflow",
7857
8342
  baseDirectory,
7858
8343
  cwd: process.cwd(),
@@ -7877,11 +8362,11 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7877
8362
  });
7878
8363
  }
7879
8364
  const themeWarnings = mapNames.flatMap(
7880
- (mapName) => auditTileflowMapThemeValues(project.maps[mapName]).filter(
8365
+ (mapName) => auditTileflowMapThemeValues2(project.maps[mapName]).filter(
7881
8366
  ({ severity }) => severity === "warning"
7882
8367
  )
7883
8368
  );
7884
- const diagnostics = themeWarnings.length === 0 ? [] : createTileflowStructuredDiagnostics2({ diagnostics: themeWarnings }, process.cwd(), {
8369
+ const diagnostics = themeWarnings.length === 0 ? [] : createTileflowStructuredDiagnostics3({ diagnostics: themeWarnings }, process.cwd(), {
7885
8370
  code: "VALIDATION_WARNING",
7886
8371
  phase: "theme-audit"
7887
8372
  });
@@ -7896,7 +8381,7 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7896
8381
  ...options.target === "hosted" ? ["Hosted compatibility"] : []
7897
8382
  ];
7898
8383
  if (options.json) {
7899
- const summary = createTileflowCommandSummary2({
8384
+ const summary = createTileflowCommandSummary3({
7900
8385
  code: "VALIDATION_OK",
7901
8386
  command: "validate",
7902
8387
  message: `Tileflow config is valid (${plural(mapNames.length, "map")}).`,
@@ -7907,7 +8392,7 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7907
8392
  suggestion: "No changes are required."
7908
8393
  });
7909
8394
  process.stdout.write(
7910
- serializeTileflowCommandDocument4({
8395
+ serializeTileflowCommandDocument5({
7911
8396
  ...summary,
7912
8397
  target: options.target,
7913
8398
  maps: mapNames,
@@ -7924,25 +8409,29 @@ program.command("validate").description("Validate a Tileflow config").option("-c
7924
8409
  }
7925
8410
  } catch (error) {
7926
8411
  if (!options.json) throw error;
7927
- const failure = createTileflowCommandFailureDocument4(
8412
+ const failure2 = createTileflowCommandFailureDocument5(
7928
8413
  "validate",
7929
8414
  error,
7930
8415
  process.cwd(),
7931
8416
  failureDefaults
7932
8417
  );
7933
- process.stderr.write(serializeTileflowCommandDocument4(failure));
8418
+ process.stderr.write(serializeTileflowCommandDocument5(failure2));
7934
8419
  process.exitCode = 1;
7935
8420
  }
7936
8421
  }
7937
8422
  );
7938
- program.command("build").description("Generate static Tileflow styles").option("-c, --config <path>", "config path", defaultConfigPath).option("-o, --out <path>", "output directory", "dist/tileflow").option(
8423
+ program.command("build").description("Generate static Tileflow styles").option("-c, --config <path>", "config path", defaultConfigPath).option("-o, --out <path>", "output directory", "dist/tileflow").option("--renderer <renderer>", "artifact renderer: web or native", "web").option("--target <target>", "artifact target: local or hosted (build supports local)", "local").option("--json", "print deterministic schema-version-1 JSON").option(
7939
8424
  "--api-base-url <url>",
7940
8425
  "Tileflow API base URL used to resolve official map assets",
7941
8426
  process.env.TILEFLOW_API_URL ?? defaultApiUrl
7942
8427
  ).option("--cache-dir <path>", "verified Icon Set artifact cache root").option("--offline", "fail a locked Icon Set cache miss instead of hydrating it").action(
7943
8428
  async (options) => {
7944
- logInfo(`Building ${pathLabel(options.config)}.`);
7945
8429
  const icons = resolveIconOptions(options);
8430
+ if (options.renderer !== "web" || options.target !== "local" || options.json) {
8431
+ await runRendererArtifactCommand("build", { ...options, icons });
8432
+ return;
8433
+ }
8434
+ logInfo(`Building ${pathLabel(options.config)}.`);
7946
8435
  await withTileflowConfigSecretsHidden(
7947
8436
  () => writeTileflowBuildArtifacts({
7948
8437
  config: options.config,
@@ -7953,15 +8442,62 @@ program.command("build").description("Generate static Tileflow styles").option("
7953
8442
  })
7954
8443
  );
7955
8444
  logSuccess("Built Tileflow artifacts.");
7956
- printKeyValue("Output", pathLabel(resolve7(process.cwd(), options.out)));
8445
+ printKeyValue("Output", pathLabel(resolve8(process.cwd(), options.out)));
7957
8446
  }
7958
8447
  );
7959
- program.command("preview").alias("dev").description("Run a local map preview").option("-c, --config <path>", "config path", defaultConfigPath).option("--against-config <path>", "second config for the comparison workbench").option("--against-map <name>", "map on the right; defaults to --map").option("--against-scene <name>", "committed standalone scene on the right").option("--against-theme <name>", "concrete theme on the right; defaults to --theme").option("--host <host>", "bind host: an explicit IP address or localhost", defaultTileflowDevHost).option("--map <name>", "preview one configured map").option("--theme <name>", "preview one concrete theme; defaults to the map default").option("-p, --port <port>", "preview port", "3333").option("--scene <name>", "preview one committed standalone map scene").option(
8448
+ program.command("preview").alias("dev").description("Run a local map preview").option("-c, --config <path>", "config path", defaultConfigPath).option("--against-config <path>", "second config for the comparison workbench").option("--against-map <name>", "map on the right; defaults to --map").option("--against-scene <name>", "committed standalone scene on the right").option("--against-theme <name>", "concrete theme on the right; defaults to --theme").option("--host <host>", "bind host: an explicit IP address or localhost", defaultTileflowDevHost).option("--map <name>", "preview one configured map").option("--theme <name>", "preview one concrete theme; defaults to the map default").option("--renderer <renderer>", "artifact renderer: web or native", "web").option("-p, --port <port>", "preview port", "3333").option("--scene <name>", "preview one committed standalone map scene").option(
7960
8449
  "--api-base-url <url>",
7961
8450
  "Tileflow API base URL used to resolve official map assets",
7962
8451
  process.env.TILEFLOW_API_URL ?? defaultApiUrl
7963
8452
  ).option("--cache-dir <path>", "verified Icon Set artifact cache root").option("--offline", "fail a locked Icon Set cache miss instead of hydrating it").option("--json", "emit schema-version-1 NDJSON lifecycle events").action(
7964
8453
  async (options) => {
8454
+ let renderer;
8455
+ try {
8456
+ renderer = resolveTileflowRenderer2(options.renderer);
8457
+ } catch (error) {
8458
+ const diagnostics = createTileflowArtifactDiagnostics3(error, process.cwd());
8459
+ if (options.json) {
8460
+ const first = diagnostics[0];
8461
+ process.stdout.write(
8462
+ `${JSON.stringify({
8463
+ schemaVersion: 1,
8464
+ command: "dev",
8465
+ event: "error",
8466
+ code: first?.code ?? "NATIVE_RENDERER_UNSUPPORTED",
8467
+ phase: first?.phase ?? "command-validation",
8468
+ diagnostics
8469
+ })}
8470
+ `
8471
+ );
8472
+ } else {
8473
+ logError(diagnostics[0]?.message ?? "Unsupported artifact renderer.");
8474
+ }
8475
+ process.exitCode = 1;
8476
+ return;
8477
+ }
8478
+ const comparisonRequested = options.againstConfig !== void 0 || options.againstMap !== void 0 || options.againstScene !== void 0 || options.againstTheme !== void 0;
8479
+ if (renderer === "native" && (options.scene !== void 0 || comparisonRequested)) {
8480
+ if (options.json) {
8481
+ process.stdout.write(
8482
+ `${JSON.stringify({
8483
+ schemaVersion: 1,
8484
+ command: "dev",
8485
+ event: "error",
8486
+ code: "NATIVE_RENDERER_UNSUPPORTED",
8487
+ phase: "command-validation",
8488
+ renderer: "native",
8489
+ profile: tileflowNativePreviewProfile
8490
+ })}
8491
+ `
8492
+ );
8493
+ } else {
8494
+ logError(
8495
+ "Native preview serves assets only; scenes and comparison workbench options are unavailable."
8496
+ );
8497
+ }
8498
+ process.exitCode = 1;
8499
+ return;
8500
+ }
7965
8501
  const port = parsePort(options.port);
7966
8502
  if (port === null) {
7967
8503
  logError(`Invalid port: ${options.port}`);
@@ -8006,30 +8542,45 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8006
8542
  process.exitCode = 1;
8007
8543
  return;
8008
8544
  }
8009
- const comparisonRequested = options.againstConfig !== void 0 || options.againstMap !== void 0 || options.againstScene !== void 0 || options.againstTheme !== void 0;
8010
8545
  if (comparisonRequested) {
8011
8546
  await runTileflowComparisonPreview(options, { host, port });
8012
8547
  return;
8013
8548
  }
8014
8549
  await withTileflowConfigSecretsHidden(async () => {
8015
8550
  const origin = tileflowDevOrigin(host, port);
8551
+ const manifestUrl = renderer === "native" ? getTileflowNativePreviewManifestUrl(origin) : void 0;
8552
+ const nativeLifecycleFields = manifestUrl ? {
8553
+ renderer: "native",
8554
+ profile: tileflowNativePreviewProfile,
8555
+ manifest: manifestUrl,
8556
+ assetsOnly: true
8557
+ } : {};
8016
8558
  const icons = resolveIconOptions(options);
8017
8559
  const session = await createTileflowArtifactSession3({
8018
8560
  assetBaseUrl: origin,
8019
8561
  apiBaseUrl: options.apiBaseUrl,
8020
8562
  config: options.config,
8021
8563
  ...icons ? { icons } : {},
8564
+ ...renderer === "native" ? { renderer: "native" } : {},
8022
8565
  styleBaseUrl: origin,
8023
8566
  watch: true
8024
8567
  });
8025
8568
  const initialArtifacts = session.getLastGoodArtifacts();
8569
+ let nativeSelection;
8026
8570
  try {
8027
8571
  if (initialArtifacts) {
8028
- resolveTileflowPreview(initialArtifacts.project, {
8029
- map: options.map,
8030
- scene: options.scene,
8031
- theme: options.theme
8032
- });
8572
+ if (renderer === "native") {
8573
+ nativeSelection = resolveTileflowNativePreviewSelection(initialArtifacts.manifest, {
8574
+ map: options.map,
8575
+ theme: options.theme
8576
+ });
8577
+ } else {
8578
+ resolveTileflowPreview(initialArtifacts.project, {
8579
+ map: options.map,
8580
+ scene: options.scene,
8581
+ theme: options.theme
8582
+ });
8583
+ }
8033
8584
  }
8034
8585
  } catch (error) {
8035
8586
  await session.close();
@@ -8037,7 +8588,12 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8037
8588
  process.exitCode = 1;
8038
8589
  return;
8039
8590
  }
8040
- const fetch2 = createTileflowDevRequestHandler({
8591
+ const fetch2 = renderer === "native" ? createTileflowNativePreviewRequestHandler({
8592
+ config: options.config,
8593
+ apiBaseUrl: options.apiBaseUrl,
8594
+ onError: printTileflowPreviewError,
8595
+ session
8596
+ }) : createTileflowDevRequestHandler2({
8041
8597
  config: options.config,
8042
8598
  apiBaseUrl: options.apiBaseUrl,
8043
8599
  map: options.map,
@@ -8062,7 +8618,8 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8062
8618
  ..."lastGoodGeneration" in state && state.lastGoodGeneration !== void 0 ? { lastGoodGeneration: state.lastGoodGeneration } : {},
8063
8619
  ...firstDiagnostic?.code ? { code: firstDiagnostic.code } : {},
8064
8620
  ...firstDiagnostic?.phase ? { phase: firstDiagnostic.phase } : {},
8065
- ...state.status === "invalid" ? { diagnostics: state.diagnostics } : {}
8621
+ ...state.status === "invalid" ? { diagnostics: state.diagnostics } : {},
8622
+ ...nativeLifecycleFields
8066
8623
  })}
8067
8624
  `
8068
8625
  );
@@ -8071,14 +8628,16 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8071
8628
  if (state.status === "invalid") {
8072
8629
  console.error(
8073
8630
  [
8074
- `Tileflow generation ${state.generation} is invalid; preserving the last valid preview.`,
8631
+ renderer === "native" ? `Tileflow generation ${state.generation} is invalid; preserving the last valid native artifact family.` : `Tileflow generation ${state.generation} is invalid; preserving the last valid preview.`,
8075
8632
  ...state.diagnostics.map(
8076
8633
  (diagnostic) => `- ${diagnostic.path || "(root)"}: ${diagnostic.message}`
8077
8634
  )
8078
8635
  ].join("\n")
8079
8636
  );
8080
8637
  } else if (recovered) {
8081
- logSuccess(`Tileflow preview recovered at generation ${state.generation}.`);
8638
+ logSuccess(
8639
+ renderer === "native" ? `Tileflow native artifact preview recovered at generation ${state.generation}.` : `Tileflow preview recovered at generation ${state.generation}.`
8640
+ );
8082
8641
  }
8083
8642
  };
8084
8643
  emitState(session.getState());
@@ -8091,13 +8650,26 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8091
8650
  server = createdServer;
8092
8651
  });
8093
8652
  if (!options.json) {
8094
- logSuccess("Tileflow preview is running and watching for changes.");
8095
- printKeyValue("Local", link(origin));
8096
- printKeyValue("Config", pathLabel(options.config));
8097
- if (options.map) printKeyValue("Map", options.map);
8098
- if (options.theme) printKeyValue("Theme", options.theme);
8099
- if (options.scene) printKeyValue("Scene", options.scene);
8100
- logMuted("Press Ctrl+C to stop.");
8653
+ if (renderer === "native") {
8654
+ logSuccess("Tileflow native artifact preview is running and watching for changes.");
8655
+ printKeyValue("Manifest", link(manifestUrl));
8656
+ printKeyValue("Profile", tileflowNativePreviewProfile);
8657
+ printKeyValue("Endpoint", "assets-only");
8658
+ printKeyValue("Config", pathLabel(options.config));
8659
+ if (nativeSelection) {
8660
+ printKeyValue("Map", nativeSelection.mapName);
8661
+ printKeyValue("Theme", nativeSelection.themeName);
8662
+ }
8663
+ logMuted("Metro remains the JavaScript development server. Press Ctrl+C to stop.");
8664
+ } else {
8665
+ logSuccess("Tileflow preview is running and watching for changes.");
8666
+ printKeyValue("Local", link(origin));
8667
+ printKeyValue("Config", pathLabel(options.config));
8668
+ if (options.map) printKeyValue("Map", options.map);
8669
+ if (options.theme) printKeyValue("Theme", options.theme);
8670
+ if (options.scene) printKeyValue("Scene", options.scene);
8671
+ logMuted("Press Ctrl+C to stop.");
8672
+ }
8101
8673
  }
8102
8674
  await waitForTerminationSignal(server);
8103
8675
  } finally {
@@ -8107,7 +8679,13 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8107
8679
  await session.close();
8108
8680
  if (options.json) {
8109
8681
  process.stdout.write(
8110
- `${JSON.stringify({ schemaVersion: 1, command: "dev", event: "stopped", generation })}
8682
+ `${JSON.stringify({
8683
+ schemaVersion: 1,
8684
+ command: "dev",
8685
+ event: "stopped",
8686
+ generation,
8687
+ ...nativeLifecycleFields
8688
+ })}
8111
8689
  `
8112
8690
  );
8113
8691
  }
@@ -8115,7 +8693,7 @@ program.command("preview").alias("dev").description("Run a local map preview").o
8115
8693
  });
8116
8694
  }
8117
8695
  );
8118
- program.command("deploy").description("Deploy maps to Tileflow and write the frontend manifest").option("-c, --config <path>", "config path", defaultConfigPath).option("--manifest <path>", "manifest path written for frontend bundlers", defaultManifestPath).option("--api-url <url>", "Tileflow API URL", process.env.TILEFLOW_API_URL).option("--api-key <key>", "Tileflow API key", process.env.TILEFLOW_API_KEY).option("--map-id <id>", "managed Map destination").option("--map <name>", "configured map to connect when the repository contains multiple maps").option(
8696
+ program.command("deploy").description("Deploy maps to Tileflow and write the frontend manifest").option("-c, --config <path>", "config path", defaultConfigPath).option("--manifest <path>", "manifest path written for frontend bundlers", defaultManifestPath).option("--api-url <url>", "Tileflow API URL", process.env.TILEFLOW_API_URL).option("--api-key <key>", "Tileflow API key", process.env.TILEFLOW_API_KEY).option("--map-id <id>", "managed Map destination").option("--with-native", "publish web and native-v1 together for the selected managed Map").option("--map <name>", "configured map to connect when the repository contains multiple maps").option(
8119
8697
  "--overwrite-self-hosted-manifest",
8120
8698
  "explicitly replace an existing self-hosted manifest at --manifest"
8121
8699
  ).option("--cache-dir <path>", "verified Icon Set artifact cache root").option("--offline", "fail a locked Icon Set cache miss instead of hydrating it").action(
@@ -8136,19 +8714,39 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8136
8714
  options.apiUrl ?? defaultApiUrl,
8137
8715
  ...options.overwriteSelfHostedManifest ? ["--overwrite-self-hosted-manifest"] : [],
8138
8716
  ...options.mapId ? ["--map-id", options.mapId] : [],
8139
- ...options.map && selectedMap ? ["--map", selectedMap] : []
8717
+ ...options.map && selectedMap ? ["--map", selectedMap] : [],
8718
+ ...options.withNative ? ["--with-native"] : []
8140
8719
  ])
8141
8720
  });
8142
8721
  const apiUrl = normalizeApiOrigin(options.apiUrl ?? defaultApiUrl);
8143
8722
  delete process.env.TILEFLOW_API_KEY;
8723
+ if (options.withNative) {
8724
+ const result = await runHostedNativeDeploy(
8725
+ { ...options, apiUrl },
8726
+ {
8727
+ source,
8728
+ resolveApi,
8729
+ loadManifest: loadExistingDeployManifest,
8730
+ writeManifest: writeDeployManifest
8731
+ }
8732
+ );
8733
+ if (result) {
8734
+ logSuccess(
8735
+ `${result.changed ? "Published" : "Unchanged"} ${pc6.bold(result.mapName)} web + native-v1 (v${result.version}).`
8736
+ );
8737
+ printKeyValue("Manifest", pathLabel(result.manifestPath));
8738
+ printKeyValue("Native", link(result.nativeManifestUrl));
8739
+ }
8740
+ return;
8741
+ }
8144
8742
  logInfo(`Deploying ${pathLabel(options.config)}.`);
8145
8743
  const loaded = await withTileflowConfigSecretsHidden(
8146
- () => loadTileflowConfigWithInputs3(options.config)
8744
+ () => loadTileflowConfigWithInputs4(options.config)
8147
8745
  );
8148
8746
  const project = loaded.project;
8149
- const baseDirectory = dirname11(loaded.configFile);
8150
- assertValidTileflowConfig2(project);
8151
- const configuredMapNames = getTileflowMapNames4(project);
8747
+ const baseDirectory = dirname12(loaded.configFile);
8748
+ assertValidTileflowConfig3(project);
8749
+ const configuredMapNames = getTileflowMapNames5(project);
8152
8750
  const mapNames = selectManagedDeployMaps(configuredMapNames, options);
8153
8751
  if (!mapNames) return;
8154
8752
  if (!validateDeployTarget(options)) return;
@@ -8159,7 +8757,7 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8159
8757
  mapNames.map((mapName) => [mapName, project.maps[mapName]])
8160
8758
  )
8161
8759
  };
8162
- const compiledIcons = await compileTileflowIconPackages2(deploymentProject, {
8760
+ const compiledIcons = await compileTileflowIconPackages3(deploymentProject, {
8163
8761
  baseDirectory,
8164
8762
  cwd: process.cwd(),
8165
8763
  icons: resolveIconOptions(options),
@@ -8175,16 +8773,16 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8175
8773
  compiledIcons,
8176
8774
  (binding) => `${apiUrl}/sprites/preflight/${binding.packageHash}/sprite`
8177
8775
  );
8178
- const compiledPreflightStyles = createTileflowStyles(deploymentProject, {
8776
+ const compiledPreflightStyles = createTileflowStyles2(deploymentProject, {
8179
8777
  apiBaseUrl: apiUrl,
8180
8778
  mapAssets: preflightMapAssets
8181
8779
  });
8182
- const preflightLocalTilesets = await prepareTileflowLocalTilesets(
8780
+ const preflightLocalTilesets = await prepareTileflowLocalTilesets2(
8183
8781
  deploymentProject,
8184
8782
  compiledPreflightStyles,
8185
8783
  { assetBaseUrl: apiUrl, baseDirectory, cwd: process.cwd() }
8186
8784
  );
8187
- const preflightFonts = await prepareTileflowStyleFonts(
8785
+ const preflightFonts = await prepareTileflowStyleFonts2(
8188
8786
  deploymentProject,
8189
8787
  preflightLocalTilesets.styles,
8190
8788
  {
@@ -8252,16 +8850,16 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8252
8850
  if (!sprite) throw new Error(`Missing hosted sprite URL for map ${binding.mapName}`);
8253
8851
  return sprite;
8254
8852
  });
8255
- const compiledHostedStyles = createTileflowStyles(deploymentProject, {
8853
+ const compiledHostedStyles = createTileflowStyles2(deploymentProject, {
8256
8854
  apiBaseUrl: api.apiUrl,
8257
8855
  mapAssets: hostedMapAssets
8258
8856
  });
8259
- const hostedLocalTilesets = await prepareTileflowLocalTilesets(
8857
+ const hostedLocalTilesets = await prepareTileflowLocalTilesets2(
8260
8858
  deploymentProject,
8261
8859
  compiledHostedStyles,
8262
8860
  { assetBaseUrl: api.apiUrl, baseDirectory, cwd: process.cwd() }
8263
8861
  );
8264
- const hostedFonts = await prepareTileflowStyleFonts(
8862
+ const hostedFonts = await prepareTileflowStyleFonts2(
8265
8863
  deploymentProject,
8266
8864
  hostedLocalTilesets.styles,
8267
8865
  {
@@ -8326,7 +8924,7 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8326
8924
  const styles = Object.fromEntries(
8327
8925
  Object.entries(hostedThemeFamilies).map(([mapName, family]) => [mapName, family.styles])
8328
8926
  );
8329
- const buildManifest = await createTileflowMapBuildManifest(
8927
+ const buildManifest = await createTileflowMapBuildManifest2(
8330
8928
  Object.fromEntries(
8331
8929
  mapNames.map((mapName) => {
8332
8930
  const map = deploymentProject.maps[mapName];
@@ -8357,7 +8955,7 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8357
8955
  ];
8358
8956
  })
8359
8957
  ),
8360
- { provenance: await createTileflowBuildProvenance(process.cwd()) }
8958
+ { provenance: await createTileflowBuildProvenance2(process.cwd()) }
8361
8959
  );
8362
8960
  const deployments = mapNames.map((mapName) => {
8363
8961
  const iconBinding = bindingsByMap.get(mapName);
@@ -8448,7 +9046,7 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8448
9046
  process.exitCode = 1;
8449
9047
  return;
8450
9048
  }
8451
- const resolvedMap = parseResolvedTileflowMap4(deploymentProject.maps[mapName]);
9049
+ const resolvedMap = parseResolvedTileflowMap5(deploymentProject.maps[mapName]);
8452
9050
  const mapBuild = buildManifest2.maps[mapName];
8453
9051
  deployedMaps[mapName] = {
8454
9052
  defaultTheme: resolvedMap.defaultTheme,
@@ -8458,7 +9056,7 @@ program.command("deploy").description("Deploy maps to Tileflow and write the fro
8458
9056
  themes: Object.fromEntries(
8459
9057
  themeNames.map((themeName) => {
8460
9058
  const deployedTheme = body.themes[themeName];
8461
- const fontFaces = getTileflowStyleFontFaces(themeStyles[themeName]);
9059
+ const fontFaces = getTileflowStyleFontFaces2(themeStyles[themeName]);
8462
9060
  return [
8463
9061
  themeName,
8464
9062
  {
@@ -8595,10 +9193,15 @@ registerProjectCommands(program, {
8595
9193
  defaultApiUrl,
8596
9194
  loadAuthConfig
8597
9195
  });
8598
- program.parseAsync().catch((error) => {
8599
- printCliError(error);
8600
- process.exitCode = 1;
8601
- });
9196
+ if (isRootCliVersionRequest(process.argv.slice(2))) {
9197
+ process.stdout.write(`${packageJson.version}
9198
+ `);
9199
+ } else {
9200
+ program.parseAsync().catch((error) => {
9201
+ printCliError(error);
9202
+ process.exitCode = 1;
9203
+ });
9204
+ }
8602
9205
  async function runTileflowComparisonPreview(options, address) {
8603
9206
  await withTileflowConfigSecretsHidden(async () => {
8604
9207
  const origin = tileflowDevOrigin(address.host, address.port);
@@ -8702,7 +9305,7 @@ async function runTileflowComparisonPreview(options, address) {
8702
9305
  scene: rightScene,
8703
9306
  theme: rightTheme
8704
9307
  });
8705
- const leftHandler = createTileflowDevRequestHandler({
9308
+ const leftHandler = createTileflowDevRequestHandler2({
8706
9309
  apiBaseUrl: options.apiBaseUrl,
8707
9310
  basePath: leftBasePath,
8708
9311
  config: options.config,
@@ -8712,7 +9315,7 @@ async function runTileflowComparisonPreview(options, address) {
8712
9315
  session: leftSession,
8713
9316
  theme: options.theme
8714
9317
  });
8715
- const rightHandler = createTileflowDevRequestHandler({
9318
+ const rightHandler = createTileflowDevRequestHandler2({
8716
9319
  apiBaseUrl: options.apiBaseUrl,
8717
9320
  basePath: rightBasePath,
8718
9321
  config: rightConfig,
@@ -8783,8 +9386,8 @@ async function runTileflowComparisonPreview(options, address) {
8783
9386
  }
8784
9387
  function comparisonCaptureConfigArgument(configPath) {
8785
9388
  const cwd = realpathSync(process.cwd());
8786
- const requestedConfigPath = resolve7(process.cwd(), configPath);
8787
- const defaultRequestedPath = resolve7(process.cwd(), defaultConfigPath);
9389
+ const requestedConfigPath = resolve8(process.cwd(), configPath);
9390
+ const defaultRequestedPath = resolve8(process.cwd(), defaultConfigPath);
8788
9391
  const absoluteConfigPath = existsSync(requestedConfigPath) ? realpathSync(requestedConfigPath) : requestedConfigPath;
8789
9392
  const absoluteDefaultPath = existsSync(defaultRequestedPath) ? realpathSync(defaultRequestedPath) : defaultRequestedPath;
8790
9393
  if (absoluteConfigPath === absoluteDefaultPath) return void 0;
@@ -8889,9 +9492,9 @@ function openBrowser(url, errorsToStderr = false) {
8889
9492
  });
8890
9493
  }
8891
9494
  async function writeDeployManifest(manifestPath, manifest) {
8892
- const outputPath = resolve7(process.cwd(), manifestPath);
9495
+ const outputPath = resolve8(process.cwd(), manifestPath);
8893
9496
  await writeAtomicFile({
8894
- boundaryPath: dirname11(outputPath),
9497
+ boundaryPath: dirname12(outputPath),
8895
9498
  force: true,
8896
9499
  label: "Deploy manifest",
8897
9500
  managed: true,
@@ -8912,7 +9515,13 @@ function createCompiledMapAssets(compiled, resolveSprite) {
8912
9515
  return Object.fromEntries(
8913
9516
  compiled.bindings.map((binding) => [
8914
9517
  binding.mapName,
8915
- { icons: { ids: binding.iconIds, sprite: resolveSprite(binding) } }
9518
+ {
9519
+ icons: {
9520
+ ids: binding.iconIds,
9521
+ sprite: resolveSprite(binding),
9522
+ ...binding.appearances ? { appearances: binding.appearances } : {}
9523
+ }
9524
+ }
8916
9525
  ])
8917
9526
  );
8918
9527
  }
@@ -8969,7 +9578,7 @@ function validateDeployManifestMapNames(mapNames) {
8969
9578
  async function loadExistingDeployManifest(manifestPath, options) {
8970
9579
  let source;
8971
9580
  try {
8972
- source = await readFile7(resolve7(process.cwd(), manifestPath), "utf8");
9581
+ source = await readFile7(resolve8(process.cwd(), manifestPath), "utf8");
8973
9582
  } catch (error) {
8974
9583
  if (error.code === "ENOENT") return null;
8975
9584
  throw new Error("Existing Tileflow manifest could not be read.");
@@ -8983,7 +9592,7 @@ async function loadExistingDeployManifest(manifestPath, options) {
8983
9592
  }
8984
9593
  let manifest;
8985
9594
  try {
8986
- manifest = parseTileflowRuntimeManifest(value);
9595
+ manifest = parseTileflowRuntimeManifest2(value);
8987
9596
  } catch {
8988
9597
  throw new Error(
8989
9598
  "Existing Tileflow manifest does not match the strict theme manifest contract."