@tileflow/dev 0.1.0-alpha.14 → 0.1.0-alpha.16

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/README.md CHANGED
@@ -14,10 +14,115 @@ const artifacts = await createTileflowBuildArtifacts({
14
14
  });
15
15
  ```
16
16
 
17
+ `createTileflowStyle`, `createTileflowStyles`, and artifact construction all enforce the same
18
+ recursive JSON-value invariant and MapLibre style-spec semantics without fetching remote resources.
19
+ Invalid output throws `TileflowStyleValidationError` with at most 32 deterministic
20
+ `map`/`path`/`message` issues; layer indexes are projected to stable layer IDs.
21
+
22
+ For a watched, last-known-good integration, use one artifact session rather than recompiling each
23
+ request independently:
24
+
25
+ ```ts
26
+ import {createTileflowArtifactSession} from '@tileflow/dev';
27
+
28
+ const session = await createTileflowArtifactSession({
29
+ config: 'tileflow.config.ts',
30
+ watch: true,
31
+ });
32
+
33
+ const unsubscribe = session.subscribe((state) => {
34
+ // building -> ready, or invalid while getLastGoodArtifacts() remains available
35
+ console.log(state.status, state.generation);
36
+ });
37
+
38
+ unsubscribe();
39
+ await session.close();
40
+ ```
41
+
42
+ The bounded watcher follows the config, transitive local TypeScript/JavaScript/JSON imports, and
43
+ effective icon inputs. Generations are monotonic, overlapping refreshes are latest-wins, invalid
44
+ edits retain the last good snapshot, and caller-supplied output directories can be ignored to avoid
45
+ feedback loops. `tileflow dev`, `capture --watch`, and framework adapters use this shared status
46
+ vocabulary.
47
+
17
48
  If a map uses `icons: './icons/brand'`, build artifacts include the generated
18
49
  MapLibre `sprite.json`, `sprite.png`, `sprite@2x.json`, and `sprite@2x.png`
19
50
  assets alongside the styles.
20
51
 
52
+ ## Bounded vector-feature inspection
53
+
54
+ Custom Node tooling can inspect only the features visible near a configured camera without opening
55
+ a browser:
56
+
57
+ ```ts
58
+ import {inspectTileflowFeatures} from '@tileflow/dev';
59
+
60
+ const inspection = await inspectTileflowFeatures(project, 'madrid', {
61
+ center: [-3.6927512, 40.4086555],
62
+ zoom: 16,
63
+ sourceLayers: ['poi'],
64
+ properties: ['name', 'class', 'subclass', 'rank'],
65
+ width: 512,
66
+ height: 512,
67
+ limit: 100,
68
+ });
69
+ ```
70
+
71
+ The inspector supports ordinary HTTP(S) vector sources and TileJSON. It bounds viewport, tile
72
+ count, individual/total bytes, scanned and returned features, property count/string lengths, and
73
+ request time; results are deduplicated and sorted deterministically. Output contains projected
74
+ properties, geometry summaries, safe origin/path metadata, and the configured source revision or
75
+ `null`. It never emits URL queries, credentials, hidden properties, response bodies, or absolute
76
+ paths. PMTiles and authenticated provider adapters are not currently supported by this primitive.
77
+
78
+ Deployment adapters can compile the same sources without writing them to disk:
79
+
80
+ ```ts
81
+ import {compileTileflowIconPackages} from '@tileflow/dev';
82
+
83
+ const result = await compileTileflowIconPackages(project, {
84
+ cwd: process.cwd(),
85
+ target: 'hosted',
86
+ });
87
+ ```
88
+
89
+ The hosted target enforces repository containment, portable icon IDs, safe SVG
90
+ references, deterministic ordering, and the public package limits. It returns
91
+ deduplicated generated files plus a canonical manifest/content hash. Upload only
92
+ those generated files: source icons and absolute paths remain local. External
93
+ sprite URLs are preserved as references and are not downloaded.
94
+
95
+ The version-1 manifest includes `renderedIcons` in the exact sorted `iconNames` order. Each entry
96
+ contains SHA-256 digests for the normalized 1x and 2x RGBA cell. The digest framing includes its
97
+ density and dimensions, zeroes RGB only where alpha is zero, and excludes filenames/source bytes.
98
+ The package content hash still covers the complete canonical manifest, including all four encoded
99
+ file hashes. Consumers can therefore distinguish a visible per-icon change from an atlas-layout or
100
+ encoding-only package change without receiving the original SVG/raster file.
101
+
102
+ `compileTileflowIconPackages` retains the exact RGBA cells used to assemble each atlas, so its
103
+ pixel digests describe delivered pixels rather than a second render. Hosted upload services must
104
+ decode the submitted PNGs and reconstruct those digests independently; client-authored manifest
105
+ analysis is not authoritative.
106
+
107
+ Custom Node tooling can inspect the same local pipeline without walking or decoding source files a
108
+ second time:
109
+
110
+ ```ts
111
+ import {inspectTileflowIconCatalogs} from '@tileflow/dev';
112
+
113
+ const inspection = await inspectTileflowIconCatalogs(project, {
114
+ cwd: process.cwd(),
115
+ mapNames: ['madrid'],
116
+ });
117
+ ```
118
+
119
+ The result keeps one catalog per resolved source directory, map-specific resolved mappings,
120
+ cwd-relative source metadata, exact atlas rectangles, both manifest pixel digests, and the shared
121
+ compiled package. It classifies remote and absent catalogs without fetching them. This is a
122
+ local-authoring integration surface: use the hosted compilation target separately for deployment
123
+ compatibility, and project only the metadata needed by an external protocol rather than serializing
124
+ generated byte arrays accidentally.
125
+
21
126
  This package is public, but it is an integration layer. Map styling primitives live in
22
127
  `@tileflow/core`; React rendering lives in `@tileflow/react`.
23
128
 
package/dist/index.d.ts CHANGED
@@ -1,11 +1,232 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { TileflowManifest, MapLibreStyle, ValidationMessage, TileflowProjectConfig, TileflowStyleOptions } from '@tileflow/core';
2
+ import { TileflowIconPackageFileName, TileflowIconPackageManifest, TileflowProjectConfig, MapLibreStyle, TileflowManifest, ValidationMessage, TileflowStyleOptions } from '@tileflow/core';
3
+
4
+ declare const tileflowArtifactSessionSchemaVersion: 1;
5
+ type TileflowArtifactDiagnostic = {
6
+ code?: string;
7
+ message: string;
8
+ path: string;
9
+ phase?: string;
10
+ };
11
+ type TileflowArtifactSessionState = {
12
+ status: 'building';
13
+ generation: number;
14
+ lastGoodGeneration?: number;
15
+ } | {
16
+ status: 'ready';
17
+ generation: number;
18
+ artifacts: TileflowBuildArtifacts;
19
+ lastGoodGeneration: number;
20
+ } | {
21
+ status: 'invalid';
22
+ generation: number;
23
+ diagnostics: TileflowArtifactDiagnostic[];
24
+ lastGoodGeneration?: number;
25
+ };
26
+ type TileflowArtifactSessionOptions = TileflowBuildArtifactsOptions & {
27
+ debounceMs?: number;
28
+ ignoredPaths?: string[];
29
+ watch?: boolean;
30
+ };
31
+ type TileflowArtifactSession = {
32
+ close(): Promise<void>;
33
+ getLastGoodArtifacts(): TileflowBuildArtifacts | undefined;
34
+ getState(): TileflowArtifactSessionState;
35
+ refresh(reason?: string): Promise<void>;
36
+ subscribe(listener: (state: TileflowArtifactSessionState) => void): () => void;
37
+ };
38
+ declare function createTileflowArtifactDiagnostics(error: unknown, cwd: string): TileflowArtifactDiagnostic[];
3
39
 
4
40
  type TileflowBuildAsset = {
5
41
  contentType: string;
6
42
  fileName: string;
7
43
  source: string | Uint8Array;
8
44
  };
45
+ type PreparedTileflowProject = {
46
+ assets: TileflowBuildAsset[];
47
+ project: TileflowProjectConfig;
48
+ watchPaths: string[];
49
+ };
50
+ type TileflowIconCompilationTarget = 'hosted' | 'local';
51
+ type TileflowIconCompilationIssue = {
52
+ message: string;
53
+ path: string;
54
+ };
55
+ type CompiledTileflowIconPackageFile = {
56
+ contentType: 'application/json' | 'image/png';
57
+ fileName: TileflowIconPackageFileName;
58
+ source: Uint8Array;
59
+ };
60
+ type CompiledTileflowIconPackage = {
61
+ contentHash: string;
62
+ files: CompiledTileflowIconPackageFile[];
63
+ manifest: TileflowIconPackageManifest;
64
+ };
65
+ type TileflowMapIconPackageBinding = {
66
+ label: string;
67
+ mapName: string;
68
+ mapping?: Record<string, string>;
69
+ packageHash: string;
70
+ };
71
+ type CompileTileflowIconPackagesResult = {
72
+ bindings: TileflowMapIconPackageBinding[];
73
+ packages: CompiledTileflowIconPackage[];
74
+ watchPaths: string[];
75
+ };
76
+ type InspectTileflowIconCatalogsOptions = {
77
+ cwd: string;
78
+ mapNames?: readonly string[];
79
+ };
80
+ type TileflowIconCatalogSourceFormat = 'jpeg' | 'png' | 'svg' | 'webp';
81
+ type TileflowIconCatalogMapping = {
82
+ iconId: string;
83
+ semantic: string;
84
+ targetStatus: 'missing' | 'present' | 'unknown';
85
+ };
86
+ type TileflowIconCatalogMappedFrom = {
87
+ map: string;
88
+ semantic: string;
89
+ };
90
+ type TileflowIconCatalogAtlasRectangle = {
91
+ height: number;
92
+ width: number;
93
+ x: number;
94
+ y: number;
95
+ };
96
+ type TileflowIconCatalogRenderedDensity = {
97
+ atlas: TileflowIconCatalogAtlasRectangle;
98
+ height: number;
99
+ pixelRatio: 1 | 2;
100
+ pixelSha256: string;
101
+ width: number;
102
+ };
103
+ type TileflowIconCatalogIcon = {
104
+ id: string;
105
+ mappedFrom: TileflowIconCatalogMappedFrom[];
106
+ rendered: {
107
+ oneX: TileflowIconCatalogRenderedDensity;
108
+ twoX: TileflowIconCatalogRenderedDensity;
109
+ };
110
+ source: {
111
+ byteLength: number;
112
+ dimensions: {
113
+ height: number;
114
+ width: number;
115
+ } | null;
116
+ format: TileflowIconCatalogSourceFormat;
117
+ path: string;
118
+ };
119
+ };
120
+ type TileflowIconCatalog = {
121
+ compiledPackage: CompiledTileflowIconPackage;
122
+ icons: TileflowIconCatalogIcon[];
123
+ insideWorkingTree: boolean;
124
+ sourcePath: string;
125
+ };
126
+ type TileflowIconCatalogMap = {
127
+ name: string;
128
+ icons: {
129
+ catalogSourcePath: string;
130
+ kind: 'local';
131
+ label: string;
132
+ mappings: TileflowIconCatalogMapping[];
133
+ packageHash: string;
134
+ } | {
135
+ inspectable: false;
136
+ kind: 'external';
137
+ mappings: TileflowIconCatalogMapping[];
138
+ } | {
139
+ inspectable: false;
140
+ kind: 'none';
141
+ mappings: TileflowIconCatalogMapping[];
142
+ };
143
+ };
144
+ type TileflowIconCatalogInspection = {
145
+ catalogs: TileflowIconCatalog[];
146
+ maps: TileflowIconCatalogMap[];
147
+ };
148
+ declare class TileflowIconCompilationError extends Error {
149
+ readonly code: "ICON_INVALID";
150
+ readonly issues: TileflowIconCompilationIssue[];
151
+ readonly phase: "icon-compilation";
152
+ constructor(issues: TileflowIconCompilationIssue[]);
153
+ }
154
+ declare const iconFileExtensions: Set<string>;
155
+ declare function compileTileflowIconPackages(project: TileflowProjectConfig, options: {
156
+ cwd: string;
157
+ target: TileflowIconCompilationTarget;
158
+ }): Promise<CompileTileflowIconPackagesResult>;
159
+ declare function inspectTileflowIconCatalogs(project: TileflowProjectConfig, options: InspectTileflowIconCatalogsOptions): Promise<TileflowIconCatalogInspection>;
160
+ declare function prepareTileflowProjectIcons(project: TileflowProjectConfig, options: {
161
+ assetBaseUrl: string;
162
+ cwd: string;
163
+ }): Promise<PreparedTileflowProject>;
164
+
165
+ type TileflowFeatureInspectionOptions = {
166
+ center: readonly [number, number];
167
+ fetch?: typeof fetch;
168
+ height?: number;
169
+ limit?: number;
170
+ properties?: readonly string[];
171
+ signal?: AbortSignal;
172
+ sourceLayers: readonly string[];
173
+ tileBaseUrl?: string;
174
+ timeoutMs?: number;
175
+ width?: number;
176
+ zoom: number;
177
+ };
178
+ type TileflowInspectedProperty = boolean | number | string;
179
+ type TileflowInspectedFeature = {
180
+ sourceLayer: string;
181
+ id: number | null;
182
+ geometry: {
183
+ type: string;
184
+ center: [number, number];
185
+ bounds: [number, number, number, number];
186
+ };
187
+ properties: Record<string, TileflowInspectedProperty>;
188
+ };
189
+ type TileflowFeatureInspection = {
190
+ schemaVersion: 1;
191
+ map: string;
192
+ camera: {
193
+ center: [number, number];
194
+ zoom: number;
195
+ viewport: {
196
+ width: number;
197
+ height: number;
198
+ };
199
+ };
200
+ source: {
201
+ id: string;
202
+ origin: string;
203
+ tileJsonPath: string | null;
204
+ tileOrigins: string[];
205
+ version: string | null;
206
+ };
207
+ sourceLayers: string[];
208
+ properties: string[];
209
+ tileZoom: number;
210
+ tilesRead: number;
211
+ scannedFeatures: number;
212
+ truncated: boolean;
213
+ features: TileflowInspectedFeature[];
214
+ };
215
+ declare function inspectTileflowFeatures(project: TileflowProjectConfig, mapName: string, input: TileflowFeatureInspectionOptions): Promise<TileflowFeatureInspection>;
216
+
217
+ type TileflowStyleValidationIssue = {
218
+ map: string;
219
+ message: string;
220
+ path: string;
221
+ };
222
+ declare class TileflowStyleValidationError extends Error {
223
+ readonly code: "STYLE_INVALID";
224
+ readonly issues: TileflowStyleValidationIssue[];
225
+ readonly phase: "style-validation";
226
+ constructor(issues: readonly TileflowStyleValidationIssue[]);
227
+ }
228
+ declare function assertValidTileflowStyle(style: MapLibreStyle, map: string): void;
229
+ declare function validateTileflowStyle(style: MapLibreStyle, map: string): TileflowStyleValidationIssue[];
9
230
 
10
231
  declare const defaultTileflowApiUrl = "https://api.tileflow.dev";
11
232
  declare const defaultTileflowConfigPath = "tileflow.config.ts";
@@ -24,6 +245,7 @@ type TileflowDevRequestHandlerOptions = {
24
245
  config?: string;
25
246
  cwd?: string;
26
247
  onError?: (error: unknown) => void;
248
+ session?: TileflowArtifactSession;
27
249
  styleBaseUrl?: string;
28
250
  tileBaseUrl?: string;
29
251
  };
@@ -37,6 +259,7 @@ type TileflowBuildArtifactsOptions = {
37
259
  type TileflowBuildArtifacts = {
38
260
  assets: TileflowBuildAsset[];
39
261
  manifest: TileflowManifest;
262
+ project: TileflowProjectConfig;
40
263
  styles: Record<string, MapLibreStyle>;
41
264
  watchPaths: string[];
42
265
  };
@@ -44,7 +267,9 @@ type WriteTileflowBuildArtifactsOptions = TileflowBuildArtifactsOptions & {
44
267
  outDir: string;
45
268
  };
46
269
  declare class TileflowValidationError extends Error {
270
+ readonly code: "CONFIG_INVALID";
47
271
  readonly messages: ValidationMessage[];
272
+ readonly phase: "config-validation";
48
273
  constructor(messages: ValidationMessage[]);
49
274
  }
50
275
  declare function loadTileflowConfig(configPath?: string, options?: LoadTileflowConfigOptions): Promise<TileflowProjectConfig>;
@@ -56,7 +281,9 @@ declare function getFirstTileflowMapName(project: TileflowProjectConfig): string
56
281
  declare function getTileflowStyleMapName(path: string): string;
57
282
  declare function createTileflowManifest(project: TileflowProjectConfig, options?: TileflowManifestOptions): TileflowManifest;
58
283
  declare function createTileflowStyle(project: TileflowProjectConfig, mapName: string, options?: TileflowStyleOptions): MapLibreStyle;
284
+ declare function createTileflowStyles(project: TileflowProjectConfig, options?: TileflowStyleOptions): Record<string, MapLibreStyle>;
59
285
  declare function createTileflowBuildArtifacts(options?: TileflowBuildArtifactsOptions): Promise<TileflowBuildArtifacts>;
286
+ declare function createTileflowArtifactSession(options?: TileflowArtifactSessionOptions): Promise<TileflowArtifactSession>;
60
287
  declare function getTileflowWatchPaths(options?: Pick<TileflowBuildArtifactsOptions, 'config' | 'cwd'>): Promise<string[]>;
61
288
  declare function writeTileflowBuildArtifacts(options: WriteTileflowBuildArtifactsOptions): Promise<TileflowBuildArtifacts>;
62
289
  declare function isTileflowRequestUrl(url: string | undefined, basePath: string): boolean;
@@ -66,6 +293,13 @@ declare function joinTileflowPublicUrl(publicBase: string, basePath: string): st
66
293
  declare function getTileflowAssetBasePath(basePath: string): string;
67
294
  declare function getTileflowAssetFileName(basePath: string, fileName: string): string;
68
295
  declare function createTileflowDevRequestHandler(options?: TileflowDevRequestHandlerOptions): (request: Request) => Promise<Response>;
296
+ declare function createTileflowArtifactStatus(state: TileflowArtifactSessionState): {
297
+ diagnostics?: TileflowArtifactDiagnostic[] | undefined;
298
+ lastGoodGeneration?: number | undefined;
299
+ schemaVersion: 1;
300
+ generation: number;
301
+ status: "building" | "ready" | "invalid";
302
+ };
69
303
  declare function normalizeTileflowBasePath(value?: string): string;
70
304
 
71
- export { type LoadTileflowConfigOptions, type TileflowBuildArtifacts, type TileflowBuildArtifactsOptions, type TileflowDevRequestHandlerOptions, type TileflowManifestOptions, TileflowValidationError, type WriteTileflowBuildArtifactsOptions, asTileflowProjectConfig, assertValidTileflowConfig, createTileflowBuildArtifacts, createTileflowDevRequestHandler, createTileflowManifest, createTileflowNodeRequest, createTileflowStyle, defaultTileflowApiUrl, defaultTileflowConfigPath, defaultTileflowManifestPath, defaultTileflowTileset, getFirstTileflowMapName, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowMapNames, getTileflowStyleMapName, getTileflowWatchPaths, isTileflowRequestUrl, joinTileflowPublicUrl, loadTileflowConfig, loadValidTileflowConfig, normalizeTileflowBasePath, writeTileflowBuildArtifacts, writeTileflowNodeResponse };
305
+ export { type CompileTileflowIconPackagesResult, type CompiledTileflowIconPackage, type CompiledTileflowIconPackageFile, type InspectTileflowIconCatalogsOptions, type LoadTileflowConfigOptions, type PreparedTileflowProject, type TileflowArtifactDiagnostic, type TileflowArtifactSession, type TileflowArtifactSessionOptions, type TileflowArtifactSessionState, type TileflowBuildArtifacts, type TileflowBuildArtifactsOptions, type TileflowBuildAsset, type TileflowDevRequestHandlerOptions, type TileflowFeatureInspection, type TileflowFeatureInspectionOptions, type TileflowIconCatalog, type TileflowIconCatalogAtlasRectangle, type TileflowIconCatalogIcon, type TileflowIconCatalogInspection, type TileflowIconCatalogMap, type TileflowIconCatalogMappedFrom, type TileflowIconCatalogMapping, type TileflowIconCatalogRenderedDensity, type TileflowIconCatalogSourceFormat, TileflowIconCompilationError, type TileflowIconCompilationIssue, type TileflowIconCompilationTarget, type TileflowInspectedFeature, type TileflowInspectedProperty, type TileflowManifestOptions, type TileflowMapIconPackageBinding, TileflowStyleValidationError, type TileflowStyleValidationIssue, TileflowValidationError, type WriteTileflowBuildArtifactsOptions, asTileflowProjectConfig, assertValidTileflowConfig, assertValidTileflowStyle, compileTileflowIconPackages, createTileflowArtifactDiagnostics, createTileflowArtifactSession, createTileflowArtifactStatus, createTileflowBuildArtifacts, createTileflowDevRequestHandler, createTileflowManifest, createTileflowNodeRequest, createTileflowStyle, createTileflowStyles, defaultTileflowApiUrl, defaultTileflowConfigPath, defaultTileflowManifestPath, defaultTileflowTileset, getFirstTileflowMapName, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowMapNames, getTileflowStyleMapName, getTileflowWatchPaths, iconFileExtensions, inspectTileflowFeatures, inspectTileflowIconCatalogs, isTileflowRequestUrl, joinTileflowPublicUrl, loadTileflowConfig, loadValidTileflowConfig, normalizeTileflowBasePath, prepareTileflowProjectIcons, tileflowArtifactSessionSchemaVersion, validateTileflowStyle, writeTileflowBuildArtifacts, writeTileflowNodeResponse };