@tileflow/static 0.1.0-alpha.2 → 0.1.0-alpha.20

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,304 @@
1
+ import {
2
+ validateStaticScene
3
+ } from "./chunk-ROBEGDDY.js";
4
+ import {
5
+ isSafeHttpUrl,
6
+ stableStringify
7
+ } from "./chunk-YUG3PBK2.js";
8
+
9
+ // src/client.ts
10
+ import { z } from "zod";
11
+ var maxStaticMapResponseBytes = 64 * 1024;
12
+ var staticMapIdempotencyKeyPattern = /^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$/;
13
+ var preparedStaticMapRequestBodies = /* @__PURE__ */ new WeakMap();
14
+ var staticMapReadyResultSchema = z.object({
15
+ cached: z.boolean(),
16
+ hash: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
17
+ imageUrl: z.string().trim().url().max(2048).refine(isSafeHttpUrl, { message: "Expected an http(s) URL without credentials" }),
18
+ operationId: z.string().min(20).max(68),
19
+ remainingUnits: z.number().int().nonnegative().nullable(),
20
+ status: z.literal("ready"),
21
+ unitCost: z.literal(15)
22
+ }).strict();
23
+ var staticMapProcessingResultSchema = z.object({
24
+ operationId: z.string().min(20).max(68),
25
+ retryAfterMs: z.number().int().min(0).max(5e3),
26
+ status: z.literal("processing")
27
+ }).strict();
28
+ function validateStaticMapIdempotencyKey(value) {
29
+ if (typeof value !== "string" || !staticMapIdempotencyKeyPattern.test(value)) {
30
+ return {
31
+ error: "Idempotency key must contain 8-128 ASCII letters, digits, dot, underscore, colon, or hyphen and start with a letter or digit",
32
+ ok: false
33
+ };
34
+ }
35
+ return { key: value, ok: true };
36
+ }
37
+ function createStaticMapIdempotencyKey() {
38
+ const key = `static_${crypto.randomUUID()}`;
39
+ if (!validateStaticMapIdempotencyKey(key).ok) {
40
+ throw new Error("Unable to create a valid Tileflow Static Maps idempotency key");
41
+ }
42
+ return key;
43
+ }
44
+ function prepareStaticMapRequest(scene) {
45
+ const validation = validateStaticScene(scene);
46
+ if (!validation.ok) {
47
+ throw new Error(`Invalid Tileflow static scene: ${validation.error}`);
48
+ }
49
+ const prepared = Object.freeze({
50
+ sceneKey: stableStringify(validation.scene)
51
+ });
52
+ preparedStaticMapRequestBodies.set(prepared, JSON.stringify(validation.scene));
53
+ return prepared;
54
+ }
55
+ async function createStaticMap(scene, options) {
56
+ return requestStaticMap(scene, options, "/v1/static/maps");
57
+ }
58
+ async function precacheStaticMap(scene, options) {
59
+ return requestStaticMap(scene, options, "/v1/static/maps/precache");
60
+ }
61
+ async function requestStaticMap(scene, options, path) {
62
+ const preparedRequest = prepareStaticMapRequest(scene);
63
+ const { apiUrl = "https://api.tileflow.dev", ...requestOptions } = options;
64
+ return requestStaticMapUntilReady(preparedRequest, {
65
+ ...requestOptions,
66
+ createUrl: `${normalizeUrl(apiUrl)}${path}`
67
+ });
68
+ }
69
+ async function requestStaticMapUntilReady(request, options) {
70
+ const body = preparedStaticMapRequestBodies.get(request);
71
+ if (body === void 0) {
72
+ throw new Error("Tileflow static map request must be created with prepareStaticMapRequest");
73
+ }
74
+ const idempotency = validateStaticMapIdempotencyKey(options.idempotencyKey);
75
+ if (!idempotency.ok) {
76
+ throw new Error(`Invalid Tileflow Static Maps idempotency key: ${idempotency.error}`);
77
+ }
78
+ const maxWaitMs = boundedClientDuration(options.maxWaitMs, 3e4, 100, 12e4, "maxWaitMs");
79
+ const pollIntervalMs = boundedClientDuration(
80
+ options.pollIntervalMs,
81
+ 500,
82
+ 0,
83
+ 5e3,
84
+ "pollIntervalMs"
85
+ );
86
+ const fetcher = options.fetch ?? fetch;
87
+ const createUrl = normalizeStaticMapEndpointUrl(options.createUrl);
88
+ const headers = {
89
+ "Content-Type": "application/json",
90
+ "Idempotency-Key": idempotency.key
91
+ };
92
+ if (options.apiKey) {
93
+ headers.Authorization = `Bearer ${options.apiKey}`;
94
+ }
95
+ return runWithinStaticMapBudget(maxWaitMs, options.signal, async (signal) => {
96
+ let operationId = null;
97
+ while (true) {
98
+ const response = await fetcher(createUrl, {
99
+ body,
100
+ headers,
101
+ method: "POST",
102
+ signal
103
+ });
104
+ throwIfAborted(signal);
105
+ if (!response.ok) {
106
+ await discardBoundedResponse(response, 8 * 1024);
107
+ throwIfAborted(signal);
108
+ throw new Error(`Tileflow static map failed (${response.status}).`);
109
+ }
110
+ const json = await readJsonResponse(response);
111
+ throwIfAborted(signal);
112
+ if (response.status !== 202) {
113
+ const parsed = staticMapReadyResultSchema.safeParse(json);
114
+ if (!parsed.success) {
115
+ throw new Error(
116
+ `Tileflow static map returned an invalid response: ${parsed.error.message}`
117
+ );
118
+ }
119
+ assertStaticMapOperationIdentity(operationId, parsed.data.operationId);
120
+ return parsed.data;
121
+ }
122
+ const pending = staticMapProcessingResultSchema.safeParse(json);
123
+ if (!pending.success) {
124
+ throw new Error(
125
+ `Tileflow static map returned an invalid response: ${pending.error.message}`
126
+ );
127
+ }
128
+ assertStaticMapOperationIdentity(operationId, pending.data.operationId);
129
+ operationId ??= pending.data.operationId;
130
+ await delay(Math.max(pollIntervalMs, pending.data.retryAfterMs), signal);
131
+ }
132
+ });
133
+ }
134
+ function boundedClientDuration(value, fallback, minimum, maximum, name) {
135
+ const resolved = value ?? fallback;
136
+ if (!Number.isSafeInteger(resolved) || resolved < minimum || resolved > maximum) {
137
+ throw new Error(
138
+ `Tileflow Static Maps ${name} must be an integer from ${minimum} to ${maximum}`
139
+ );
140
+ }
141
+ return resolved;
142
+ }
143
+ async function readJsonResponse(response) {
144
+ const source = await readBoundedResponseText(response, maxStaticMapResponseBytes, "64 KiB");
145
+ try {
146
+ return JSON.parse(source);
147
+ } catch {
148
+ throw new Error("Tileflow static map returned an invalid response: expected JSON");
149
+ }
150
+ }
151
+ async function discardBoundedResponse(response, maximumBytes) {
152
+ try {
153
+ await readBoundedResponseText(response, maximumBytes, `${maximumBytes} bytes`);
154
+ } catch {
155
+ }
156
+ }
157
+ async function readBoundedResponseText(response, maximumBytes, displayLimit) {
158
+ if (!response.body) return "";
159
+ const reader = response.body.getReader();
160
+ const chunks = [];
161
+ let byteLength = 0;
162
+ while (true) {
163
+ const { done, value } = await reader.read();
164
+ if (done) break;
165
+ byteLength += value.byteLength;
166
+ if (byteLength > maximumBytes) {
167
+ await reader.cancel();
168
+ throw new Error(
169
+ `Tileflow static map returned an invalid response: response exceeded ${displayLimit}`
170
+ );
171
+ }
172
+ chunks.push(value);
173
+ }
174
+ const bytes = new Uint8Array(byteLength);
175
+ let offset = 0;
176
+ for (const chunk of chunks) {
177
+ bytes.set(chunk, offset);
178
+ offset += chunk.byteLength;
179
+ }
180
+ try {
181
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
182
+ } catch {
183
+ throw new Error("Tileflow static map returned an invalid response: expected UTF-8 JSON");
184
+ }
185
+ }
186
+ async function runWithinStaticMapBudget(maxWaitMs, externalSignal, operation) {
187
+ const controller = new AbortController();
188
+ const timeoutError = new Error(`Tileflow static map timed out after ${maxWaitMs}ms`);
189
+ const abortFromCaller = () => controller.abort(externalSignal?.reason);
190
+ if (externalSignal?.aborted) {
191
+ abortFromCaller();
192
+ } else {
193
+ externalSignal?.addEventListener("abort", abortFromCaller, { once: true });
194
+ }
195
+ const timeout = setTimeout(() => controller.abort(timeoutError), maxWaitMs);
196
+ try {
197
+ throwIfAborted(controller.signal);
198
+ const pending = operation(controller.signal);
199
+ return await raceWithAbort(pending, controller.signal);
200
+ } finally {
201
+ clearTimeout(timeout);
202
+ externalSignal?.removeEventListener("abort", abortFromCaller);
203
+ }
204
+ }
205
+ function delay(milliseconds, signal) {
206
+ if (milliseconds === 0) {
207
+ throwIfAborted(signal);
208
+ return Promise.resolve();
209
+ }
210
+ return new Promise((resolve, reject) => {
211
+ const timeout = setTimeout(() => {
212
+ signal.removeEventListener("abort", onAbort);
213
+ resolve();
214
+ }, milliseconds);
215
+ const onAbort = () => {
216
+ clearTimeout(timeout);
217
+ reject(abortReason(signal));
218
+ };
219
+ if (signal.aborted) {
220
+ onAbort();
221
+ } else {
222
+ signal.addEventListener("abort", onAbort, { once: true });
223
+ }
224
+ });
225
+ }
226
+ function raceWithAbort(operation, signal) {
227
+ if (signal.aborted) return Promise.reject(abortReason(signal));
228
+ return new Promise((resolve, reject) => {
229
+ const onAbort = () => {
230
+ cleanup();
231
+ reject(abortReason(signal));
232
+ };
233
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
234
+ signal.addEventListener("abort", onAbort, { once: true });
235
+ operation.then(
236
+ (value) => {
237
+ cleanup();
238
+ resolve(value);
239
+ },
240
+ (error) => {
241
+ cleanup();
242
+ reject(error);
243
+ }
244
+ );
245
+ });
246
+ }
247
+ function throwIfAborted(signal) {
248
+ if (signal.aborted) throw abortReason(signal);
249
+ }
250
+ function abortReason(signal) {
251
+ if (signal.reason instanceof Error) return signal.reason;
252
+ const error = new Error("Tileflow static map request was aborted");
253
+ error.name = "AbortError";
254
+ return error;
255
+ }
256
+ function assertStaticMapOperationIdentity(expected, actual) {
257
+ if (expected !== null && actual !== expected) {
258
+ throw new Error("Tileflow static map changed operation identity while polling");
259
+ }
260
+ }
261
+ function normalizeUrl(value) {
262
+ const url = new URL(value);
263
+ if (!isSafeHttpUrl(value) || url.search) {
264
+ throw new TypeError(
265
+ "Tileflow Static Maps apiUrl must be HTTP(S) without credentials, query, or fragment"
266
+ );
267
+ }
268
+ return url.toString().replace(/\/+$/, "");
269
+ }
270
+ function normalizeStaticMapEndpointUrl(value) {
271
+ if (value.startsWith("/")) {
272
+ if (value.startsWith("//") || value.length > 2048 || /[\\?#]/u.test(value) || hasControlCharacter(value)) {
273
+ throw new TypeError(
274
+ "Tileflow Static Maps createUrl must be HTTP(S) without credentials, query, or fragment or a safe root-relative path"
275
+ );
276
+ }
277
+ return value;
278
+ }
279
+ const url = new URL(value);
280
+ if (!isSafeHttpUrl(value) || url.search) {
281
+ throw new TypeError(
282
+ "Tileflow Static Maps createUrl must be HTTP(S) without credentials, query, or fragment or a safe root-relative path"
283
+ );
284
+ }
285
+ return url.toString();
286
+ }
287
+ function hasControlCharacter(value) {
288
+ for (let index = 0; index < value.length; index += 1) {
289
+ const codePoint = value.charCodeAt(index);
290
+ if (codePoint <= 31 || codePoint === 127) return true;
291
+ }
292
+ return false;
293
+ }
294
+
295
+ export {
296
+ staticMapReadyResultSchema,
297
+ staticMapProcessingResultSchema,
298
+ validateStaticMapIdempotencyKey,
299
+ createStaticMapIdempotencyKey,
300
+ prepareStaticMapRequest,
301
+ createStaticMap,
302
+ precacheStaticMap,
303
+ requestStaticMapUntilReady
304
+ };
@@ -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.ZodNullable<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-QCR76BUO.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
+ };