@tileflow/react 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.
- package/README.md +30 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +18 -29
- package/dist/static.d.ts +3 -1
- package/dist/static.js +202 -43
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ manifest:
|
|
|
38
38
|
Or bypass the manifest and load a hosted style directly:
|
|
39
39
|
|
|
40
40
|
```tsx
|
|
41
|
-
<Map styleUrl="https://api.tileflow.dev/
|
|
41
|
+
<Map styleUrl="https://api.tileflow.dev/maps/map_1234567890abcdef/style.json" />
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
For simple hosted static images, use image mode:
|
|
@@ -55,6 +55,35 @@ the production image behavior locally.
|
|
|
55
55
|
For full static scenes with bounds, overlays, and server-side precache, use
|
|
56
56
|
`StaticMap` from `@tileflow/react/static` or helpers from `@tileflow/static`.
|
|
57
57
|
|
|
58
|
+
```tsx
|
|
59
|
+
import {StaticMap} from '@tileflow/react/static';
|
|
60
|
+
import {useState} from 'react';
|
|
61
|
+
import {createStaticMapIdempotencyKey} from '@tileflow/static';
|
|
62
|
+
|
|
63
|
+
export function Preview() {
|
|
64
|
+
const [idempotencyKey] = useState(createStaticMapIdempotencyKey);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<StaticMap
|
|
68
|
+
map="madrid"
|
|
69
|
+
camera={{type: 'center', center: [-3.7038, 40.4168], zoom: 12}}
|
|
70
|
+
size={{width: 1200, height: 800}}
|
|
71
|
+
createUrl="/api/static-maps"
|
|
72
|
+
idempotencyKey={idempotencyKey}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`idempotencyKey` is required in create mode. Keep one key for one intentional create action and
|
|
79
|
+
reuse it across retries and remounts. Concurrent React consumers share work only when URL,
|
|
80
|
+
normalized scene, and idempotency key all identify the same operation; unmounting the final
|
|
81
|
+
consumer aborts its in-flight request.
|
|
82
|
+
|
|
83
|
+
Hosted interactive maps automatically preflight a short-lived commercial session grant before
|
|
84
|
+
eligible resources. Setting `analytics={{enabled: false}}` disables the optional beacon only; it
|
|
85
|
+
does not remove hosted authorization or override a user `mapOptions.transformRequest` callback.
|
|
86
|
+
|
|
58
87
|
## Headless capture readiness
|
|
59
88
|
|
|
60
89
|
Use `captureId` to disambiguate multiple maps with the same configured name:
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ type MapProps = {
|
|
|
14
14
|
styleUrl?: string;
|
|
15
15
|
imageUrl?: string;
|
|
16
16
|
styleBaseUrl?: string;
|
|
17
|
-
tileBaseUrl?: string;
|
|
18
17
|
themes?: TileflowProjectThemes;
|
|
19
18
|
manifestUrl?: string;
|
|
20
19
|
preferLocalDev?: boolean;
|
|
@@ -30,6 +29,6 @@ type MapProps = {
|
|
|
30
29
|
analytics?: TileflowAnalytics;
|
|
31
30
|
onLoad?: (map: Map$1) => void;
|
|
32
31
|
};
|
|
33
|
-
declare function Map({ captureId, map: mapName, mode, config, style, styleUrl, imageUrl, styleBaseUrl,
|
|
32
|
+
declare function Map({ captureId, map: mapName, mode, config, style, styleUrl, imageUrl, styleBaseUrl, themes, manifestUrl, preferLocalDev, alt, center, zoom, className, height, imageLoading, interactive, mapOptions, markers, analytics, onLoad, }: MapProps): react.JSX.Element;
|
|
34
33
|
|
|
35
34
|
export { Map, type MapMarker, type MapProps, type TileflowMapOptions };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
import maplibregl from "maplibre-gl";
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
createTileflowSessionController,
|
|
14
14
|
defaultTileflowManifestUrl,
|
|
15
15
|
loadTileflowManifest,
|
|
16
16
|
mergeTileflowAnalytics,
|
|
@@ -40,7 +40,6 @@ function Map({
|
|
|
40
40
|
styleUrl,
|
|
41
41
|
imageUrl,
|
|
42
42
|
styleBaseUrl,
|
|
43
|
-
tileBaseUrl,
|
|
44
43
|
themes,
|
|
45
44
|
manifestUrl = defaultTileflowManifestUrl,
|
|
46
45
|
preferLocalDev = true,
|
|
@@ -72,11 +71,6 @@ function Map({
|
|
|
72
71
|
const mapNameRef = useRef(mapName);
|
|
73
72
|
const resolvedAnalyticsRef = useRef(void 0);
|
|
74
73
|
const readinessRunRef = useRef(0);
|
|
75
|
-
const sessionId = useMemo(() => createTileflowSessionId(), []);
|
|
76
|
-
const sessionStarter = useMemo(
|
|
77
|
-
() => createTileflowSessionStarter({ sessionId, source: "react" }),
|
|
78
|
-
[sessionId]
|
|
79
|
-
);
|
|
80
74
|
const markerController = useMemo(
|
|
81
75
|
() => createTileflowMarkerController({
|
|
82
76
|
attach(markerInstance, map, marker) {
|
|
@@ -143,8 +137,7 @@ function Map({
|
|
|
143
137
|
style,
|
|
144
138
|
styleBaseUrl,
|
|
145
139
|
styleUrl,
|
|
146
|
-
themes
|
|
147
|
-
tileBaseUrl
|
|
140
|
+
themes
|
|
148
141
|
});
|
|
149
142
|
}, [
|
|
150
143
|
config,
|
|
@@ -155,8 +148,7 @@ function Map({
|
|
|
155
148
|
style,
|
|
156
149
|
styleBaseUrl,
|
|
157
150
|
styleUrl,
|
|
158
|
-
themes
|
|
159
|
-
tileBaseUrl
|
|
151
|
+
themes
|
|
160
152
|
]);
|
|
161
153
|
const resolvedAnalytics = useMemo(
|
|
162
154
|
() => mergeTileflowAnalytics(analytics, runtimeStyle?.analytics),
|
|
@@ -188,16 +180,6 @@ function Map({
|
|
|
188
180
|
}) : void 0),
|
|
189
181
|
[imageSize, imageUrl, isImageMode, manifestMap, resolvedZoom, staticImageCenter]
|
|
190
182
|
);
|
|
191
|
-
const transformRequest = useMemo(
|
|
192
|
-
() => createTileflowTransformRequest({
|
|
193
|
-
always: true,
|
|
194
|
-
asyncAnalyticsTiming: "resolution",
|
|
195
|
-
getAnalytics: () => resolvedAnalyticsRef.current,
|
|
196
|
-
sessionId,
|
|
197
|
-
transformRequest: stableMapOptions?.transformRequest ?? void 0
|
|
198
|
-
}),
|
|
199
|
-
[sessionId, stableMapOptions?.transformRequest]
|
|
200
|
-
);
|
|
201
183
|
useEffect(() => {
|
|
202
184
|
if (!isImageMode || imageUrl || !containerRef.current) {
|
|
203
185
|
setImageSize(null);
|
|
@@ -226,6 +208,20 @@ function Map({
|
|
|
226
208
|
}
|
|
227
209
|
readinessRunRef.current += 1;
|
|
228
210
|
setCaptureState("loading");
|
|
211
|
+
const session = createTileflowSessionController({ source: "react" });
|
|
212
|
+
const sessionStarter = createTileflowSessionStarter({
|
|
213
|
+
getSessionId: () => session.sessionId,
|
|
214
|
+
sessionId: session.sessionId,
|
|
215
|
+
source: "react"
|
|
216
|
+
});
|
|
217
|
+
const transformRequest = createTileflowTransformRequest({
|
|
218
|
+
always: true,
|
|
219
|
+
asyncAnalyticsTiming: "resolution",
|
|
220
|
+
getAnalytics: () => resolvedAnalyticsRef.current,
|
|
221
|
+
sessionController: session,
|
|
222
|
+
sessionId: session.sessionId,
|
|
223
|
+
transformRequest: stableMapOptions?.transformRequest ?? void 0
|
|
224
|
+
});
|
|
229
225
|
const map = new maplibregl.Map({
|
|
230
226
|
...stableMapOptions,
|
|
231
227
|
container: containerRef.current,
|
|
@@ -288,14 +284,7 @@ function Map({
|
|
|
288
284
|
}
|
|
289
285
|
}
|
|
290
286
|
};
|
|
291
|
-
}, [
|
|
292
|
-
markerController,
|
|
293
|
-
resolvedInteractive,
|
|
294
|
-
runtimeStyle,
|
|
295
|
-
sessionStarter,
|
|
296
|
-
stableMapOptions,
|
|
297
|
-
transformRequest
|
|
298
|
-
]);
|
|
287
|
+
}, [markerController, resolvedInteractive, runtimeStyle, stableMapOptions]);
|
|
299
288
|
useLayoutEffect(() => {
|
|
300
289
|
if (!isImageMode) return;
|
|
301
290
|
readinessRunRef.current += 1;
|
package/dist/static.d.ts
CHANGED
|
@@ -16,13 +16,15 @@ type StaticMapBaseProps = StaticSceneInput & {
|
|
|
16
16
|
};
|
|
17
17
|
type StaticMapImageProps = {
|
|
18
18
|
createUrl?: never;
|
|
19
|
+
idempotencyKey?: never;
|
|
19
20
|
imageUrl: string;
|
|
20
21
|
};
|
|
21
22
|
type StaticMapCreateProps = {
|
|
22
23
|
createUrl: string;
|
|
24
|
+
idempotencyKey: string;
|
|
23
25
|
imageUrl?: never;
|
|
24
26
|
};
|
|
25
27
|
type StaticMapProps = StaticMapBaseProps & (StaticMapCreateProps | StaticMapImageProps);
|
|
26
|
-
declare function StaticMap({ alt, camera, className, captureId, createUrl, imageStyle, imageUrl, keepPreviousImage, loading, map, onError, onImageLoad, onReady, overlays, size, style, }: StaticMapProps): react.JSX.Element;
|
|
28
|
+
declare function StaticMap({ alt, camera, className, captureId, createUrl, imageStyle, imageUrl, idempotencyKey, keepPreviousImage, loading, map, onError, onImageLoad, onReady, overlays, size, style, }: StaticMapProps): react.JSX.Element;
|
|
27
29
|
|
|
28
30
|
export { StaticMap, type StaticMapProps };
|
package/dist/static.js
CHANGED
|
@@ -9,8 +9,181 @@ import {
|
|
|
9
9
|
useState
|
|
10
10
|
} from "react";
|
|
11
11
|
import { normalizeTileflowCaptureId } from "@tileflow/core";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
validateStaticMapIdempotencyKey
|
|
14
|
+
} from "@tileflow/static";
|
|
15
|
+
|
|
16
|
+
// src/static-map-request.ts
|
|
17
|
+
import {
|
|
18
|
+
staticMapProcessingResultSchema,
|
|
19
|
+
staticMapReadyResultSchema
|
|
20
|
+
} from "@tileflow/static";
|
|
13
21
|
var inFlightRequests = /* @__PURE__ */ new Map();
|
|
22
|
+
function createStaticMapRequestKey(input) {
|
|
23
|
+
return stableStringify(input);
|
|
24
|
+
}
|
|
25
|
+
async function resolveStaticMap(input) {
|
|
26
|
+
throwIfAborted(input.signal);
|
|
27
|
+
let entry = inFlightRequests.get(input.requestKey);
|
|
28
|
+
if (!entry) {
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const promise = requestStaticMapUntilReady({ ...input, signal: controller.signal });
|
|
31
|
+
const created = {
|
|
32
|
+
controller,
|
|
33
|
+
consumers: 0,
|
|
34
|
+
promise,
|
|
35
|
+
settled: false
|
|
36
|
+
};
|
|
37
|
+
const settle = () => {
|
|
38
|
+
created.settled = true;
|
|
39
|
+
if (inFlightRequests.get(input.requestKey) === created) {
|
|
40
|
+
inFlightRequests.delete(input.requestKey);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
void promise.then(settle, settle);
|
|
44
|
+
inFlightRequests.set(input.requestKey, created);
|
|
45
|
+
entry = created;
|
|
46
|
+
}
|
|
47
|
+
entry.consumers += 1;
|
|
48
|
+
try {
|
|
49
|
+
return await raceWithAbort(entry.promise, input.signal);
|
|
50
|
+
} finally {
|
|
51
|
+
entry.consumers -= 1;
|
|
52
|
+
if (entry.consumers === 0 && !entry.settled) {
|
|
53
|
+
if (inFlightRequests.get(input.requestKey) === entry) {
|
|
54
|
+
inFlightRequests.delete(input.requestKey);
|
|
55
|
+
}
|
|
56
|
+
entry.controller.abort();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function requestStaticMapUntilReady(input) {
|
|
61
|
+
const maxWaitMs = input.maxWaitMs ?? 3e4;
|
|
62
|
+
if (!Number.isSafeInteger(maxWaitMs) || maxWaitMs < 1 || maxWaitMs > 12e4) {
|
|
63
|
+
throw new Error("Static map maxWaitMs must be an integer from 1 to 120000");
|
|
64
|
+
}
|
|
65
|
+
return runWithinBudget(maxWaitMs, input.signal, async (signal) => {
|
|
66
|
+
const body = JSON.stringify(input.scene);
|
|
67
|
+
const fetcher = input.fetch ?? fetch;
|
|
68
|
+
let operationId = null;
|
|
69
|
+
while (true) {
|
|
70
|
+
const response = await fetcher(input.createUrl, {
|
|
71
|
+
body,
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
"Idempotency-Key": input.idempotencyKey
|
|
75
|
+
},
|
|
76
|
+
method: "POST",
|
|
77
|
+
signal
|
|
78
|
+
});
|
|
79
|
+
throwIfAborted(signal);
|
|
80
|
+
if (!response.ok) throw new Error(`Static map endpoint failed: ${response.status}`);
|
|
81
|
+
let value;
|
|
82
|
+
try {
|
|
83
|
+
value = await response.json();
|
|
84
|
+
} catch {
|
|
85
|
+
throw new Error("Static map endpoint returned invalid JSON");
|
|
86
|
+
}
|
|
87
|
+
throwIfAborted(signal);
|
|
88
|
+
if (response.status !== 202) {
|
|
89
|
+
const ready = staticMapReadyResultSchema.safeParse(value);
|
|
90
|
+
if (!ready.success) throw new Error("Static map endpoint returned an invalid response");
|
|
91
|
+
assertStaticMapOperationIdentity(operationId, ready.data.operationId);
|
|
92
|
+
return ready.data;
|
|
93
|
+
}
|
|
94
|
+
const pending = staticMapProcessingResultSchema.safeParse(value);
|
|
95
|
+
if (!pending.success) throw new Error("Static map endpoint returned an invalid response");
|
|
96
|
+
assertStaticMapOperationIdentity(operationId, pending.data.operationId);
|
|
97
|
+
operationId ??= pending.data.operationId;
|
|
98
|
+
await delay(pending.data.retryAfterMs, signal);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function stableStringify(value) {
|
|
103
|
+
return JSON.stringify(sortJson(value));
|
|
104
|
+
}
|
|
105
|
+
function assertStaticMapOperationIdentity(expected, actual) {
|
|
106
|
+
if (expected !== null && actual !== expected) {
|
|
107
|
+
throw new Error("Static map endpoint changed operation identity while polling");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function runWithinBudget(maxWaitMs, externalSignal, operation) {
|
|
111
|
+
const controller = new AbortController();
|
|
112
|
+
const timeoutError = new Error(`Static map request timed out after ${maxWaitMs}ms`);
|
|
113
|
+
const abortFromConsumer = () => controller.abort(externalSignal?.reason);
|
|
114
|
+
if (externalSignal?.aborted) abortFromConsumer();
|
|
115
|
+
else externalSignal?.addEventListener("abort", abortFromConsumer, { once: true });
|
|
116
|
+
const timeout = setTimeout(() => controller.abort(timeoutError), maxWaitMs);
|
|
117
|
+
try {
|
|
118
|
+
throwIfAborted(controller.signal);
|
|
119
|
+
const pending = operation(controller.signal);
|
|
120
|
+
return await raceWithAbort(pending, controller.signal);
|
|
121
|
+
} finally {
|
|
122
|
+
clearTimeout(timeout);
|
|
123
|
+
externalSignal?.removeEventListener("abort", abortFromConsumer);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function delay(milliseconds, signal) {
|
|
127
|
+
if (milliseconds === 0) {
|
|
128
|
+
throwIfAborted(signal);
|
|
129
|
+
return Promise.resolve();
|
|
130
|
+
}
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const timeout = setTimeout(() => {
|
|
133
|
+
signal.removeEventListener("abort", onAbort);
|
|
134
|
+
resolve();
|
|
135
|
+
}, milliseconds);
|
|
136
|
+
const onAbort = () => {
|
|
137
|
+
clearTimeout(timeout);
|
|
138
|
+
reject(abortReason(signal));
|
|
139
|
+
};
|
|
140
|
+
if (signal.aborted) onAbort();
|
|
141
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function raceWithAbort(operation, signal) {
|
|
145
|
+
if (!signal) return operation;
|
|
146
|
+
if (signal.aborted) return Promise.reject(abortReason(signal));
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const onAbort = () => {
|
|
149
|
+
cleanup();
|
|
150
|
+
reject(abortReason(signal));
|
|
151
|
+
};
|
|
152
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
153
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
154
|
+
operation.then(
|
|
155
|
+
(value) => {
|
|
156
|
+
cleanup();
|
|
157
|
+
resolve(value);
|
|
158
|
+
},
|
|
159
|
+
(error) => {
|
|
160
|
+
cleanup();
|
|
161
|
+
reject(error);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function throwIfAborted(signal) {
|
|
167
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
168
|
+
}
|
|
169
|
+
function abortReason(signal) {
|
|
170
|
+
if (signal.reason instanceof Error) return signal.reason;
|
|
171
|
+
const error = new Error("Static map request was aborted");
|
|
172
|
+
error.name = "AbortError";
|
|
173
|
+
return error;
|
|
174
|
+
}
|
|
175
|
+
function sortJson(value) {
|
|
176
|
+
if (Array.isArray(value)) return value.map(sortJson);
|
|
177
|
+
if (value && typeof value === "object") {
|
|
178
|
+
return Object.fromEntries(
|
|
179
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, sortJson(entry)])
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/static-map.tsx
|
|
186
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
187
|
function StaticMap({
|
|
15
188
|
alt = "",
|
|
16
189
|
camera,
|
|
@@ -19,6 +192,7 @@ function StaticMap({
|
|
|
19
192
|
createUrl,
|
|
20
193
|
imageStyle,
|
|
21
194
|
imageUrl,
|
|
195
|
+
idempotencyKey,
|
|
22
196
|
keepPreviousImage = false,
|
|
23
197
|
loading = "lazy",
|
|
24
198
|
map,
|
|
@@ -43,7 +217,7 @@ function StaticMap({
|
|
|
43
217
|
() => stableStringify({ camera, map, overlays, size }),
|
|
44
218
|
[camera, map, overlays, size]
|
|
45
219
|
);
|
|
46
|
-
const
|
|
220
|
+
const intentKey = imageUrl ? `image:${imageUrl}` : `create:${createUrl}:${idempotencyKey ?? ""}:${sceneKey}`;
|
|
47
221
|
useLayoutEffect(() => {
|
|
48
222
|
imageLoadRunRef.current += 1;
|
|
49
223
|
setCaptureState("loading");
|
|
@@ -52,7 +226,7 @@ function StaticMap({
|
|
|
52
226
|
if (image.naturalWidth === 0) setCaptureState("error");
|
|
53
227
|
else void markImageReady(image);
|
|
54
228
|
}
|
|
55
|
-
}, [
|
|
229
|
+
}, [intentKey]);
|
|
56
230
|
async function markImageReady(image) {
|
|
57
231
|
const runId = ++imageLoadRunRef.current;
|
|
58
232
|
try {
|
|
@@ -81,14 +255,31 @@ function StaticMap({
|
|
|
81
255
|
if (!createUrl) {
|
|
82
256
|
return;
|
|
83
257
|
}
|
|
258
|
+
const validation = validateStaticMapIdempotencyKey(idempotencyKey ?? "");
|
|
259
|
+
if (!validation.ok) {
|
|
260
|
+
const keyError = new Error(`Invalid Static Maps idempotency key: ${validation.error}`);
|
|
261
|
+
if (!keepPreviousImage) setResult(null);
|
|
262
|
+
setError(keyError);
|
|
263
|
+
imageLoadRunRef.current += 1;
|
|
264
|
+
setCaptureState("error");
|
|
265
|
+
onErrorRef.current?.(keyError);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
84
268
|
if (!keepPreviousImage) {
|
|
85
269
|
setResult(null);
|
|
86
270
|
}
|
|
87
271
|
setError(null);
|
|
272
|
+
const requestController = new AbortController();
|
|
88
273
|
resolveStaticMap({
|
|
89
274
|
createUrl,
|
|
90
|
-
|
|
91
|
-
|
|
275
|
+
idempotencyKey: validation.key,
|
|
276
|
+
requestKey: createStaticMapRequestKey({
|
|
277
|
+
createUrl,
|
|
278
|
+
idempotencyKey: validation.key,
|
|
279
|
+
sceneKey
|
|
280
|
+
}),
|
|
281
|
+
scene: JSON.parse(sceneKey),
|
|
282
|
+
signal: requestController.signal
|
|
92
283
|
}).then((nextResult) => {
|
|
93
284
|
if (cancelled) {
|
|
94
285
|
return;
|
|
@@ -111,8 +302,9 @@ function StaticMap({
|
|
|
111
302
|
});
|
|
112
303
|
return () => {
|
|
113
304
|
cancelled = true;
|
|
305
|
+
requestController.abort();
|
|
114
306
|
};
|
|
115
|
-
}, [createUrl, imageUrl,
|
|
307
|
+
}, [createUrl, idempotencyKey, imageUrl, intentKey, keepPreviousImage, sceneKey]);
|
|
116
308
|
return /* @__PURE__ */ jsx(
|
|
117
309
|
"div",
|
|
118
310
|
{
|
|
@@ -159,50 +351,17 @@ function StaticMap({
|
|
|
159
351
|
}
|
|
160
352
|
);
|
|
161
353
|
}
|
|
162
|
-
async function resolveStaticMap(input) {
|
|
163
|
-
const existing = inFlightRequests.get(input.requestKey);
|
|
164
|
-
if (existing) {
|
|
165
|
-
return existing;
|
|
166
|
-
}
|
|
167
|
-
const promise = fetch(input.createUrl, {
|
|
168
|
-
body: JSON.stringify(input.scene),
|
|
169
|
-
headers: {
|
|
170
|
-
"Content-Type": "application/json"
|
|
171
|
-
},
|
|
172
|
-
method: "POST"
|
|
173
|
-
}).then(async (response) => {
|
|
174
|
-
if (!response.ok) {
|
|
175
|
-
throw new Error(`Static map endpoint failed: ${response.status}`);
|
|
176
|
-
}
|
|
177
|
-
return await response.json();
|
|
178
|
-
}).finally(() => {
|
|
179
|
-
inFlightRequests.delete(input.requestKey);
|
|
180
|
-
});
|
|
181
|
-
inFlightRequests.set(input.requestKey, promise);
|
|
182
|
-
return promise;
|
|
183
|
-
}
|
|
184
354
|
function imageResult(imageUrl) {
|
|
185
355
|
return {
|
|
186
356
|
cached: true,
|
|
187
357
|
hash: "",
|
|
188
358
|
imageUrl,
|
|
189
|
-
|
|
359
|
+
operationId: null,
|
|
360
|
+
remainingUnits: null,
|
|
361
|
+
status: "ready",
|
|
362
|
+
unitCost: 0
|
|
190
363
|
};
|
|
191
364
|
}
|
|
192
|
-
function stableStringify(value) {
|
|
193
|
-
return JSON.stringify(sortJson(value));
|
|
194
|
-
}
|
|
195
|
-
function sortJson(value) {
|
|
196
|
-
if (Array.isArray(value)) {
|
|
197
|
-
return value.map(sortJson);
|
|
198
|
-
}
|
|
199
|
-
if (value && typeof value === "object") {
|
|
200
|
-
return Object.fromEntries(
|
|
201
|
-
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, sortJson(entry)])
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
return value;
|
|
205
|
-
}
|
|
206
365
|
export {
|
|
207
366
|
StaticMap
|
|
208
367
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.19",
|
|
4
4
|
"description": "React components for rendering Tileflow maps with MapLibre.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
45
|
-
"@tileflow/static": ">=0.1.0-alpha.
|
|
44
|
+
"@tileflow/core": ">=0.1.0-alpha.19 <0.1.0-beta.0",
|
|
45
|
+
"@tileflow/static": ">=0.1.0-alpha.17 <0.1.0-beta.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"maplibre-gl": ">=5",
|