@tileflow/static 0.1.0-alpha.17 → 0.1.0-alpha.19

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.
@@ -0,0 +1,79 @@
1
+ import {
2
+ normalizeStaticScene,
3
+ validateStaticScene
4
+ } from "./chunk-ROBEGDDY.js";
5
+ import {
6
+ hashStableValue,
7
+ isSafeHttpUrl,
8
+ staticSceneSchema,
9
+ stripUndefined
10
+ } from "./chunk-YUG3PBK2.js";
11
+
12
+ // src/manifest.ts
13
+ import { z } from "zod";
14
+ var staticRendererSchemaVersion = 1;
15
+ var staticRenderManifestSchema = z.object({
16
+ mapId: z.string().trim().min(1).max(128),
17
+ rendererVersion: z.string().trim().min(1).max(64),
18
+ schemaVersion: z.literal(staticRendererSchemaVersion),
19
+ scene: staticSceneSchema,
20
+ styleId: z.string().trim().min(1).max(128).optional(),
21
+ styleRevision: z.string().trim().min(1).max(128),
22
+ styleUrl: z.string().trim().url().max(512).refine(isSafeHttpUrl, {
23
+ message: "Expected an http(s) style URL without credentials or a fragment"
24
+ })
25
+ });
26
+ function validateStaticRenderManifest(input) {
27
+ const parsed = staticRenderManifestSchema.safeParse(input);
28
+ if (!parsed.success) {
29
+ return {
30
+ error: parsed.error.issues.map((issue) => `${issue.path.join(".") || "manifest"}: ${issue.message}`).join("; "),
31
+ ok: false
32
+ };
33
+ }
34
+ const sceneValidation = validateStaticScene(parsed.data.scene);
35
+ if (!sceneValidation.ok) {
36
+ return sceneValidation;
37
+ }
38
+ return {
39
+ manifest: {
40
+ ...parsed.data,
41
+ scene: sceneValidation.scene
42
+ },
43
+ ok: true
44
+ };
45
+ }
46
+ function createRenderManifest(input) {
47
+ return staticRenderManifestSchema.parse(
48
+ stripUndefined({
49
+ mapId: input.mapId,
50
+ rendererVersion: input.rendererVersion,
51
+ schemaVersion: staticRendererSchemaVersion,
52
+ scene: normalizeStaticScene(input.scene),
53
+ styleId: input.styleId,
54
+ styleRevision: input.styleRevision,
55
+ styleUrl: input.styleUrl
56
+ })
57
+ );
58
+ }
59
+ async function hashRenderManifest(manifest) {
60
+ const normalized = staticRenderManifestSchema.parse({
61
+ ...manifest,
62
+ scene: normalizeStaticScene(manifest.scene)
63
+ });
64
+ return hashStableValue(normalized);
65
+ }
66
+ async function hashStaticSceneRequest(scene) {
67
+ const validation = validateStaticScene(scene);
68
+ if (!validation.ok) throw new Error(`Invalid Tileflow static scene: ${validation.error}`);
69
+ return hashStableValue(validation.scene);
70
+ }
71
+
72
+ export {
73
+ staticRendererSchemaVersion,
74
+ staticRenderManifestSchema,
75
+ validateStaticRenderManifest,
76
+ createRenderManifest,
77
+ hashRenderManifest,
78
+ hashStaticSceneRequest
79
+ };
@@ -0,0 +1,106 @@
1
+ import {
2
+ normalizeStaticOverlay
3
+ } from "./chunk-YUG3PBK2.js";
4
+
5
+ // src/overlays.ts
6
+ function line(input) {
7
+ return normalizeStaticOverlay({ ...input, type: "line" });
8
+ }
9
+ function circle(input) {
10
+ return normalizeStaticOverlay({ ...input, type: "circle" });
11
+ }
12
+ function marker(input) {
13
+ return normalizeStaticOverlay({ ...input, type: "marker" });
14
+ }
15
+ function polygon(input) {
16
+ return normalizeStaticOverlay({ ...input, type: "polygon" });
17
+ }
18
+ function compileStaticOverlays(overlays) {
19
+ const sources = {};
20
+ const layers = [];
21
+ for (const [index, overlay] of overlays.entries()) {
22
+ const id = safeLayerId(`overlay-${index + 1}-${overlay.id ?? overlay.type}`);
23
+ const sourceId = `${id}-source`;
24
+ if (overlay.type === "line") {
25
+ sources[sourceId] = {
26
+ data: feature("LineString", overlay.coordinates),
27
+ type: "geojson"
28
+ };
29
+ layers.push({
30
+ id,
31
+ layout: { "line-cap": "round", "line-join": "round" },
32
+ paint: {
33
+ "line-color": overlay.color,
34
+ "line-opacity": overlay.opacity,
35
+ "line-width": overlay.width
36
+ },
37
+ source: sourceId,
38
+ type: "line"
39
+ });
40
+ continue;
41
+ }
42
+ if (overlay.type === "polygon") {
43
+ sources[sourceId] = {
44
+ data: feature("Polygon", overlay.coordinates),
45
+ type: "geojson"
46
+ };
47
+ layers.push({
48
+ id,
49
+ paint: {
50
+ "fill-color": overlay.fill,
51
+ "fill-opacity": overlay.opacity
52
+ },
53
+ source: sourceId,
54
+ type: "fill"
55
+ });
56
+ if (overlay.stroke && overlay.strokeWidth > 0) {
57
+ layers.push({
58
+ id: `${id}-stroke`,
59
+ layout: { "line-cap": "round", "line-join": "round" },
60
+ paint: {
61
+ "line-color": overlay.stroke,
62
+ "line-width": overlay.strokeWidth
63
+ },
64
+ source: sourceId,
65
+ type: "line"
66
+ });
67
+ }
68
+ continue;
69
+ }
70
+ sources[sourceId] = {
71
+ data: feature("Point", overlay.coordinate),
72
+ type: "geojson"
73
+ };
74
+ layers.push({
75
+ id,
76
+ paint: {
77
+ "circle-color": overlay.color,
78
+ "circle-opacity": overlay.type === "circle" ? overlay.opacity : 1,
79
+ "circle-radius": overlay.radius,
80
+ "circle-stroke-color": overlay.strokeColor ?? overlay.color,
81
+ "circle-stroke-width": overlay.strokeWidth
82
+ },
83
+ source: sourceId,
84
+ type: "circle"
85
+ });
86
+ }
87
+ return { layers, sources };
88
+ }
89
+ function feature(type, coordinates) {
90
+ return {
91
+ geometry: { coordinates, type },
92
+ properties: {},
93
+ type: "Feature"
94
+ };
95
+ }
96
+ function safeLayerId(value) {
97
+ return value.replace(/[^a-zA-Z0-9_-]/g, "-").slice(0, 80);
98
+ }
99
+
100
+ export {
101
+ line,
102
+ circle,
103
+ marker,
104
+ polygon,
105
+ compileStaticOverlays
106
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ jsonByteLength,
3
+ normalizeStaticCoordinate,
4
+ normalizeStaticOverlay,
5
+ roundNumber,
6
+ staticSceneLimits,
7
+ staticSceneSchema,
8
+ stripUndefined
9
+ } from "./chunk-YUG3PBK2.js";
10
+
11
+ // src/scene.ts
12
+ function validateStaticScene(input) {
13
+ const parsed = staticSceneSchema.safeParse(input);
14
+ if (!parsed.success) {
15
+ return {
16
+ error: parsed.error.issues.map((issue) => `${issue.path.join(".") || "scene"}: ${issue.message}`).join("; "),
17
+ ok: false
18
+ };
19
+ }
20
+ if (jsonByteLength(parsed.data.overlays) > staticSceneLimits.maxGeoJsonBytes) {
21
+ return {
22
+ error: `overlays exceed ${staticSceneLimits.maxGeoJsonBytes} bytes`,
23
+ ok: false
24
+ };
25
+ }
26
+ return { ok: true, scene: normalizeParsedStaticScene(parsed.data) };
27
+ }
28
+ function normalizeStaticScene(scene) {
29
+ return normalizeParsedStaticScene(staticSceneSchema.parse(scene));
30
+ }
31
+ function normalizeParsedStaticScene(parsed) {
32
+ return stripUndefined({
33
+ camera: parsed.camera.type === "center" ? {
34
+ bearing: roundNumber(parsed.camera.bearing ?? 0),
35
+ center: normalizeStaticCoordinate(parsed.camera.center),
36
+ type: "center",
37
+ zoom: roundNumber(parsed.camera.zoom)
38
+ } : {
39
+ bearing: roundNumber(parsed.camera.bearing ?? 0),
40
+ bounds: parsed.camera.bounds.map(roundNumber),
41
+ padding: parsed.camera.padding ?? 32,
42
+ type: "bounds"
43
+ },
44
+ map: parsed.map,
45
+ overlays: parsed.overlays.map(
46
+ (overlay, index) => normalizeStaticOverlay({
47
+ ...overlay,
48
+ id: overlay.id ?? `overlay-${index + 1}`
49
+ })
50
+ ),
51
+ size: {
52
+ dpr: parsed.size.dpr ?? 1,
53
+ height: parsed.size.height,
54
+ width: parsed.size.width
55
+ },
56
+ theme: parsed.theme
57
+ });
58
+ }
59
+
60
+ export {
61
+ validateStaticScene,
62
+ normalizeStaticScene
63
+ };
@@ -0,0 +1,198 @@
1
+ // src/canonical.ts
2
+ function stableStringify(value) {
3
+ return JSON.stringify(sortJson(value));
4
+ }
5
+ function roundNumber(value) {
6
+ return Number(value.toFixed(6));
7
+ }
8
+ function stripUndefined(value) {
9
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
10
+ return value;
11
+ }
12
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
13
+ }
14
+ function jsonByteLength(value) {
15
+ return new TextEncoder().encode(JSON.stringify(value)).length;
16
+ }
17
+ async function hashStableValue(value) {
18
+ const bytes = new TextEncoder().encode(stableStringify(value));
19
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
20
+ return base64Url(new Uint8Array(digest));
21
+ }
22
+ function isSafeHttpUrl(value) {
23
+ try {
24
+ const url = new URL(value);
25
+ return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password && !url.hash;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ function sortJson(value) {
31
+ if (Array.isArray(value)) {
32
+ return value.map(sortJson);
33
+ }
34
+ if (value && typeof value === "object") {
35
+ return Object.fromEntries(
36
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, sortJson(entry)])
37
+ );
38
+ }
39
+ return value;
40
+ }
41
+ function base64Url(bytes) {
42
+ let binary = "";
43
+ for (const byte of bytes) {
44
+ binary += String.fromCharCode(byte);
45
+ }
46
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
47
+ }
48
+
49
+ // src/scene-contract.ts
50
+ import { z } from "zod";
51
+ var staticSceneSchemaVersion = 1;
52
+ var staticSceneLimits = {
53
+ maxDimension: 1280,
54
+ maxGeoJsonBytes: 96e3,
55
+ maxOverlays: 24,
56
+ maxPathCoordinates: 2e3,
57
+ maxPhysicalPixels: 1280 * 1280,
58
+ minDimension: 64
59
+ };
60
+ var coordinateSchema = z.tuple([z.number().finite(), z.number().finite()]).refine(([lng, lat]) => lng >= -180 && lng <= 180 && lat >= -90 && lat <= 90, {
61
+ message: "Expected [lng, lat] within world bounds"
62
+ });
63
+ var colorSchema = z.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/, {
64
+ message: "Expected a hex color like #C6A15B"
65
+ });
66
+ var portableIdSchema = z.string().min(1).max(64).regex(/^[a-z][a-z0-9-]{0,63}$/u, {
67
+ message: "Expected lowercase kebab-case beginning with a letter"
68
+ }).refine(
69
+ (name) => !["constructor", "prototype"].includes(name) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(name),
70
+ "Expected a portable identifier that is not a reserved filename or prototype key"
71
+ );
72
+ var concreteThemeSchema = portableIdSchema.refine((value) => value !== "system", {
73
+ message: 'Static maps require a concrete theme; "system" is browser-only'
74
+ });
75
+ var sizeSchema = z.object({
76
+ dpr: z.literal(1).optional(),
77
+ height: z.number().int().min(staticSceneLimits.minDimension).max(staticSceneLimits.maxDimension),
78
+ width: z.number().int().min(staticSceneLimits.minDimension).max(staticSceneLimits.maxDimension)
79
+ }).refine(
80
+ (size) => size.width * size.height * (size.dpr ?? 1) <= staticSceneLimits.maxPhysicalPixels,
81
+ {
82
+ message: "Static map exceeds the maximum render pixel budget"
83
+ }
84
+ );
85
+ var centerCameraSchema = z.object({
86
+ bearing: z.number().finite().min(-180).max(180).optional(),
87
+ center: coordinateSchema,
88
+ type: z.literal("center"),
89
+ zoom: z.number().finite().min(0).max(22)
90
+ });
91
+ var boundsCameraSchema = z.object({
92
+ bearing: z.number().finite().min(-180).max(180).optional(),
93
+ bounds: z.tuple([z.number().finite(), z.number().finite(), z.number().finite(), z.number().finite()]).refine(
94
+ ([west, south, east, north]) => west >= -180 && west <= 180 && east >= -180 && east <= 180 && south >= -90 && south <= 90 && north >= -90 && north <= 90 && west !== east && south !== north,
95
+ { message: "Expected bounds as [west, south, east, north]" }
96
+ ),
97
+ padding: z.number().int().min(0).max(256).optional(),
98
+ type: z.literal("bounds")
99
+ }).refine((camera) => camera.bounds[3] > camera.bounds[1], {
100
+ message: "Bounds north must be greater than south"
101
+ });
102
+ var lineOverlaySchema = z.object({
103
+ color: colorSchema.default("#C6A15B"),
104
+ coordinates: z.array(coordinateSchema).min(2).max(staticSceneLimits.maxPathCoordinates),
105
+ id: z.string().trim().min(1).max(64).optional(),
106
+ opacity: z.number().finite().min(0).max(1).default(1),
107
+ type: z.literal("line"),
108
+ width: z.number().finite().min(0.5).max(32).default(4)
109
+ });
110
+ var circleOverlaySchema = z.object({
111
+ color: colorSchema.default("#C6A15B"),
112
+ coordinate: coordinateSchema,
113
+ id: z.string().trim().min(1).max(64).optional(),
114
+ opacity: z.number().finite().min(0).max(1).default(1),
115
+ radius: z.number().finite().min(1).max(64).default(6),
116
+ strokeColor: colorSchema.optional(),
117
+ strokeWidth: z.number().finite().min(0).max(16).default(0),
118
+ type: z.literal("circle")
119
+ });
120
+ var markerOverlaySchema = z.object({
121
+ color: colorSchema.default("#C6A15B"),
122
+ coordinate: coordinateSchema,
123
+ id: z.string().trim().min(1).max(64).optional(),
124
+ radius: z.number().finite().min(2).max(64).default(8),
125
+ strokeColor: colorSchema.default("#ffffff"),
126
+ strokeWidth: z.number().finite().min(0).max(16).default(2),
127
+ type: z.literal("marker")
128
+ });
129
+ var polygonRingSchema = z.array(coordinateSchema).min(4).max(staticSceneLimits.maxPathCoordinates).refine(
130
+ (ring) => {
131
+ const first = ring[0];
132
+ const last = ring[ring.length - 1];
133
+ return Boolean(first && last && first[0] === last[0] && first[1] === last[1]);
134
+ },
135
+ { message: "Polygon rings must end at their starting coordinate" }
136
+ );
137
+ var polygonOverlaySchema = z.object({
138
+ coordinates: z.array(polygonRingSchema).min(1).max(16),
139
+ fill: colorSchema.default("#C6A15B"),
140
+ id: z.string().trim().min(1).max(64).optional(),
141
+ opacity: z.number().finite().min(0).max(1).default(0.28),
142
+ stroke: colorSchema.optional(),
143
+ strokeWidth: z.number().finite().min(0).max(16).default(0),
144
+ type: z.literal("polygon")
145
+ });
146
+ var staticOverlaySchema = z.discriminatedUnion("type", [
147
+ lineOverlaySchema,
148
+ circleOverlaySchema,
149
+ markerOverlaySchema,
150
+ polygonOverlaySchema
151
+ ]);
152
+ var staticSceneSchema = z.object({
153
+ camera: z.discriminatedUnion("type", [centerCameraSchema, boundsCameraSchema]),
154
+ map: portableIdSchema,
155
+ overlays: z.array(staticOverlaySchema).max(staticSceneLimits.maxOverlays).default([]),
156
+ size: sizeSchema,
157
+ theme: concreteThemeSchema
158
+ });
159
+
160
+ // src/overlay-normalization.ts
161
+ function normalizeStaticOverlay(overlay) {
162
+ const parsed = staticOverlaySchema.parse(overlay);
163
+ const normalized = stripUndefined({ ...parsed });
164
+ if ("coordinate" in normalized) {
165
+ normalized.coordinate = normalizeStaticCoordinate(normalized.coordinate);
166
+ }
167
+ if ("coordinates" in normalized) {
168
+ normalized.coordinates = normalizeStaticCoordinates(normalized.coordinates);
169
+ }
170
+ return normalized;
171
+ }
172
+ function normalizeStaticCoordinate(coordinate) {
173
+ return [roundNumber(coordinate[0]), roundNumber(coordinate[1])];
174
+ }
175
+ function normalizeStaticCoordinates(value) {
176
+ if (!Array.isArray(value)) {
177
+ return value;
178
+ }
179
+ if (value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number") {
180
+ return normalizeStaticCoordinate(value);
181
+ }
182
+ return value.map(normalizeStaticCoordinates);
183
+ }
184
+
185
+ export {
186
+ stableStringify,
187
+ roundNumber,
188
+ stripUndefined,
189
+ jsonByteLength,
190
+ hashStableValue,
191
+ isSafeHttpUrl,
192
+ staticSceneSchemaVersion,
193
+ staticSceneLimits,
194
+ staticOverlaySchema,
195
+ staticSceneSchema,
196
+ normalizeStaticOverlay,
197
+ normalizeStaticCoordinate
198
+ };
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ import { d as StaticSceneInput } from './scene-contract-DzsUeJ_V.js';
3
+
4
+ declare function stableStringify(value: unknown): string;
5
+
6
+ type StaticMapResult = {
7
+ cached: boolean;
8
+ hash: string;
9
+ imageUrl: string;
10
+ operationId: string | null;
11
+ remainingUnits: number | null;
12
+ status: 'ready';
13
+ unitCost: 0 | 15;
14
+ };
15
+ type StaticMapCreateOptions = {
16
+ apiKey?: string;
17
+ apiUrl?: string;
18
+ fetch?: typeof fetch;
19
+ idempotencyKey: string;
20
+ maxWaitMs?: number;
21
+ pollIntervalMs?: number;
22
+ signal?: AbortSignal;
23
+ };
24
+ type StaticMapEndpointRequestOptions = Omit<StaticMapCreateOptions, 'apiUrl'> & {
25
+ createUrl: string;
26
+ };
27
+ type PreparedStaticMapRequest = Readonly<{
28
+ sceneKey: string;
29
+ }>;
30
+ declare const staticMapReadyResultSchema: z.ZodObject<{
31
+ cached: z.ZodBoolean;
32
+ hash: z.ZodString;
33
+ imageUrl: z.ZodString;
34
+ operationId: z.ZodString;
35
+ remainingUnits: z.ZodNumber;
36
+ status: z.ZodLiteral<"ready">;
37
+ unitCost: z.ZodLiteral<15>;
38
+ }, z.core.$strict>;
39
+ declare const staticMapProcessingResultSchema: z.ZodObject<{
40
+ operationId: z.ZodString;
41
+ retryAfterMs: z.ZodNumber;
42
+ status: z.ZodLiteral<"processing">;
43
+ }, z.core.$strict>;
44
+
45
+ declare function validateStaticMapIdempotencyKey(value: unknown): {
46
+ key: string;
47
+ ok: true;
48
+ } | {
49
+ error: string;
50
+ ok: false;
51
+ };
52
+ declare function createStaticMapIdempotencyKey(): string;
53
+ declare function prepareStaticMapRequest(scene: StaticSceneInput): PreparedStaticMapRequest;
54
+ declare function createStaticMap(scene: StaticSceneInput, options: StaticMapCreateOptions): Promise<StaticMapResult>;
55
+ declare function precacheStaticMap(scene: StaticSceneInput, options: StaticMapCreateOptions): Promise<StaticMapResult>;
56
+ declare function requestStaticMapUntilReady(request: PreparedStaticMapRequest, options: StaticMapEndpointRequestOptions): Promise<StaticMapResult>;
57
+
58
+ export { type PreparedStaticMapRequest, type StaticMapCreateOptions, type StaticMapEndpointRequestOptions, type StaticMapResult, createStaticMap, createStaticMapIdempotencyKey, precacheStaticMap, prepareStaticMapRequest, requestStaticMapUntilReady, stableStringify, staticMapProcessingResultSchema, staticMapReadyResultSchema, validateStaticMapIdempotencyKey };
package/dist/client.js ADDED
@@ -0,0 +1,25 @@
1
+ import {
2
+ createStaticMap,
3
+ createStaticMapIdempotencyKey,
4
+ precacheStaticMap,
5
+ prepareStaticMapRequest,
6
+ requestStaticMapUntilReady,
7
+ staticMapProcessingResultSchema,
8
+ staticMapReadyResultSchema,
9
+ validateStaticMapIdempotencyKey
10
+ } from "./chunk-43QGLF6K.js";
11
+ import "./chunk-ROBEGDDY.js";
12
+ import {
13
+ stableStringify
14
+ } from "./chunk-YUG3PBK2.js";
15
+ export {
16
+ createStaticMap,
17
+ createStaticMapIdempotencyKey,
18
+ precacheStaticMap,
19
+ prepareStaticMapRequest,
20
+ requestStaticMapUntilReady,
21
+ stableStringify,
22
+ staticMapProcessingResultSchema,
23
+ staticMapReadyResultSchema,
24
+ validateStaticMapIdempotencyKey
25
+ };