@honua/react 0.1.2-beta.0 → 0.1.4-beta.0
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/contract/discovery.d.ts +34 -0
- package/contract/discovery.d.ts.map +1 -1
- package/contract/index.d.ts +7 -5
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +3 -2
- package/contract/pmtiles.d.ts +10 -1
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +10 -2
- package/contract/protocol-module.d.ts +84 -9
- package/contract/protocol-module.d.ts.map +1 -1
- package/contract/query-filter-fes.d.ts +18 -0
- package/contract/query-filter-fes.d.ts.map +1 -0
- package/contract/query-filter-fes.js +122 -0
- package/contract/query-filter.d.ts +300 -0
- package/contract/query-filter.d.ts.map +1 -0
- package/contract/query-filter.js +883 -0
- package/contract/schema.d.ts +12 -0
- package/contract/schema.d.ts.map +1 -1
- package/contract/schema.js +34 -0
- package/contract/source-capability-support.d.ts.map +1 -1
- package/contract/source-capability-support.js +15 -3
- package/contract/source.d.ts +45 -25
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +719 -479
- package/contract/types.d.ts +87 -18
- package/contract/types.d.ts.map +1 -1
- package/contract/widget-source.d.ts.map +1 -1
- package/core/client.d.ts +45 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +224 -46
- package/core/error-classifications.d.ts +6 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +6 -0
- package/core/error-code-registry.d.ts +6 -0
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +6 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +68 -4
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +325 -8
- package/core/odata-write-codec.d.ts.map +1 -1
- package/core/odata-write-codec.js +0 -1
- package/core/odata.d.ts +6 -0
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +6 -1
- package/core/ogc-processes.d.ts +182 -25
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +602 -30
- package/core/process-runner.d.ts +8 -1
- package/core/process-runner.d.ts.map +1 -1
- package/core/process-runner.js +1 -0
- package/core/protocol-transport.d.ts +2 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/stac.d.ts +31 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +136 -19
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +123 -9
- package/core/types.d.ts.map +1 -1
- package/core/wfs-axis-order.d.ts +18 -0
- package/core/wfs-axis-order.d.ts.map +1 -0
- package/core/wfs-axis-order.js +108 -0
- package/core/wfs-capabilities.d.ts +65 -24
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +237 -27
- package/core/wfs-filter.d.ts +26 -3
- package/core/wfs-filter.d.ts.map +1 -1
- package/core/wfs-filter.js +48 -53
- package/core/wfs-protocol-error.d.ts +12 -0
- package/core/wfs-protocol-error.d.ts.map +1 -0
- package/core/wfs-protocol-error.js +13 -0
- package/core/wfs.d.ts +53 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +251 -29
- package/core/wms-feature-info.d.ts +92 -0
- package/core/wms-feature-info.d.ts.map +1 -0
- package/core/wms-feature-info.js +285 -0
- package/core/wms.d.ts +9 -0
- package/core/wms.d.ts.map +1 -1
- package/core/wms.js +17 -5
- package/esri-compat/event-bus.d.ts +20 -0
- package/esri-compat/event-bus.d.ts.map +1 -1
- package/esri-compat/feature-filter.d.ts +46 -1
- package/esri-compat/feature-filter.d.ts.map +1 -1
- package/esri-compat/feature-filter.js +49 -0
- package/esri-compat/geojson-layer.d.ts +4 -2
- package/esri-compat/geojson-layer.d.ts.map +1 -1
- package/esri-compat/geojson-layer.js +4 -2
- package/esri-compat/identity-manager.js +2 -2
- package/esri-compat/imagery-layer.d.ts +2 -1
- package/esri-compat/imagery-layer.d.ts.map +1 -1
- package/esri-compat/imagery-layer.js +2 -1
- package/esri-compat/layer-list.d.ts +8 -1
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +11 -4
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +1 -1
- package/esri-compat/locator.d.ts +297 -0
- package/esri-compat/locator.d.ts.map +1 -0
- package/esri-compat/locator.js +579 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -1
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +1 -1
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/time-slider.d.ts +29 -0
- package/esri-compat/time-slider.d.ts.map +1 -1
- package/esri-compat/time-slider.js +117 -0
- package/esri-compat/wfs-layer.d.ts +2 -1
- package/esri-compat/wfs-layer.d.ts.map +1 -1
- package/esri-compat/wfs-layer.js +2 -1
- package/esri-compat/widget-host.d.ts +42 -6
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +99 -10
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/runtime.d.ts.map +1 -1
- package/map/data-to-map-bridge.d.ts +1 -1
- package/map/data-to-map-bridge.d.ts.map +1 -1
- package/map/data-to-map-bridge.js +1 -2
- package/map/honua-map.d.ts.map +1 -1
- package/map/honua-map.js +1 -1
- package/map/index.d.ts +2 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +2 -0
- package/map/realtime-reconciliation-adapter.d.ts +98 -0
- package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
- package/map/realtime-reconciliation-adapter.js +84 -0
- package/map/temporal-playback.d.ts +25 -0
- package/map/temporal-playback.d.ts.map +1 -1
- package/map/temporal-playback.js +29 -1
- package/package.json +4 -3
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- package/query-planner/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -0
- package/query-planner/diagnostics.d.ts +3 -3
- package/query-planner/diagnostics.d.ts.map +1 -1
- package/query-planner/diagnostics.js +17 -4
- package/query-planner/duckdb.d.ts.map +1 -1
- package/query-planner/duckdb.js +16 -2
- package/query-planner/execution-context.d.ts.map +1 -1
- package/query-planner/execution-context.js +3 -1
- package/query-planner/executor.d.ts.map +1 -1
- package/query-planner/executor.js +7 -1
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +24 -5
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +29 -5
- package/query-planner/index.d.ts +20 -5
- package/query-planner/index.d.ts.map +1 -1
- package/query-planner/index.js +16 -3
- package/query-planner/ir.d.ts +6 -1
- package/query-planner/ir.d.ts.map +1 -1
- package/query-planner/ir.js +63 -1
- package/query-planner/odata-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +0 -3
- package/query-planner/odata.d.ts.map +1 -1
- package/query-planner/odata.js +0 -143
- package/query-planner/ogc-features.d.ts.map +1 -1
- package/query-planner/ogc-features.js +23 -1
- package/query-planner/planner.d.ts +2 -2
- package/query-planner/planner.d.ts.map +1 -1
- package/query-planner/planner.js +146 -27
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -0
- package/query-planner/types.d.ts +153 -3
- package/query-planner/types.d.ts.map +1 -1
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -0
- package/query-planner/wfs-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +1 -3
- package/query-planner/wfs.d.ts.map +1 -1
- package/query-planner/wfs.js +1 -70
- package/react/honua-map.d.ts +3 -1
- package/react/honua-map.d.ts.map +1 -1
- package/react/honua-map.js +11 -1
- package/react/hooks.d.ts +1 -1
- package/react/hooks.js +1 -1
- package/react/selection.d.ts.map +1 -1
- package/react/selection.js +0 -0
- package/react/use-mounted-source.d.ts +1 -1
- package/react/use-mounted-source.js +1 -1
- package/realtime/checkpoint-store.d.ts +206 -0
- package/realtime/checkpoint-store.d.ts.map +1 -0
- package/realtime/checkpoint-store.js +504 -0
- package/realtime/contract.d.ts +142 -0
- package/realtime/contract.d.ts.map +1 -0
- package/realtime/contract.js +154 -0
- package/realtime/exploration.d.ts +16 -0
- package/realtime/exploration.d.ts.map +1 -0
- package/realtime/exploration.js +32 -0
- package/realtime/honua-server.d.ts +131 -0
- package/realtime/honua-server.d.ts.map +1 -0
- package/realtime/honua-server.js +302 -0
- package/realtime/index.d.ts +39 -0
- package/realtime/index.d.ts.map +1 -0
- package/realtime/index.js +26 -0
- package/realtime/odata-delta.d.ts +114 -0
- package/realtime/odata-delta.d.ts.map +1 -0
- package/realtime/odata-delta.js +483 -0
- package/realtime/projections.d.ts +30 -0
- package/realtime/projections.d.ts.map +1 -0
- package/realtime/projections.js +51 -0
- package/realtime/reconciliation.d.ts +245 -0
- package/realtime/reconciliation.d.ts.map +1 -0
- package/realtime/reconciliation.js +377 -0
- package/realtime/reducer.d.ts +14 -0
- package/realtime/reducer.d.ts.map +1 -0
- package/realtime/reducer.js +351 -0
- package/realtime/resumable-transport.d.ts +111 -0
- package/realtime/resumable-transport.d.ts.map +1 -0
- package/realtime/resumable-transport.js +406 -0
- package/realtime/resumable.d.ts +104 -0
- package/realtime/resumable.d.ts.map +1 -0
- package/realtime/resumable.js +632 -0
- package/realtime/sse.d.ts +23 -0
- package/realtime/sse.d.ts.map +1 -0
- package/realtime/sse.js +147 -0
- package/realtime/store.d.ts +18 -0
- package/realtime/store.d.ts.map +1 -0
- package/realtime/store.js +63 -0
- package/realtime/types.d.ts +190 -0
- package/realtime/types.d.ts.map +1 -0
- package/realtime/types.js +10 -0
- package/realtime/websocket.d.ts +60 -0
- package/realtime/websocket.d.ts.map +1 -0
- package/realtime/websocket.js +157 -0
- package/realtime/wire.d.ts +28 -0
- package/realtime/wire.d.ts.map +1 -0
- package/realtime/wire.js +73 -0
- package/runtime/index.d.ts +6 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -1
- package/runtime/load-package.d.ts +24 -0
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +45 -1
- package/runtime/maplibre-renderer.d.ts +11 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -1
- package/runtime/maplibre-renderer.js +32 -7
- package/runtime/offline-region-protocol.d.ts +73 -0
- package/runtime/offline-region-protocol.d.ts.map +1 -0
- package/runtime/offline-region-protocol.js +63 -0
- package/runtime/offline-region-style.d.ts +78 -0
- package/runtime/offline-region-style.d.ts.map +1 -0
- package/runtime/offline-region-style.js +147 -0
- package/runtime/pmtiles-protocol.d.ts +7 -8
- package/runtime/pmtiles-protocol.d.ts.map +1 -1
- package/runtime/pmtiles-protocol.js +19 -66
- package/runtime/protocol-registry.d.ts +55 -0
- package/runtime/protocol-registry.d.ts.map +1 -0
- package/runtime/protocol-registry.js +103 -0
- package/runtime/runtime.d.ts +2 -0
- package/runtime/runtime.d.ts.map +1 -1
- package/runtime/runtime.js +6 -1
- package/studio/index.d.ts +24 -7
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -7
- package/studio/lifecycle-client.d.ts +164 -0
- package/studio/lifecycle-client.d.ts.map +1 -0
- package/studio/lifecycle-client.js +299 -0
- package/studio/lifecycle-errors.d.ts +91 -0
- package/studio/lifecycle-errors.d.ts.map +1 -0
- package/studio/lifecycle-errors.js +77 -0
- package/studio/lifecycle-types.d.ts +321 -0
- package/studio/lifecycle-types.d.ts.map +1 -0
- package/studio/lifecycle-types.js +22 -0
- package/webmap/convert-label.js +0 -1
- package/webmap/convert-symbol.d.ts.map +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-registration of the MapLibre `offline-region://` protocol.
|
|
3
|
+
*
|
|
4
|
+
* A style whose tile sources address a persisted offline region renders through
|
|
5
|
+
* a protocol handler built by `@honua/sdk-js/offline`
|
|
6
|
+
* (`createOfflineRegionTileProtocol`). This module registers that handler on
|
|
7
|
+
* MapLibre once, through the same shared registry `pmtiles://` uses.
|
|
8
|
+
*
|
|
9
|
+
* The runtime deliberately does **not** import `@honua/sdk-js/offline` and does
|
|
10
|
+
* not build the handler itself. A handler is bound to one region manifest, one
|
|
11
|
+
* store, and one authorization scope, none of which the runtime can invent —
|
|
12
|
+
* so the caller supplies the handler and the runtime decides only *when* it must
|
|
13
|
+
* be registered. That also keeps the offline module graph out of every map that
|
|
14
|
+
* never reads from a region.
|
|
15
|
+
*
|
|
16
|
+
* Registration is triggered by evidence, never by import: `loadMapPackage`
|
|
17
|
+
* registers when the composed style actually references the scheme, and fails
|
|
18
|
+
* closed when it does but no handler was supplied — because a missing handler
|
|
19
|
+
* renders blank tiles rather than an error.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import { ensureMaplibreProtocol, isMaplibreProtocolRegistered, resetMaplibreProtocol, styleUsesProtocolScheme, } from "./protocol-registry.js";
|
|
24
|
+
/** The MapLibre protocol scheme persisted offline regions are addressed under. */
|
|
25
|
+
export const OFFLINE_REGION_PROTOCOL_SCHEME = "offline-region";
|
|
26
|
+
/**
|
|
27
|
+
* Register the `offline-region://` protocol on MapLibre if it is not registered
|
|
28
|
+
* already. Idempotent per scheme, exactly like the PMTiles registration: several
|
|
29
|
+
* maps loading the same region concurrently share one registration.
|
|
30
|
+
*
|
|
31
|
+
* Because MapLibre's protocol table is process-global, the *first* handler wins
|
|
32
|
+
* for a given scheme. A host that needs to serve a different region on the same
|
|
33
|
+
* scheme must {@link resetOfflineRegionProtocol} first, or register the second
|
|
34
|
+
* region under its own scheme.
|
|
35
|
+
*/
|
|
36
|
+
export async function ensureOfflineRegionProtocol(deps) {
|
|
37
|
+
if (typeof deps?.tileHandler !== "function") {
|
|
38
|
+
throw new TypeError("An offline-region tile handler is required; build one with createOfflineRegionTileProtocol() from @honua/sdk-js/offline.");
|
|
39
|
+
}
|
|
40
|
+
await ensureMaplibreProtocol({
|
|
41
|
+
scheme: deps.scheme ?? OFFLINE_REGION_PROTOCOL_SCHEME,
|
|
42
|
+
...(deps.maplibre ? { maplibre: deps.maplibre } : {}),
|
|
43
|
+
createHandler: () => deps.tileHandler,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/** Whether the `offline-region://` protocol (or `scheme`) is currently registered. */
|
|
47
|
+
export function isOfflineRegionProtocolRegistered(scheme = OFFLINE_REGION_PROTOCOL_SCHEME) {
|
|
48
|
+
return isMaplibreProtocolRegistered(scheme);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Release a prior {@link ensureOfflineRegionProtocol} registration, so a later
|
|
52
|
+
* call can bind a different region's handler to the same scheme.
|
|
53
|
+
*/
|
|
54
|
+
export function resetOfflineRegionProtocol(scheme = OFFLINE_REGION_PROTOCOL_SCHEME) {
|
|
55
|
+
resetMaplibreProtocol(scheme);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Whether a composed MapLibre style references at least one `offline-region://`
|
|
59
|
+
* source. This is the evidence `loadMapPackage` registers on.
|
|
60
|
+
*/
|
|
61
|
+
export function styleUsesOfflineRegion(style, scheme = OFFLINE_REGION_PROTOCOL_SCHEME) {
|
|
62
|
+
return styleUsesProtocolScheme(style, scheme);
|
|
63
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewriting a style's tile templates onto the `offline-region://` scheme.
|
|
3
|
+
*
|
|
4
|
+
* A persisted region can only answer what it was addressed for, so pointing a
|
|
5
|
+
* style at one is a narrow, mechanical edit: replace a source's single XYZ tile
|
|
6
|
+
* template with `offline-region://<tileMatrixSetId>/{z}/{x}/{y}`. Everything
|
|
7
|
+
* else — TileJSON `url` members, GeoJSON `data`, sprites, glyphs, layer paint —
|
|
8
|
+
* is left exactly as authored.
|
|
9
|
+
*
|
|
10
|
+
* The rewrite is lossless and reversible: it returns a new style plus a record of
|
|
11
|
+
* every replacement, and {@link revertOfflineRegionStyleRewrite} restores the
|
|
12
|
+
* original byte-for-byte. Anything it cannot rewrite *exactly* is refused with a
|
|
13
|
+
* reason rather than guessed at, because a style that silently kept its network
|
|
14
|
+
* template would render live tiles while the application believed it was reading
|
|
15
|
+
* from a region.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
export type OfflineRegionStyleRefusalReason =
|
|
20
|
+
/** No source with this id exists in the style. */
|
|
21
|
+
"unknown-source"
|
|
22
|
+
/** The source is not a tile source (`geojson`, `image`, `video`, …). */
|
|
23
|
+
| "not-a-tile-source"
|
|
24
|
+
/** The source addresses tiles only through a TileJSON `url`, which a region does not serve. */
|
|
25
|
+
| "tilejson-url-only"
|
|
26
|
+
/** The source carries both `url` and `tiles`; which one MapLibre uses is not ours to decide. */
|
|
27
|
+
| "ambiguous-tile-source"
|
|
28
|
+
/** The source has no single tile template to replace. */
|
|
29
|
+
| "multiple-tile-templates"
|
|
30
|
+
/** The template is not a plain `{z}/{x}/{y}` address. */
|
|
31
|
+
| "unsupported-tile-template"
|
|
32
|
+
/** The template already addresses the offline scheme. */
|
|
33
|
+
| "already-rewritten";
|
|
34
|
+
export interface OfflineRegionStyleRefusalV1 {
|
|
35
|
+
readonly sourceId: string;
|
|
36
|
+
readonly reason: OfflineRegionStyleRefusalReason;
|
|
37
|
+
readonly detail: string;
|
|
38
|
+
}
|
|
39
|
+
/** One replacement, carrying exactly what is needed to undo it. */
|
|
40
|
+
export interface OfflineRegionStyleRewriteEntryV1 {
|
|
41
|
+
readonly sourceId: string;
|
|
42
|
+
readonly member: "tiles";
|
|
43
|
+
readonly index: number;
|
|
44
|
+
readonly from: string;
|
|
45
|
+
readonly to: string;
|
|
46
|
+
}
|
|
47
|
+
export interface OfflineRegionStyleRewriteV1<TStyle = unknown> {
|
|
48
|
+
/** A new style. The input is never mutated. */
|
|
49
|
+
readonly style: TStyle;
|
|
50
|
+
readonly rewrites: readonly OfflineRegionStyleRewriteEntryV1[];
|
|
51
|
+
readonly refusals: readonly OfflineRegionStyleRefusalV1[];
|
|
52
|
+
}
|
|
53
|
+
export interface RewriteStyleTilesForOfflineRegionOptions {
|
|
54
|
+
/** Style source ids to serve from the region. Only these are considered. */
|
|
55
|
+
readonly sourceIds: readonly string[];
|
|
56
|
+
/** Tile-matrix-set segment of the rewritten URL. Defaults to `"default"`. */
|
|
57
|
+
readonly tileMatrixSetId?: string;
|
|
58
|
+
/** Protocol scheme. Defaults to `"offline-region"`. */
|
|
59
|
+
readonly scheme?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Point the named tile sources at a persisted offline region.
|
|
63
|
+
*
|
|
64
|
+
* Rewrites only `sources[id].tiles[0]`, and only when that source is a
|
|
65
|
+
* `vector`, `raster`, or `raster-dem` source whose single template is a plain
|
|
66
|
+
* `{z}`/`{x}`/`{y}` address. Every other shape is refused; the caller decides
|
|
67
|
+
* whether a refusal is fatal.
|
|
68
|
+
*/
|
|
69
|
+
export declare function rewriteStyleTilesForOfflineRegion<TStyle>(style: TStyle, options: RewriteStyleTilesForOfflineRegionOptions): OfflineRegionStyleRewriteV1<TStyle>;
|
|
70
|
+
/**
|
|
71
|
+
* Undo a rewrite, restoring every original template exactly.
|
|
72
|
+
*
|
|
73
|
+
* Applying this to the style a rewrite produced yields a style deep-equal to the
|
|
74
|
+
* one that went in, which is what makes the offline binding safe to apply to a
|
|
75
|
+
* package a host still owns.
|
|
76
|
+
*/
|
|
77
|
+
export declare function revertOfflineRegionStyleRewrite<TStyle>(style: TStyle, rewrite: Pick<OfflineRegionStyleRewriteV1, "rewrites">): TStyle;
|
|
78
|
+
//# sourceMappingURL=offline-region-style.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-region-style.d.ts","sourceRoot":"","sources":["../../../src/runtime/offline-region-style.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAUH,MAAM,MAAM,+BAA+B;AACzC,kDAAkD;AAChD,gBAAgB;AAClB,wEAAwE;GACtE,mBAAmB;AACrB,+FAA+F;GAC7F,mBAAmB;AACrB,gGAAgG;GAC9F,uBAAuB;AACzB,yDAAyD;GACvD,yBAAyB;AAC3B,yDAAyD;GACvD,2BAA2B;AAC7B,yDAAyD;GACvD,mBAAmB,CAAC;AAExB,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,+BAA+B,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,mEAAmE;AACnE,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B,CAAC,MAAM,GAAG,OAAO;IAC3D,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAC/D,QAAQ,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC3D;AAED,MAAM,WAAW,wCAAwC;IACvD,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAOD;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EACtD,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,wCAAwC,GAChD,2BAA2B,CAAC,MAAM,CAAC,CAmCrC;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EACpD,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,IAAI,CAAC,2BAA2B,EAAE,UAAU,CAAC,GACrD,MAAM,CAqBR"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewriting a style's tile templates onto the `offline-region://` scheme.
|
|
3
|
+
*
|
|
4
|
+
* A persisted region can only answer what it was addressed for, so pointing a
|
|
5
|
+
* style at one is a narrow, mechanical edit: replace a source's single XYZ tile
|
|
6
|
+
* template with `offline-region://<tileMatrixSetId>/{z}/{x}/{y}`. Everything
|
|
7
|
+
* else — TileJSON `url` members, GeoJSON `data`, sprites, glyphs, layer paint —
|
|
8
|
+
* is left exactly as authored.
|
|
9
|
+
*
|
|
10
|
+
* The rewrite is lossless and reversible: it returns a new style plus a record of
|
|
11
|
+
* every replacement, and {@link revertOfflineRegionStyleRewrite} restores the
|
|
12
|
+
* original byte-for-byte. Anything it cannot rewrite *exactly* is refused with a
|
|
13
|
+
* reason rather than guessed at, because a style that silently kept its network
|
|
14
|
+
* template would render live tiles while the application believed it was reading
|
|
15
|
+
* from a region.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { OFFLINE_REGION_PROTOCOL_SCHEME } from "./offline-region-protocol.js";
|
|
20
|
+
/** Source types whose `tiles` templates address XYZ tiles. */
|
|
21
|
+
const TILE_SOURCE_TYPES = new Set(["vector", "raster", "raster-dem"]);
|
|
22
|
+
/** Placeholders the offline tile handler can answer. Anything else is refused. */
|
|
23
|
+
const SUPPORTED_PLACEHOLDERS = new Set(["z", "x", "y"]);
|
|
24
|
+
/**
|
|
25
|
+
* Point the named tile sources at a persisted offline region.
|
|
26
|
+
*
|
|
27
|
+
* Rewrites only `sources[id].tiles[0]`, and only when that source is a
|
|
28
|
+
* `vector`, `raster`, or `raster-dem` source whose single template is a plain
|
|
29
|
+
* `{z}`/`{x}`/`{y}` address. Every other shape is refused; the caller decides
|
|
30
|
+
* whether a refusal is fatal.
|
|
31
|
+
*/
|
|
32
|
+
export function rewriteStyleTilesForOfflineRegion(style, options) {
|
|
33
|
+
const sourceIds = options?.sourceIds;
|
|
34
|
+
if (!Array.isArray(sourceIds) || sourceIds.length === 0) {
|
|
35
|
+
throw new TypeError("rewriteStyleTilesForOfflineRegion requires at least one style source id.");
|
|
36
|
+
}
|
|
37
|
+
const scheme = options.scheme ?? OFFLINE_REGION_PROTOCOL_SCHEME;
|
|
38
|
+
const tileMatrixSetId = options.tileMatrixSetId ?? "default";
|
|
39
|
+
if (tileMatrixSetId.length === 0 || tileMatrixSetId.includes("/")) {
|
|
40
|
+
throw new TypeError("tileMatrixSetId must be a non-empty path segment.");
|
|
41
|
+
}
|
|
42
|
+
const target = `${scheme}://${tileMatrixSetId}/{z}/{x}/{y}`;
|
|
43
|
+
const sources = style?.sources;
|
|
44
|
+
const rewrites = [];
|
|
45
|
+
const refusals = [];
|
|
46
|
+
const replacements = new Map();
|
|
47
|
+
for (const sourceId of sourceIds) {
|
|
48
|
+
const source = sources && typeof sources === "object" ? sources[sourceId] : undefined;
|
|
49
|
+
const refusal = classify(sourceId, source, scheme);
|
|
50
|
+
if (refusal) {
|
|
51
|
+
refusals.push(refusal);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const record = source;
|
|
55
|
+
rewrites.push({ sourceId, member: "tiles", index: 0, from: record.tiles[0], to: target });
|
|
56
|
+
replacements.set(sourceId, { ...record, tiles: [target] });
|
|
57
|
+
}
|
|
58
|
+
if (replacements.size === 0) {
|
|
59
|
+
return { style, rewrites, refusals };
|
|
60
|
+
}
|
|
61
|
+
const nextSources = { ...sources };
|
|
62
|
+
for (const [sourceId, source] of replacements)
|
|
63
|
+
nextSources[sourceId] = source;
|
|
64
|
+
return { style: { ...style, sources: nextSources }, rewrites, refusals };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Undo a rewrite, restoring every original template exactly.
|
|
68
|
+
*
|
|
69
|
+
* Applying this to the style a rewrite produced yields a style deep-equal to the
|
|
70
|
+
* one that went in, which is what makes the offline binding safe to apply to a
|
|
71
|
+
* package a host still owns.
|
|
72
|
+
*/
|
|
73
|
+
export function revertOfflineRegionStyleRewrite(style, rewrite) {
|
|
74
|
+
const entries = rewrite?.rewrites ?? [];
|
|
75
|
+
if (entries.length === 0)
|
|
76
|
+
return style;
|
|
77
|
+
const sources = style?.sources;
|
|
78
|
+
if (!sources || typeof sources !== "object") {
|
|
79
|
+
throw new TypeError("Cannot revert an offline-region rewrite against a style without sources.");
|
|
80
|
+
}
|
|
81
|
+
const nextSources = { ...sources };
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
const source = nextSources[entry.sourceId];
|
|
84
|
+
const current = source?.tiles?.[entry.index];
|
|
85
|
+
if (current !== entry.to) {
|
|
86
|
+
throw new TypeError(`Style source "${entry.sourceId}" no longer carries the rewritten tile template; refusing a partial revert.`);
|
|
87
|
+
}
|
|
88
|
+
const tiles = [...(source?.tiles ?? [])];
|
|
89
|
+
tiles[entry.index] = entry.from;
|
|
90
|
+
nextSources[entry.sourceId] = { ...source, tiles };
|
|
91
|
+
}
|
|
92
|
+
return { ...style, sources: nextSources };
|
|
93
|
+
}
|
|
94
|
+
function classify(sourceId, source, scheme) {
|
|
95
|
+
if (!source || typeof source !== "object") {
|
|
96
|
+
return refuse(sourceId, "unknown-source", "The style declares no source with this id.");
|
|
97
|
+
}
|
|
98
|
+
const record = source;
|
|
99
|
+
if (typeof record.type !== "string" || !TILE_SOURCE_TYPES.has(record.type)) {
|
|
100
|
+
return refuse(sourceId, "not-a-tile-source", `Only vector, raster, and raster-dem sources address tiles; this source is "${String(record.type)}".`);
|
|
101
|
+
}
|
|
102
|
+
const hasTiles = Array.isArray(record.tiles);
|
|
103
|
+
if (record.url !== undefined && hasTiles) {
|
|
104
|
+
return refuse(sourceId, "ambiguous-tile-source", "The source carries both a TileJSON url and a tiles array; remove one before binding it to a region.");
|
|
105
|
+
}
|
|
106
|
+
if (!hasTiles) {
|
|
107
|
+
return refuse(sourceId, "tilejson-url-only", "The source addresses tiles through a TileJSON url, which a persisted region does not serve.");
|
|
108
|
+
}
|
|
109
|
+
const tiles = record.tiles;
|
|
110
|
+
if (tiles.length !== 1 || typeof tiles[0] !== "string") {
|
|
111
|
+
return refuse(sourceId, "multiple-tile-templates", `Exactly one string tile template can be bound to a region; this source declares ${tiles.length}.`);
|
|
112
|
+
}
|
|
113
|
+
const template = tiles[0];
|
|
114
|
+
if (template.startsWith(`${scheme}://`)) {
|
|
115
|
+
return refuse(sourceId, "already-rewritten", "The source already addresses the offline-region scheme.");
|
|
116
|
+
}
|
|
117
|
+
const placeholders = collectPlaceholders(template);
|
|
118
|
+
const missing = ["z", "x", "y"].filter((name) => !placeholders.has(name));
|
|
119
|
+
if (missing.length > 0) {
|
|
120
|
+
return refuse(sourceId, "unsupported-tile-template", `The template is missing the ${missing.join(", ")} placeholder(s) a region addresses tiles by.`);
|
|
121
|
+
}
|
|
122
|
+
for (const placeholder of placeholders) {
|
|
123
|
+
if (!SUPPORTED_PLACEHOLDERS.has(placeholder)) {
|
|
124
|
+
return refuse(sourceId, "unsupported-tile-template", `The template uses the {${placeholder}} placeholder, which a persisted region cannot address.`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
/** Bounded linear scan for `{name}` placeholders; deliberately not a regex. */
|
|
130
|
+
function collectPlaceholders(template) {
|
|
131
|
+
const found = new Set();
|
|
132
|
+
let index = 0;
|
|
133
|
+
while (index < template.length) {
|
|
134
|
+
const open = template.indexOf("{", index);
|
|
135
|
+
if (open < 0)
|
|
136
|
+
break;
|
|
137
|
+
const close = template.indexOf("}", open + 1);
|
|
138
|
+
if (close < 0)
|
|
139
|
+
break;
|
|
140
|
+
found.add(template.slice(open + 1, close));
|
|
141
|
+
index = close + 1;
|
|
142
|
+
}
|
|
143
|
+
return found;
|
|
144
|
+
}
|
|
145
|
+
function refuse(sourceId, reason, detail) {
|
|
146
|
+
return { sourceId, reason, detail };
|
|
147
|
+
}
|
|
@@ -16,16 +16,15 @@
|
|
|
16
16
|
* PMTiles source to a live map through `runtime.addSource` is synchronous — call
|
|
17
17
|
* {@link ensurePmtilesProtocol} yourself beforehand in that case.
|
|
18
18
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
19
|
+
* The registration bookkeeping itself lives in `protocol-registry.ts`, shared
|
|
20
|
+
* with every other scheme the runtime registers; this module owns only the
|
|
21
|
+
* PMTiles policy. The `maplibre-gl` / `pmtiles` slices are injectable so the
|
|
22
|
+
* wiring is unit-testable without either real package.
|
|
21
23
|
*
|
|
22
24
|
* @module
|
|
23
25
|
*/
|
|
24
|
-
|
|
25
|
-
export
|
|
26
|
-
addProtocol(scheme: string, handler: unknown): void;
|
|
27
|
-
removeProtocol?(scheme: string): void;
|
|
28
|
-
}
|
|
26
|
+
import { type MaplibreProtocolRegistrar } from "./protocol-registry.js";
|
|
27
|
+
export type { MaplibreProtocolRegistrar };
|
|
29
28
|
/** The `pmtiles.Protocol` surface this module drives. */
|
|
30
29
|
export interface PmtilesProtocolLike {
|
|
31
30
|
readonly tile: unknown;
|
|
@@ -65,7 +64,7 @@ export declare function isPmtilesProtocolRegistered(scheme?: string): boolean;
|
|
|
65
64
|
* useful if a host wants to fully release the protocol. Best-effort — a
|
|
66
65
|
* registrar without `removeProtocol` just clears the local record.
|
|
67
66
|
*/
|
|
68
|
-
export declare function resetPmtilesProtocol(): void;
|
|
67
|
+
export declare function resetPmtilesProtocol(scheme?: string): void;
|
|
69
68
|
/**
|
|
70
69
|
* Whether a composed MapLibre style references at least one `pmtiles://` source.
|
|
71
70
|
* Used by `loadMapPackage` to decide whether the protocol must be registered
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pmtiles-protocol.d.ts","sourceRoot":"","sources":["../../../src/runtime/pmtiles-protocol.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pmtiles-protocol.d.ts","sourceRoot":"","sources":["../../../src/runtime/pmtiles-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACL,KAAK,yBAAyB,EAK/B,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAE1C,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,0EAA0E;AAC1E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,KAAK,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,mBAAmB,CAAC;CACvG;AAED,8EAA8E;AAC9E,MAAM,WAAW,yBAAyB;IACxC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IAC9C,qDAAqD;IACrD,QAAQ,CAAC,aAAa,CAAC,EAAE,yBAAyB,CAAC;IACnD,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,YAAY,CAAC;AAMjD;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,GAAE,yBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/F;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,MAAM,GAAE,MAAgC,GAAG,OAAO,CAE7F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,MAAgC,GAAG,IAAI,CAEnF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EAC/D,MAAM,GAAE,MAAgC,GACvC,OAAO,CAET"}
|
|
@@ -16,30 +16,16 @@
|
|
|
16
16
|
* PMTiles source to a live map through `runtime.addSource` is synchronous — call
|
|
17
17
|
* {@link ensurePmtilesProtocol} yourself beforehand in that case.
|
|
18
18
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
19
|
+
* The registration bookkeeping itself lives in `protocol-registry.ts`, shared
|
|
20
|
+
* with every other scheme the runtime registers; this module owns only the
|
|
21
|
+
* PMTiles policy. The `maplibre-gl` / `pmtiles` slices are injectable so the
|
|
22
|
+
* wiring is unit-testable without either real package.
|
|
21
23
|
*
|
|
22
24
|
* @module
|
|
23
25
|
*/
|
|
26
|
+
import { ensureMaplibreProtocol, isMaplibreProtocolRegistered, resetMaplibreProtocol, styleUsesProtocolScheme, } from "./protocol-registry.js";
|
|
24
27
|
/** The default MapLibre protocol scheme PMTiles archives are addressed under. */
|
|
25
28
|
export const PMTILES_PROTOCOL_SCHEME = "pmtiles";
|
|
26
|
-
let registration;
|
|
27
|
-
let inFlight;
|
|
28
|
-
/**
|
|
29
|
-
* Resolve the MapLibre `addProtocol` registrar from the lazily-imported module.
|
|
30
|
-
* MapLibre exposes it both as a named ESM export and off the default namespace;
|
|
31
|
-
* accept either so this works against any v5 packaging.
|
|
32
|
-
*/
|
|
33
|
-
async function loadMaplibreRegistrar() {
|
|
34
|
-
const mod = (await import("maplibre-gl"));
|
|
35
|
-
if (typeof mod.addProtocol === "function") {
|
|
36
|
-
return { addProtocol: mod.addProtocol, removeProtocol: mod.removeProtocol };
|
|
37
|
-
}
|
|
38
|
-
if (mod.default && typeof mod.default.addProtocol === "function") {
|
|
39
|
-
return mod.default;
|
|
40
|
-
}
|
|
41
|
-
throw new Error("maplibre-gl does not expose addProtocol(); ensure maplibre-gl >= 2 is installed.");
|
|
42
|
-
}
|
|
43
29
|
async function loadPmtilesModule() {
|
|
44
30
|
return (await import("pmtiles"));
|
|
45
31
|
}
|
|
@@ -53,29 +39,20 @@ async function loadPmtilesModule() {
|
|
|
53
39
|
*/
|
|
54
40
|
export async function ensurePmtilesProtocol(deps = {}) {
|
|
55
41
|
const scheme = deps.scheme ?? PMTILES_PROTOCOL_SCHEME;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
registrar.addProtocol(scheme, protocol.tile);
|
|
67
|
-
registration = { scheme, registrar, protocol };
|
|
68
|
-
})();
|
|
69
|
-
try {
|
|
70
|
-
await inFlight;
|
|
71
|
-
}
|
|
72
|
-
finally {
|
|
73
|
-
inFlight = undefined;
|
|
74
|
-
}
|
|
42
|
+
await ensureMaplibreProtocol({
|
|
43
|
+
scheme,
|
|
44
|
+
...(deps.maplibre ? { maplibre: deps.maplibre } : {}),
|
|
45
|
+
createHandler: async () => {
|
|
46
|
+
const pmtilesModule = deps.pmtilesModule ?? (await loadPmtilesModule());
|
|
47
|
+
// `metadata: true` lets MapLibre auto-populate source attribution and the
|
|
48
|
+
// inspect surface from the archive header without a second wiring step.
|
|
49
|
+
return new pmtilesModule.Protocol({ metadata: true }).tile;
|
|
50
|
+
},
|
|
51
|
+
});
|
|
75
52
|
}
|
|
76
53
|
/** Whether the `pmtiles://` protocol (or `scheme`) is currently registered. */
|
|
77
54
|
export function isPmtilesProtocolRegistered(scheme = PMTILES_PROTOCOL_SCHEME) {
|
|
78
|
-
return
|
|
55
|
+
return isMaplibreProtocolRegistered(scheme);
|
|
79
56
|
}
|
|
80
57
|
/**
|
|
81
58
|
* Tear down a prior {@link ensurePmtilesProtocol} registration. Primarily a test
|
|
@@ -83,25 +60,8 @@ export function isPmtilesProtocolRegistered(scheme = PMTILES_PROTOCOL_SCHEME) {
|
|
|
83
60
|
* useful if a host wants to fully release the protocol. Best-effort — a
|
|
84
61
|
* registrar without `removeProtocol` just clears the local record.
|
|
85
62
|
*/
|
|
86
|
-
export function resetPmtilesProtocol() {
|
|
87
|
-
|
|
88
|
-
registration.registrar.removeProtocol?.(registration.scheme);
|
|
89
|
-
registration = undefined;
|
|
90
|
-
}
|
|
91
|
-
inFlight = undefined;
|
|
92
|
-
}
|
|
93
|
-
function sourceReferencesPmtiles(source, scheme) {
|
|
94
|
-
if (!source || typeof source !== "object")
|
|
95
|
-
return false;
|
|
96
|
-
const prefix = `${scheme}://`;
|
|
97
|
-
const url = source.url;
|
|
98
|
-
if (typeof url === "string" && url.startsWith(prefix))
|
|
99
|
-
return true;
|
|
100
|
-
const tiles = source.tiles;
|
|
101
|
-
if (Array.isArray(tiles) && tiles.some((tile) => typeof tile === "string" && tile.startsWith(prefix))) {
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
return false;
|
|
63
|
+
export function resetPmtilesProtocol(scheme = PMTILES_PROTOCOL_SCHEME) {
|
|
64
|
+
resetMaplibreProtocol(scheme);
|
|
105
65
|
}
|
|
106
66
|
/**
|
|
107
67
|
* Whether a composed MapLibre style references at least one `pmtiles://` source.
|
|
@@ -109,12 +69,5 @@ function sourceReferencesPmtiles(source, scheme) {
|
|
|
109
69
|
* before `map.setStyle`.
|
|
110
70
|
*/
|
|
111
71
|
export function styleUsesPmtiles(style, scheme = PMTILES_PROTOCOL_SCHEME) {
|
|
112
|
-
|
|
113
|
-
if (!sources)
|
|
114
|
-
return false;
|
|
115
|
-
for (const source of Object.values(sources)) {
|
|
116
|
-
if (sourceReferencesPmtiles(source, scheme))
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
return false;
|
|
72
|
+
return styleUsesProtocolScheme(style, scheme);
|
|
120
73
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One idempotent MapLibre protocol registry, shared by every scheme the runtime
|
|
3
|
+
* auto-registers.
|
|
4
|
+
*
|
|
5
|
+
* MapLibre's protocol table is process-global, so registration has to be
|
|
6
|
+
* idempotent, deduplicated across concurrently loading maps, and keyed by scheme
|
|
7
|
+
* rather than by whichever protocol happened to register last. This module owns
|
|
8
|
+
* that bookkeeping once; `pmtiles-protocol.ts` and `offline-region-protocol.ts`
|
|
9
|
+
* are thin policies over it that decide *what* handler a scheme gets and *when* a
|
|
10
|
+
* style needs it.
|
|
11
|
+
*
|
|
12
|
+
* The `maplibre-gl` slice stays injectable so every wiring path is unit-testable
|
|
13
|
+
* without the real peer.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/** The MapLibre `addProtocol` / `removeProtocol` surface this module drives. */
|
|
18
|
+
export interface MaplibreProtocolRegistrar {
|
|
19
|
+
addProtocol(scheme: string, handler: unknown): void;
|
|
20
|
+
removeProtocol?(scheme: string): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the MapLibre `addProtocol` registrar from the lazily-imported module.
|
|
24
|
+
* MapLibre 6 is ESM-only and exposes it as a named export; MapLibre 5 may also
|
|
25
|
+
* surface it off the default namespace depending on how the host bundles the
|
|
26
|
+
* UMD build. Accept either so this works across the `^5 || ^6` peer range.
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadMaplibreRegistrar(): Promise<MaplibreProtocolRegistrar>;
|
|
29
|
+
/**
|
|
30
|
+
* Register `scheme` once, building its handler only when it is actually needed.
|
|
31
|
+
*
|
|
32
|
+
* Repeated calls — including from several maps loading at the same time — share
|
|
33
|
+
* one registration and one in-flight build per scheme. A failed build is not
|
|
34
|
+
* remembered, so a later call can retry.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ensureMaplibreProtocol(options: {
|
|
37
|
+
readonly scheme: string;
|
|
38
|
+
/** Built at most once per scheme, and only when the scheme is not registered. */
|
|
39
|
+
readonly createHandler: () => unknown | Promise<unknown>;
|
|
40
|
+
readonly maplibre?: MaplibreProtocolRegistrar;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
/** Whether `scheme` is currently registered through this registry. */
|
|
43
|
+
export declare function isMaplibreProtocolRegistered(scheme: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Tear down a prior registration. Primarily a test seam so a module-global
|
|
46
|
+
* registration does not leak between cases; also useful if a host wants to fully
|
|
47
|
+
* release a protocol. Best-effort — a registrar without `removeProtocol` just
|
|
48
|
+
* clears the local record.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resetMaplibreProtocol(scheme: string): void;
|
|
51
|
+
/** Whether a composed MapLibre style references at least one `<scheme>://` source. */
|
|
52
|
+
export declare function styleUsesProtocolScheme(style: {
|
|
53
|
+
sources?: Record<string, unknown>;
|
|
54
|
+
} | null | undefined, scheme: string): boolean;
|
|
55
|
+
//# sourceMappingURL=protocol-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-registry.d.ts","sourceRoot":"","sources":["../../../src/runtime/protocol-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gFAAgF;AAChF,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACpD,cAAc,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAUD;;;;;GAKG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,yBAAyB,CAAC,CAehF;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;CAC/C,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhB;AAED,sEAAsE;AACtE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAO1D;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EAC/D,MAAM,EAAE,MAAM,GACb,OAAO,CAQT"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One idempotent MapLibre protocol registry, shared by every scheme the runtime
|
|
3
|
+
* auto-registers.
|
|
4
|
+
*
|
|
5
|
+
* MapLibre's protocol table is process-global, so registration has to be
|
|
6
|
+
* idempotent, deduplicated across concurrently loading maps, and keyed by scheme
|
|
7
|
+
* rather than by whichever protocol happened to register last. This module owns
|
|
8
|
+
* that bookkeeping once; `pmtiles-protocol.ts` and `offline-region-protocol.ts`
|
|
9
|
+
* are thin policies over it that decide *what* handler a scheme gets and *when* a
|
|
10
|
+
* style needs it.
|
|
11
|
+
*
|
|
12
|
+
* The `maplibre-gl` slice stays injectable so every wiring path is unit-testable
|
|
13
|
+
* without the real peer.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
const registrations = new Map();
|
|
18
|
+
const inFlight = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the MapLibre `addProtocol` registrar from the lazily-imported module.
|
|
21
|
+
* MapLibre 6 is ESM-only and exposes it as a named export; MapLibre 5 may also
|
|
22
|
+
* surface it off the default namespace depending on how the host bundles the
|
|
23
|
+
* UMD build. Accept either so this works across the `^5 || ^6` peer range.
|
|
24
|
+
*/
|
|
25
|
+
export async function loadMaplibreRegistrar() {
|
|
26
|
+
const mod = (await import("maplibre-gl"));
|
|
27
|
+
if (typeof mod.addProtocol === "function") {
|
|
28
|
+
return { addProtocol: mod.addProtocol, removeProtocol: mod.removeProtocol };
|
|
29
|
+
}
|
|
30
|
+
if (mod.default && typeof mod.default.addProtocol === "function") {
|
|
31
|
+
return mod.default;
|
|
32
|
+
}
|
|
33
|
+
throw new Error("maplibre-gl does not expose addProtocol(); install maplibre-gl 5.x or 6.x (the SDK peer range is ^5.0.0 || ^6.0.0).");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Register `scheme` once, building its handler only when it is actually needed.
|
|
37
|
+
*
|
|
38
|
+
* Repeated calls — including from several maps loading at the same time — share
|
|
39
|
+
* one registration and one in-flight build per scheme. A failed build is not
|
|
40
|
+
* remembered, so a later call can retry.
|
|
41
|
+
*/
|
|
42
|
+
export async function ensureMaplibreProtocol(options) {
|
|
43
|
+
const scheme = options.scheme;
|
|
44
|
+
if (typeof scheme !== "string" || scheme.length === 0)
|
|
45
|
+
throw new TypeError("A protocol scheme is required.");
|
|
46
|
+
if (registrations.has(scheme))
|
|
47
|
+
return;
|
|
48
|
+
const pending = inFlight.get(scheme);
|
|
49
|
+
if (pending)
|
|
50
|
+
return pending;
|
|
51
|
+
const run = (async () => {
|
|
52
|
+
const registrar = options.maplibre ?? (await loadMaplibreRegistrar());
|
|
53
|
+
const handler = await options.createHandler();
|
|
54
|
+
registrar.addProtocol(scheme, handler);
|
|
55
|
+
registrations.set(scheme, { registrar, handler });
|
|
56
|
+
})();
|
|
57
|
+
inFlight.set(scheme, run);
|
|
58
|
+
try {
|
|
59
|
+
await run;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
inFlight.delete(scheme);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Whether `scheme` is currently registered through this registry. */
|
|
66
|
+
export function isMaplibreProtocolRegistered(scheme) {
|
|
67
|
+
return registrations.has(scheme);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Tear down a prior registration. Primarily a test seam so a module-global
|
|
71
|
+
* registration does not leak between cases; also useful if a host wants to fully
|
|
72
|
+
* release a protocol. Best-effort — a registrar without `removeProtocol` just
|
|
73
|
+
* clears the local record.
|
|
74
|
+
*/
|
|
75
|
+
export function resetMaplibreProtocol(scheme) {
|
|
76
|
+
const registration = registrations.get(scheme);
|
|
77
|
+
if (registration) {
|
|
78
|
+
registration.registrar.removeProtocol?.(scheme);
|
|
79
|
+
registrations.delete(scheme);
|
|
80
|
+
}
|
|
81
|
+
inFlight.delete(scheme);
|
|
82
|
+
}
|
|
83
|
+
/** Whether a composed MapLibre style references at least one `<scheme>://` source. */
|
|
84
|
+
export function styleUsesProtocolScheme(style, scheme) {
|
|
85
|
+
const sources = style?.sources;
|
|
86
|
+
if (!sources)
|
|
87
|
+
return false;
|
|
88
|
+
const prefix = `${scheme}://`;
|
|
89
|
+
for (const source of Object.values(sources)) {
|
|
90
|
+
if (sourceReferencesScheme(source, prefix))
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
function sourceReferencesScheme(source, prefix) {
|
|
96
|
+
if (!source || typeof source !== "object")
|
|
97
|
+
return false;
|
|
98
|
+
const url = source.url;
|
|
99
|
+
if (typeof url === "string" && url.startsWith(prefix))
|
|
100
|
+
return true;
|
|
101
|
+
const tiles = source.tiles;
|
|
102
|
+
return Array.isArray(tiles) && tiles.some((tile) => typeof tile === "string" && tile.startsWith(prefix));
|
|
103
|
+
}
|
package/runtime/runtime.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export interface MaplibreMap extends FeatureStateMap, MapEventTarget {
|
|
|
48
48
|
lat: number;
|
|
49
49
|
} | readonly [number, number];
|
|
50
50
|
fitBounds?(bounds: [[number, number], [number, number]] | [number, number, number, number], options?: Record<string, unknown>): void;
|
|
51
|
+
getContainer?(): HTMLElement;
|
|
51
52
|
jumpTo?(options: {
|
|
52
53
|
center?: [number, number];
|
|
53
54
|
zoom?: number;
|
|
@@ -209,6 +210,7 @@ export declare class HonuaMapRuntime {
|
|
|
209
210
|
remove(): void;
|
|
210
211
|
};
|
|
211
212
|
setViewState(view: SetViewStateInput): void;
|
|
213
|
+
private prefersReducedMotion;
|
|
212
214
|
/**
|
|
213
215
|
* Diff the current package against `next`. Applies the change
|
|
214
216
|
* incrementally when safe; falls back to `map.setStyle` for structural
|