@tileflow/dev 0.1.0-alpha.3 → 0.1.0-alpha.30

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.
Files changed (41) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +201 -5
  3. package/THIRD_PARTY_NOTICES.md +87 -0
  4. package/dist/artifacts.d.ts +265 -0
  5. package/dist/artifacts.js +81 -0
  6. package/dist/chunk-6MGFMKG3.js +284 -0
  7. package/dist/chunk-7C4F6GAX.js +170 -0
  8. package/dist/chunk-A2VTI43Y.js +1824 -0
  9. package/dist/chunk-D4OE4ITL.js +13 -0
  10. package/dist/chunk-KDFTE4Q5.js +156 -0
  11. package/dist/chunk-L56FLV4R.js +3061 -0
  12. package/dist/chunk-ONYQNLNA.js +1108 -0
  13. package/dist/chunk-UTRO4IBQ.js +671 -0
  14. package/dist/chunk-XHJBCVBB.js +241 -0
  15. package/dist/config.d.ts +33 -0
  16. package/dist/config.js +27 -0
  17. package/dist/fonts.d.ts +47 -0
  18. package/dist/fonts.js +16 -0
  19. package/dist/icons.d.ts +337 -0
  20. package/dist/icons.js +39 -0
  21. package/dist/inspect.d.ts +149 -0
  22. package/dist/inspect.js +805 -0
  23. package/dist/preview-assets-MVUJJ5XR.js +148 -0
  24. package/dist/preview.d.ts +71 -0
  25. package/dist/preview.js +4286 -0
  26. package/dist/server.d.ts +82 -0
  27. package/dist/server.js +2094 -0
  28. package/dist/tilesets.d.ts +89 -0
  29. package/dist/tilesets.js +6 -0
  30. package/dist/validation.d.ts +65 -0
  31. package/dist/validation.js +24 -0
  32. package/docs/artifact-lifecycle.md +152 -0
  33. package/docs/bounded-pmtiles-resource-inspection.md +21 -0
  34. package/docs/bounded-vector-feature-inspection.md +100 -0
  35. package/docs/local-comparison-workbench-and-compiler-inspection.md +249 -0
  36. package/docs/native-artifacts.md +285 -0
  37. package/docs/native-icons.md +129 -0
  38. package/docs/structured-config-inspection-and-diagnostics.md +39 -0
  39. package/package.json +77 -13
  40. package/dist/index.d.ts +0 -54
  41. package/dist/index.js +0 -314
@@ -0,0 +1,89 @@
1
+ declare const inspectionLimits: Readonly<{
2
+ maxBytes: 24000000;
3
+ maxDistinctValuesPerField: 256;
4
+ maxFeatures: 20000;
5
+ maxIncludedValueFields: 32;
6
+ maxTiles: 8;
7
+ maxValueLength: 256;
8
+ maxValuesPerField: 16;
9
+ }>;
10
+ type TileCoordinate = Readonly<{
11
+ x: number;
12
+ y: number;
13
+ z: number;
14
+ }>;
15
+ type FieldType = 'Boolean' | 'Number' | 'String';
16
+ type FieldValue = boolean | number | string;
17
+ type TileflowTilesetInspectionWarning = Readonly<{
18
+ code: string;
19
+ message: string;
20
+ path: string;
21
+ }>;
22
+ type TileflowTilesetInspectionV1 = Readonly<{
23
+ schemaVersion: 1;
24
+ contract: Readonly<{
25
+ authority: 'pmtiles-header-and-tilejson-v1';
26
+ attribution?: string;
27
+ bounds: readonly [number, number, number, number];
28
+ center: readonly [number, number, number];
29
+ counts: Readonly<{
30
+ addressedTiles: number;
31
+ declaredTileContents: number | null;
32
+ tileEntries: number;
33
+ }>;
34
+ maxzoom: number;
35
+ minzoom: number;
36
+ sourceLayersDeclared: boolean;
37
+ sourceLayers: readonly Readonly<{
38
+ fieldsDeclared: boolean;
39
+ fields: readonly Readonly<{
40
+ name: string;
41
+ type?: FieldType;
42
+ }>[];
43
+ id: string;
44
+ maxzoom?: number;
45
+ minzoom?: number;
46
+ }>[];
47
+ tileType: 'avif' | 'jpeg' | 'mlt' | 'mvt' | 'png' | 'webp';
48
+ }>;
49
+ observation?: Readonly<{
50
+ authority: 'bounded-mvt-sample-v1';
51
+ featuresRead: number;
52
+ includedValueFields: readonly string[];
53
+ limits: typeof inspectionLimits;
54
+ sourceLayers: readonly Readonly<{
55
+ featuresRead: number;
56
+ fields: readonly Readonly<{
57
+ distinctValuesObserved: number;
58
+ distinctValuesTruncated: boolean;
59
+ featuresMissing: number;
60
+ featuresPresent: number;
61
+ name: string;
62
+ numericRange?: Readonly<{
63
+ max: number;
64
+ min: number;
65
+ }>;
66
+ observedValues?: readonly Readonly<{
67
+ count: number;
68
+ value: FieldValue;
69
+ }>[];
70
+ observedValuesTruncated?: boolean;
71
+ types: readonly FieldType[];
72
+ }>[];
73
+ geometryTypes: readonly string[];
74
+ id: string;
75
+ }>[];
76
+ tiles: readonly TileCoordinate[];
77
+ tilesRead: number;
78
+ truncated: boolean;
79
+ }>;
80
+ warnings: readonly TileflowTilesetInspectionWarning[];
81
+ }>;
82
+ declare function inspectTileflowPmtiles(archivePath: string, options?: {
83
+ includeValues?: readonly string[];
84
+ maximumDirectoryDepth?: number;
85
+ sample?: boolean;
86
+ signal?: AbortSignal;
87
+ }): Promise<TileflowTilesetInspectionV1>;
88
+
89
+ export { type TileflowTilesetInspectionV1, type TileflowTilesetInspectionWarning, inspectTileflowPmtiles };
@@ -0,0 +1,6 @@
1
+ import {
2
+ inspectTileflowPmtiles
3
+ } from "./chunk-ONYQNLNA.js";
4
+ export {
5
+ inspectTileflowPmtiles
6
+ };
@@ -0,0 +1,65 @@
1
+ import { MapLibreStyle } from '@tileflow/core';
2
+
3
+ declare function sanitizeDiagnosticSecrets(value: string): string;
4
+
5
+ type TileflowStyleValidationIssue = {
6
+ map: string;
7
+ message: string;
8
+ path: string;
9
+ };
10
+ declare class TileflowStyleValidationError extends Error {
11
+ readonly code: "STYLE_INVALID";
12
+ readonly issues: TileflowStyleValidationIssue[];
13
+ readonly phase: "style-validation";
14
+ constructor(issues: readonly TileflowStyleValidationIssue[]);
15
+ }
16
+ declare function assertValidTileflowStyle(style: MapLibreStyle, map: string): void;
17
+ declare function validateTileflowStyle(style: MapLibreStyle, map: string): TileflowStyleValidationIssue[];
18
+
19
+ declare const tileflowCommandDocumentSchemaVersion: 1;
20
+ type TileflowDiagnosticSeverity = 'error' | 'info' | 'warning';
21
+ /** Stable, bounded diagnostic contract intended for tools and coding agents. */
22
+ type TileflowStructuredDiagnostic = {
23
+ phase: string;
24
+ code: string;
25
+ /** Semantic compiler domain; a Core diagnostic's owning-module `owner` is reported here. */
26
+ domain?: string;
27
+ path: string;
28
+ /** Semantic compiler target, when the diagnostic applies to one render contribution. */
29
+ target?: string;
30
+ severity: TileflowDiagnosticSeverity;
31
+ message: string;
32
+ suggestion: string;
33
+ renderer?: 'native';
34
+ profile?: 'native-v1';
35
+ };
36
+ type TileflowCommandSummary = TileflowStructuredDiagnostic & {
37
+ schemaVersion: typeof tileflowCommandDocumentSchemaVersion;
38
+ command: string;
39
+ ok: boolean;
40
+ };
41
+ type TileflowCommandFailureDocument = TileflowCommandSummary & {
42
+ ok: false;
43
+ diagnostics: TileflowStructuredDiagnostic[];
44
+ };
45
+ type TileflowDiagnosticDefaults = {
46
+ code: string;
47
+ phase: string;
48
+ severity?: TileflowDiagnosticSeverity;
49
+ };
50
+ declare function createTileflowCommandSummary(input: {
51
+ code: string;
52
+ command: string;
53
+ message: string;
54
+ ok: boolean;
55
+ path?: string;
56
+ phase: string;
57
+ severity: TileflowDiagnosticSeverity;
58
+ suggestion: string;
59
+ }): TileflowCommandSummary;
60
+ /** Convert arbitrary SDK failures to sorted diagnostics without leaking paths, URLs, or secrets. */
61
+ declare function createTileflowStructuredDiagnostics(error: unknown, cwd: string, defaults: TileflowDiagnosticDefaults): TileflowStructuredDiagnostic[];
62
+ declare function createTileflowCommandFailureDocument(command: string, error: unknown, cwd: string, defaults: TileflowDiagnosticDefaults): TileflowCommandFailureDocument;
63
+ declare function serializeTileflowCommandDocument(value: unknown): string;
64
+
65
+ export { type TileflowCommandFailureDocument, type TileflowCommandSummary, type TileflowDiagnosticSeverity, type TileflowStructuredDiagnostic, TileflowStyleValidationError, type TileflowStyleValidationIssue, assertValidTileflowStyle, createTileflowCommandFailureDocument, createTileflowCommandSummary, createTileflowStructuredDiagnostics, sanitizeDiagnosticSecrets, serializeTileflowCommandDocument, tileflowCommandDocumentSchemaVersion, validateTileflowStyle };
@@ -0,0 +1,24 @@
1
+ import {
2
+ createTileflowCommandFailureDocument,
3
+ createTileflowCommandSummary,
4
+ createTileflowStructuredDiagnostics,
5
+ serializeTileflowCommandDocument,
6
+ tileflowCommandDocumentSchemaVersion
7
+ } from "./chunk-XHJBCVBB.js";
8
+ import {
9
+ TileflowStyleValidationError,
10
+ assertValidTileflowStyle,
11
+ sanitizeDiagnosticSecrets,
12
+ validateTileflowStyle
13
+ } from "./chunk-KDFTE4Q5.js";
14
+ export {
15
+ TileflowStyleValidationError,
16
+ assertValidTileflowStyle,
17
+ createTileflowCommandFailureDocument,
18
+ createTileflowCommandSummary,
19
+ createTileflowStructuredDiagnostics,
20
+ sanitizeDiagnosticSecrets,
21
+ serializeTileflowCommandDocument,
22
+ tileflowCommandDocumentSchemaVersion,
23
+ validateTileflowStyle
24
+ };
@@ -0,0 +1,152 @@
1
+ # Artifact lifecycle
2
+
3
+ Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
4
+
5
+ Node utilities used by the Tileflow CLI and build integrations.
6
+
7
+ Most apps should use `tileflow`, `@tileflow/vite`, or `@tileflow/next` directly. Use this
8
+ package when you are building a custom dev server, bundler plugin, or deployment adapter that needs
9
+ to load and compile the single map exported by `tileflow.config.ts`.
10
+
11
+ ```ts
12
+ import {createTileflowBuildArtifacts} from '@tileflow/dev/artifacts';
13
+
14
+ const artifacts = await createTileflowBuildArtifacts({
15
+ config: 'tileflow.config.ts',
16
+ });
17
+
18
+ try {
19
+ // Serve, capture, or write this exact generation.
20
+ } finally {
21
+ await artifacts.dispose?.();
22
+ }
23
+ ```
24
+
25
+ The integration surfaces are deliberately split: use `@tileflow/dev/artifacts` for source
26
+ preparation and production outputs, `@tileflow/dev/server` for HTTP development handling,
27
+ `@tileflow/dev/icons` for icon compilation, `@tileflow/dev/inspect` for safe resolved-config and
28
+ bounded feature inspection, `@tileflow/dev/validation` for structured diagnostics, and
29
+ `@tileflow/dev/preview` only for the local preview contract. The package has no root entry point.
30
+
31
+ Artifact construction is an explicit `source map → resolved map → prepared map → ArtifactPlan`
32
+ pipeline. Map inheritance resolves before its ordered local/package icon and font directories are
33
+ prepared, and before the result reaches the core style compiler. The Node layer may normalize
34
+ the map into an internal build catalog, but that catalog is orchestration state rather than another
35
+ public authoring model. The plan exposes its complete files and observed input graph, so build
36
+ adapters emit and watch the same generation instead of reconstructing either list themselves. Production manifests
37
+ point to content-addressed `generations/<sha256>/...` theme styles and sprites; those immutable files are
38
+ installed before the manifest pointer changes. Stable style paths are
39
+ `styles/<map>/<theme>.json`; every manifest lookup resolves a concrete theme. The disk writer also stages the complete plan,
40
+ records a managed-file inventory, rolls back caught filesystem failures, and removes only stale
41
+ files named by its previous valid inventory. Stable `styles/` and `icons/` paths remain available,
42
+ but generation-consistent consumers resolve maps through `manifest.json`.
43
+
44
+ A local `hostedTileset()` path remains user-owned input. Dev performs bounded header, root-directory,
45
+ and metadata checks, then creates an opaque immutable snapshot under
46
+ `.tileflow/cache/pmtiles-snapshots/v1/`, using copy-on-write cloning when available and a safe copy
47
+ otherwise. It does not hash the complete archive or traverse every leaf directory. Dev and Capture
48
+ read only that snapshot. The current generation and already-started acquisitions retain references;
49
+ a replaced generation accepts no new acquisitions and is collected after its last acquisition.
50
+ The Style-facing path remains `tilesets/<logical-id>.pmtiles` across generations; physical snapshot
51
+ identity stays out of Style JSON. Standalone Capture retains one generation for the complete render.
52
+ Application Capture delegates PMTiles reads to the application's development server, where each
53
+ range request retains its generation until that response is prepared; it does not lease one
54
+ generation for the complete capture. Strong generation ETags make a cached PMTiles read restart if
55
+ current changes between its ranges. Invalid edits keep the prior valid generation.
56
+
57
+ Production writers reject unresolved local PMTiles instead of copying, content-addressing,
58
+ deduplicating, retaining, or publishing them. Production data therefore requires an explicit
59
+ `tileset publish` operation or an application-owned PMTiles location. Managed publication owns its
60
+ separate exhaustive validation and version lifecycle. Startup removes snapshot generations owned
61
+ by dead processes, and symlinked snapshot-store boundaries are rejected.
62
+
63
+ Every plan also emits canonical `build-manifest.json` (schema version 1). For each map it records
64
+ the leaf `mapVersion`, resolved lineage, effective icon/font source identities, semantic compiler ABI, and
65
+ one entry per concrete theme with `colorScheme`, identity, inferred legacy `dataRequirements`,
66
+ multi-source `sourceRequirements`, and `styleSha256`. The multi-source contract records each
67
+ referenced vector source independently and records raster DEM source ID, encoding, and tile size;
68
+ it therefore distinguishes Bathymetry vector bands from optional relief without inventing vector
69
+ fields. `mapRevisionSha256` identifies the effective cartographic definition after `extends`;
70
+ `assetSetSha256` for that map's generated runtime resources. Data requirements are derived from the
71
+ final Style layers and fields rather than copied from a manually maintained allowlist, so disabled
72
+ or overridden modules do not claim data they no longer use. Maps use the single implicit semantic
73
+ compiler; its ABI remains a separate `semanticCompiler: {name, version}` build-manifest axis.
74
+
75
+ The map revision is versioned and domain-separated. It contains the resolved cartographic design,
76
+ semantic language version, effective public module/render-stack design, and effective icon/font
77
+ identities. Map `id`, `name`, editorial `mapVersion`, default `view`, capture `scenes`, package
78
+ SemVer, compiler ABI, local paths, timestamps, generated sprite/font output, and a
79
+ concrete resolution of a floating World selector are deliberately outside it. Changing a shadowed
80
+ ancestor does not change the revision; changing an effective cartographic override or source asset
81
+ does. Lineage and the leaf `mapVersion` remain beside the hash for traceability, and Style JSON owns
82
+ its compiled-output identity. Hosted browser policy is managed outside repository artifacts. The
83
+ top-level `provenance` block records the exact participating Tileflow package versions and the
84
+ nearest package-manager lockfile's format and content hash, without embedding its local path;
85
+ provenance remains outside every map revision. The same portable block is available to Hosted
86
+ adapters through
87
+ `createTileflowBuildProvenance(cwd)`. The dev server exposes the complete document at
88
+ `/build-manifest.json`.
89
+
90
+ `createTileflowStyle`, `createTileflowStyles`, and artifact construction all enforce the same
91
+ recursive JSON-value invariant and MapLibre style-spec semantics without fetching remote resources.
92
+ The family API returns `styles[map][theme]`; it never flattens a default theme into a map alias.
93
+ Invalid output throws `TileflowStyleValidationError` with at most 32 deterministic
94
+ `map`/`path`/`message` issues; layer indexes are projected to stable layer IDs.
95
+
96
+ For a watched, last-known-good integration, use one artifact session rather than recompiling each
97
+ request independently:
98
+
99
+ ```ts
100
+ import {createTileflowArtifactSession} from '@tileflow/dev/artifacts';
101
+
102
+ const session = await createTileflowArtifactSession({
103
+ config: 'tileflow.config.ts',
104
+ watch: true,
105
+ });
106
+
107
+ const unsubscribe = session.subscribe((state) => {
108
+ // building -> ready, or invalid while getLastGoodArtifacts() remains available
109
+ console.log(state.status, state.generation);
110
+ });
111
+
112
+ unsubscribe();
113
+ await session.close();
114
+ ```
115
+
116
+ `getState()` and `getLastGoodArtifacts()` are borrowed synchronous views. Before starting async
117
+ work, call `session.acquireArtifacts(generation?)` and release the returned acquisition in `finally`.
118
+ A replacement stops new acquisitions of the old generation and deletes its snapshot after the last
119
+ release. `close()` waits for outstanding acquisitions.
120
+
121
+ The bounded watcher follows the config, transitive local TypeScript/JavaScript/JSON imports, and
122
+ effective local icon/font directory inputs. Generations are monotonic, overlapping refreshes are latest-wins, invalid
123
+ edits retain the last good snapshot, and caller-supplied output directories can be ignored to avoid
124
+ feedback loops. `tileflow preview`, `capture --watch`, and
125
+ framework adapters use this shared status
126
+ vocabulary. The built-in preview reloads after its live event stream reconnects following a server
127
+ restart, even when the replacement process begins again at generation 1.
128
+
129
+ Custom preview servers use the exported map or one of its standalone scenes:
130
+
131
+ ```ts
132
+ import {createTileflowDevRequestHandler} from '@tileflow/dev/server';
133
+
134
+ const fetch = createTileflowDevRequestHandler({
135
+ config: 'tileflow.config.ts',
136
+ scene: 'madrid-mobile',
137
+ });
138
+
139
+ // On server shutdown:
140
+ await fetch.close();
141
+ ```
142
+
143
+ The handler does not close a caller-owned session.
144
+
145
+ Map preview uses the exported map's `view` and accepts one concrete `theme`; scene preview uses its
146
+ committed concrete theme, camera, and CSS viewport metadata from that same map. A scene does not
147
+ repeat the map ID because its owner is implicit.
148
+ `resolveTileflowPreview()` exposes the validated selection for custom integrations.
149
+ Application-target scenes remain the responsibility of the application's development server. The
150
+ built-in preview records longitude, latitude, zoom, bearing, and pitch in the current URL, so browser
151
+ refreshes and config-triggered reloads return to the same view. Removing those query parameters
152
+ restores the configured camera.
@@ -0,0 +1,21 @@
1
+ # Bounded PMTiles resource inspection
2
+
3
+ Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
4
+
5
+ Node tooling can inspect one local PMTiles archive without reading it completely:
6
+
7
+ ```ts
8
+ import {inspectTileflowPmtiles} from '@tileflow/dev/tilesets';
9
+
10
+ const inspection = await inspectTileflowPmtiles('./data/stores.pmtiles', {
11
+ includeValues: ['category', 'status'],
12
+ });
13
+ ```
14
+
15
+ Inspection schema 1 separates the authoritative PMTiles header and TileJSON `vector_layers` metadata
16
+ from deterministic bounded MVT observations. Each sampled field reports present/missing feature
17
+ counts, observed primitive types, capped distinct-value cardinality, numeric min/max, and explicit
18
+ truncation. Values are returned only for requested portable field names, with at most 32 requested
19
+ fields, 16 values per field, and 256 characters per string. Sampling reads at most eight tiles,
20
+ 20,000 features, or 24 MB of tile data; `sample: false` returns only authoritative metadata and does
21
+ not accept `includeValues`.
@@ -0,0 +1,100 @@
1
+ # Bounded vector-feature inspection
2
+
3
+ Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
4
+
5
+ Custom Node tooling can inspect only the features visible near a configured camera without opening
6
+ a browser:
7
+
8
+ ```ts
9
+ import {inspectTileflowFeatures} from '@tileflow/dev/inspect';
10
+
11
+ const internalCatalog = artifacts.project;
12
+ const inspection = await inspectTileflowFeatures(internalCatalog, 'madrid', {
13
+ center: [-3.6927512, 40.4086555],
14
+ zoom: 16,
15
+ sourceLayers: ['poi'],
16
+ properties: ['name', 'category', 'type', 'icon', 'filter_rank', 'size_rank'],
17
+ width: 512,
18
+ height: 512,
19
+ limit: 100,
20
+ });
21
+ ```
22
+
23
+ The inspector supports ordinary HTTP(S) vector sources and TileJSON. It bounds viewport, tile
24
+ count, individual/total bytes, scanned and returned features, property count/string lengths, and
25
+ request time; results are deduplicated and sorted deterministically. Output contains projected
26
+ properties, geometry summaries, safe origin/path metadata, and the configured source revision or
27
+ `null`. It never emits URL queries, credentials, hidden properties, response bodies, or absolute
28
+ paths. PMTiles and authenticated provider adapters are not currently supported by this primitive.
29
+
30
+ Deployment adapters can compile the same sources without writing them to disk:
31
+
32
+ ```ts
33
+ import {compileTileflowIconPackages} from '@tileflow/dev/icons';
34
+
35
+ const internalCatalog = artifacts.project;
36
+ const result = await compileTileflowIconPackages(internalCatalog, {
37
+ cwd: process.cwd(),
38
+ target: 'hosted',
39
+ });
40
+ ```
41
+
42
+ Streets declares `[streetsIcons]` and keeps light/dark image-token targets in that one closure.
43
+ Baedeker, Cívica, Ferraris, Härad, Siegfried, Soundings, and Blueprint declare only
44
+ `[baedekerIcons]`, `[civicaIcons]`, `[ferrarisIcons]`, `[haradIcons]`, `[siegfriedIcons]`,
45
+ `[soundingsIcons]`, and `[blueprintIcons]`, respectively. No official root composes another map's assets even though all
46
+ use the semantic compiler ABI. Baedeker's directory contains eight original travel-atlas patterns;
47
+ its browser-derived Mapterhorn contours use runtime terrain tiles and are not part of the icon
48
+ package. Härad's directory contains nine original Tileflow patterns inspired by Lantmäteriet's CC0
49
+ Häradsekonomiska kartan series from 1859–1934. Soundings owns ten original nautical symbols and
50
+ patterns. Blueprint owns four technical blueprint patterns and one schematic POI node; its
51
+ unbundled Mapterhorn contours remain runtime terrain, and its text uses the canonical Noto Sans
52
+ glyph provider. An application map may inherit a root's exact array, replace it, clear it with `[]`,
53
+ or compose it explicitly with a spread.
54
+ `modules.poi.icons: false` or a disabled POI module suppresses POI icon layers without moving asset
55
+ ownership into dev. POI density is the numeric producer threshold 1–5; it is not an asset-provider
56
+ preset.
57
+
58
+ The hosted target enforces repository containment, portable icon IDs, safe SVG
59
+ references, deterministic ordering, and the public package limits. Package-owned directories are
60
+ trusted only inside their declared owning package and are exempt from config working-tree
61
+ containment. It returns deduplicated generated files plus a canonical manifest/content hash. Upload
62
+ only those generated files: source icons and absolute paths remain local.
63
+
64
+ The version-1 manifest includes `renderedIcons` in the exact sorted `iconNames` order. Each entry
65
+ contains SHA-256 digests for the normalized 1x and 2x RGBA cell. The digest framing includes its
66
+ density and dimensions, zeroes RGB only where alpha is zero, and excludes filenames/source bytes.
67
+ The package content hash still covers the complete canonical manifest, including all four encoded
68
+ file hashes. Consumers can therefore distinguish a visible per-icon change from an atlas-layout or
69
+ encoding-only package change without receiving the original SVG/raster file.
70
+
71
+ `compileTileflowIconPackages` retains the exact RGBA cells used to assemble each atlas, so its
72
+ pixel digests describe delivered pixels rather than a second render. Hosted upload services must
73
+ decode the submitted PNGs and reconstruct those digests independently; client-authored manifest
74
+ analysis is not authoritative.
75
+
76
+ Custom Node tooling can inspect the same local pipeline without walking or decoding source files a
77
+ second time:
78
+
79
+ ```ts
80
+ import {inspectTileflowIconCatalogs} from '@tileflow/dev/icons';
81
+
82
+ const internalCatalog = artifacts.project;
83
+ const inspection = await inspectTileflowIconCatalogs(internalCatalog, {
84
+ cwd: process.cwd(),
85
+ mapNames: ['madrid'],
86
+ });
87
+ ```
88
+
89
+ The result keeps one catalog per distinct ordered directory composition, the exact winning source
90
+ for every final ID, explicit same-ID replacements, config-relative source metadata, exact atlas rectangles,
91
+ both manifest pixel digests, and the shared compiled package. `icons: []` is represented as an
92
+ absent catalog. This is a local-authoring integration surface: use the hosted compilation target
93
+ separately for deployment compatibility, and project only the metadata needed by an external
94
+ protocol rather than serializing generated byte arrays accidentally.
95
+
96
+ This package is public, but it is an integration layer. Styling primitives live in
97
+ `@tileflow/core`, official maps and their source assets live in `@tileflow/maps`, and React
98
+ rendering lives in `@tileflow/react`.
99
+
100
+ Docs: https://tileflow.dev/docs