@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.
Files changed (281) hide show
  1. package/contract/discovery.d.ts +34 -0
  2. package/contract/discovery.d.ts.map +1 -1
  3. package/contract/index.d.ts +7 -5
  4. package/contract/index.d.ts.map +1 -1
  5. package/contract/index.js +3 -2
  6. package/contract/pmtiles.d.ts +10 -1
  7. package/contract/pmtiles.d.ts.map +1 -1
  8. package/contract/pmtiles.js +10 -2
  9. package/contract/protocol-module.d.ts +84 -9
  10. package/contract/protocol-module.d.ts.map +1 -1
  11. package/contract/query-filter-fes.d.ts +18 -0
  12. package/contract/query-filter-fes.d.ts.map +1 -0
  13. package/contract/query-filter-fes.js +122 -0
  14. package/contract/query-filter.d.ts +300 -0
  15. package/contract/query-filter.d.ts.map +1 -0
  16. package/contract/query-filter.js +883 -0
  17. package/contract/schema.d.ts +12 -0
  18. package/contract/schema.d.ts.map +1 -1
  19. package/contract/schema.js +34 -0
  20. package/contract/source-capability-support.d.ts.map +1 -1
  21. package/contract/source-capability-support.js +15 -3
  22. package/contract/source.d.ts +45 -25
  23. package/contract/source.d.ts.map +1 -1
  24. package/contract/source.js +719 -479
  25. package/contract/types.d.ts +87 -18
  26. package/contract/types.d.ts.map +1 -1
  27. package/contract/widget-source.d.ts.map +1 -1
  28. package/core/client.d.ts +45 -21
  29. package/core/client.d.ts.map +1 -1
  30. package/core/client.js +224 -46
  31. package/core/error-classifications.d.ts +6 -0
  32. package/core/error-classifications.d.ts.map +1 -1
  33. package/core/error-classifications.js +6 -0
  34. package/core/error-code-registry.d.ts +6 -0
  35. package/core/error-code-registry.d.ts.map +1 -1
  36. package/core/error-code-registry.js +6 -0
  37. package/core/error-envelope.js +2 -0
  38. package/core/errors.d.ts +1 -1
  39. package/core/errors.js +1 -1
  40. package/core/geoparquet-sql.d.ts +68 -4
  41. package/core/geoparquet-sql.d.ts.map +1 -1
  42. package/core/geoparquet-sql.js +325 -8
  43. package/core/odata-write-codec.d.ts.map +1 -1
  44. package/core/odata-write-codec.js +0 -1
  45. package/core/odata.d.ts +6 -0
  46. package/core/odata.d.ts.map +1 -1
  47. package/core/odata.js +6 -1
  48. package/core/ogc-processes.d.ts +182 -25
  49. package/core/ogc-processes.d.ts.map +1 -1
  50. package/core/ogc-processes.js +602 -30
  51. package/core/process-runner.d.ts +8 -1
  52. package/core/process-runner.d.ts.map +1 -1
  53. package/core/process-runner.js +1 -0
  54. package/core/protocol-transport.d.ts +2 -0
  55. package/core/protocol-transport.d.ts.map +1 -1
  56. package/core/stac.d.ts +31 -0
  57. package/core/stac.d.ts.map +1 -1
  58. package/core/stac.js +136 -19
  59. package/core/surfaces.d.ts.map +1 -1
  60. package/core/surfaces.js +273 -68
  61. package/core/types.d.ts +123 -9
  62. package/core/types.d.ts.map +1 -1
  63. package/core/wfs-axis-order.d.ts +18 -0
  64. package/core/wfs-axis-order.d.ts.map +1 -0
  65. package/core/wfs-axis-order.js +108 -0
  66. package/core/wfs-capabilities.d.ts +65 -24
  67. package/core/wfs-capabilities.d.ts.map +1 -1
  68. package/core/wfs-capabilities.js +237 -27
  69. package/core/wfs-filter.d.ts +26 -3
  70. package/core/wfs-filter.d.ts.map +1 -1
  71. package/core/wfs-filter.js +48 -53
  72. package/core/wfs-protocol-error.d.ts +12 -0
  73. package/core/wfs-protocol-error.d.ts.map +1 -0
  74. package/core/wfs-protocol-error.js +13 -0
  75. package/core/wfs.d.ts +53 -1
  76. package/core/wfs.d.ts.map +1 -1
  77. package/core/wfs.js +251 -29
  78. package/core/wms-feature-info.d.ts +92 -0
  79. package/core/wms-feature-info.d.ts.map +1 -0
  80. package/core/wms-feature-info.js +285 -0
  81. package/core/wms.d.ts +9 -0
  82. package/core/wms.d.ts.map +1 -1
  83. package/core/wms.js +17 -5
  84. package/esri-compat/event-bus.d.ts +20 -0
  85. package/esri-compat/event-bus.d.ts.map +1 -1
  86. package/esri-compat/feature-filter.d.ts +46 -1
  87. package/esri-compat/feature-filter.d.ts.map +1 -1
  88. package/esri-compat/feature-filter.js +49 -0
  89. package/esri-compat/geojson-layer.d.ts +4 -2
  90. package/esri-compat/geojson-layer.d.ts.map +1 -1
  91. package/esri-compat/geojson-layer.js +4 -2
  92. package/esri-compat/identity-manager.js +2 -2
  93. package/esri-compat/imagery-layer.d.ts +2 -1
  94. package/esri-compat/imagery-layer.d.ts.map +1 -1
  95. package/esri-compat/imagery-layer.js +2 -1
  96. package/esri-compat/layer-list.d.ts +8 -1
  97. package/esri-compat/layer-list.d.ts.map +1 -1
  98. package/esri-compat/layer-list.js +11 -4
  99. package/esri-compat/legend.d.ts.map +1 -1
  100. package/esri-compat/legend.js +1 -1
  101. package/esri-compat/locator.d.ts +297 -0
  102. package/esri-compat/locator.d.ts.map +1 -0
  103. package/esri-compat/locator.js +579 -0
  104. package/esri-compat/map-image-layer.d.ts.map +1 -1
  105. package/esri-compat/map-view.d.ts.map +1 -1
  106. package/esri-compat/map-view.js +1 -1
  107. package/esri-compat/scene-view.d.ts.map +1 -1
  108. package/esri-compat/time-slider.d.ts +29 -0
  109. package/esri-compat/time-slider.d.ts.map +1 -1
  110. package/esri-compat/time-slider.js +117 -0
  111. package/esri-compat/wfs-layer.d.ts +2 -1
  112. package/esri-compat/wfs-layer.d.ts.map +1 -1
  113. package/esri-compat/wfs-layer.js +2 -1
  114. package/esri-compat/widget-host.d.ts +42 -6
  115. package/esri-compat/widget-host.d.ts.map +1 -1
  116. package/esri-compat/widget-host.js +99 -10
  117. package/generated-app/projection.d.ts.map +1 -1
  118. package/generated-app/runtime.d.ts.map +1 -1
  119. package/map/data-to-map-bridge.d.ts +1 -1
  120. package/map/data-to-map-bridge.d.ts.map +1 -1
  121. package/map/data-to-map-bridge.js +1 -2
  122. package/map/honua-map.d.ts.map +1 -1
  123. package/map/honua-map.js +1 -1
  124. package/map/index.d.ts +2 -0
  125. package/map/index.d.ts.map +1 -1
  126. package/map/index.js +2 -0
  127. package/map/realtime-reconciliation-adapter.d.ts +98 -0
  128. package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
  129. package/map/realtime-reconciliation-adapter.js +84 -0
  130. package/map/temporal-playback.d.ts +25 -0
  131. package/map/temporal-playback.d.ts.map +1 -1
  132. package/map/temporal-playback.js +29 -1
  133. package/package.json +4 -3
  134. package/query-planner/canonical-filter.d.ts +30 -0
  135. package/query-planner/canonical-filter.d.ts.map +1 -0
  136. package/query-planner/canonical-filter.js +30 -0
  137. package/query-planner/columnar-plan.d.ts +63 -0
  138. package/query-planner/columnar-plan.d.ts.map +1 -0
  139. package/query-planner/columnar-plan.js +94 -0
  140. package/query-planner/diagnostics.d.ts +3 -3
  141. package/query-planner/diagnostics.d.ts.map +1 -1
  142. package/query-planner/diagnostics.js +17 -4
  143. package/query-planner/duckdb.d.ts.map +1 -1
  144. package/query-planner/duckdb.js +16 -2
  145. package/query-planner/execution-context.d.ts.map +1 -1
  146. package/query-planner/execution-context.js +3 -1
  147. package/query-planner/executor.d.ts.map +1 -1
  148. package/query-planner/executor.js +7 -1
  149. package/query-planner/geoservices.d.ts.map +1 -1
  150. package/query-planner/geoservices.js +24 -5
  151. package/query-planner/grpc.d.ts.map +1 -1
  152. package/query-planner/grpc.js +29 -5
  153. package/query-planner/index.d.ts +20 -5
  154. package/query-planner/index.d.ts.map +1 -1
  155. package/query-planner/index.js +16 -3
  156. package/query-planner/ir.d.ts +6 -1
  157. package/query-planner/ir.d.ts.map +1 -1
  158. package/query-planner/ir.js +63 -1
  159. package/query-planner/odata-protocol-module.d.ts +54 -0
  160. package/query-planner/odata-protocol-module.d.ts.map +1 -0
  161. package/query-planner/odata-protocol-module.js +199 -0
  162. package/query-planner/odata-v1.d.ts +23 -0
  163. package/query-planner/odata-v1.d.ts.map +1 -0
  164. package/query-planner/odata-v1.js +202 -0
  165. package/query-planner/odata.d.ts +0 -3
  166. package/query-planner/odata.d.ts.map +1 -1
  167. package/query-planner/odata.js +0 -143
  168. package/query-planner/ogc-features.d.ts.map +1 -1
  169. package/query-planner/ogc-features.js +23 -1
  170. package/query-planner/planner.d.ts +2 -2
  171. package/query-planner/planner.d.ts.map +1 -1
  172. package/query-planner/planner.js +146 -27
  173. package/query-planner/representation.d.ts +59 -0
  174. package/query-planner/representation.d.ts.map +1 -0
  175. package/query-planner/representation.js +140 -0
  176. package/query-planner/types.d.ts +153 -3
  177. package/query-planner/types.d.ts.map +1 -1
  178. package/query-planner/wfs-protocol-module.d.ts +57 -0
  179. package/query-planner/wfs-protocol-module.d.ts.map +1 -0
  180. package/query-planner/wfs-protocol-module.js +731 -0
  181. package/query-planner/wfs-v1.d.ts +41 -0
  182. package/query-planner/wfs-v1.d.ts.map +1 -0
  183. package/query-planner/wfs-v1.js +366 -0
  184. package/query-planner/wfs.d.ts +1 -3
  185. package/query-planner/wfs.d.ts.map +1 -1
  186. package/query-planner/wfs.js +1 -70
  187. package/react/honua-map.d.ts +3 -1
  188. package/react/honua-map.d.ts.map +1 -1
  189. package/react/honua-map.js +11 -1
  190. package/react/hooks.d.ts +1 -1
  191. package/react/hooks.js +1 -1
  192. package/react/selection.d.ts.map +1 -1
  193. package/react/selection.js +0 -0
  194. package/react/use-mounted-source.d.ts +1 -1
  195. package/react/use-mounted-source.js +1 -1
  196. package/realtime/checkpoint-store.d.ts +206 -0
  197. package/realtime/checkpoint-store.d.ts.map +1 -0
  198. package/realtime/checkpoint-store.js +504 -0
  199. package/realtime/contract.d.ts +142 -0
  200. package/realtime/contract.d.ts.map +1 -0
  201. package/realtime/contract.js +154 -0
  202. package/realtime/exploration.d.ts +16 -0
  203. package/realtime/exploration.d.ts.map +1 -0
  204. package/realtime/exploration.js +32 -0
  205. package/realtime/honua-server.d.ts +131 -0
  206. package/realtime/honua-server.d.ts.map +1 -0
  207. package/realtime/honua-server.js +302 -0
  208. package/realtime/index.d.ts +39 -0
  209. package/realtime/index.d.ts.map +1 -0
  210. package/realtime/index.js +26 -0
  211. package/realtime/odata-delta.d.ts +114 -0
  212. package/realtime/odata-delta.d.ts.map +1 -0
  213. package/realtime/odata-delta.js +483 -0
  214. package/realtime/projections.d.ts +30 -0
  215. package/realtime/projections.d.ts.map +1 -0
  216. package/realtime/projections.js +51 -0
  217. package/realtime/reconciliation.d.ts +245 -0
  218. package/realtime/reconciliation.d.ts.map +1 -0
  219. package/realtime/reconciliation.js +377 -0
  220. package/realtime/reducer.d.ts +14 -0
  221. package/realtime/reducer.d.ts.map +1 -0
  222. package/realtime/reducer.js +351 -0
  223. package/realtime/resumable-transport.d.ts +111 -0
  224. package/realtime/resumable-transport.d.ts.map +1 -0
  225. package/realtime/resumable-transport.js +406 -0
  226. package/realtime/resumable.d.ts +104 -0
  227. package/realtime/resumable.d.ts.map +1 -0
  228. package/realtime/resumable.js +632 -0
  229. package/realtime/sse.d.ts +23 -0
  230. package/realtime/sse.d.ts.map +1 -0
  231. package/realtime/sse.js +147 -0
  232. package/realtime/store.d.ts +18 -0
  233. package/realtime/store.d.ts.map +1 -0
  234. package/realtime/store.js +63 -0
  235. package/realtime/types.d.ts +190 -0
  236. package/realtime/types.d.ts.map +1 -0
  237. package/realtime/types.js +10 -0
  238. package/realtime/websocket.d.ts +60 -0
  239. package/realtime/websocket.d.ts.map +1 -0
  240. package/realtime/websocket.js +157 -0
  241. package/realtime/wire.d.ts +28 -0
  242. package/realtime/wire.d.ts.map +1 -0
  243. package/realtime/wire.js +73 -0
  244. package/runtime/index.d.ts +6 -2
  245. package/runtime/index.d.ts.map +1 -1
  246. package/runtime/index.js +3 -1
  247. package/runtime/load-package.d.ts +24 -0
  248. package/runtime/load-package.d.ts.map +1 -1
  249. package/runtime/load-package.js +45 -1
  250. package/runtime/maplibre-renderer.d.ts +11 -0
  251. package/runtime/maplibre-renderer.d.ts.map +1 -1
  252. package/runtime/maplibre-renderer.js +32 -7
  253. package/runtime/offline-region-protocol.d.ts +73 -0
  254. package/runtime/offline-region-protocol.d.ts.map +1 -0
  255. package/runtime/offline-region-protocol.js +63 -0
  256. package/runtime/offline-region-style.d.ts +78 -0
  257. package/runtime/offline-region-style.d.ts.map +1 -0
  258. package/runtime/offline-region-style.js +147 -0
  259. package/runtime/pmtiles-protocol.d.ts +7 -8
  260. package/runtime/pmtiles-protocol.d.ts.map +1 -1
  261. package/runtime/pmtiles-protocol.js +19 -66
  262. package/runtime/protocol-registry.d.ts +55 -0
  263. package/runtime/protocol-registry.d.ts.map +1 -0
  264. package/runtime/protocol-registry.js +103 -0
  265. package/runtime/runtime.d.ts +2 -0
  266. package/runtime/runtime.d.ts.map +1 -1
  267. package/runtime/runtime.js +6 -1
  268. package/studio/index.d.ts +24 -7
  269. package/studio/index.d.ts.map +1 -1
  270. package/studio/index.js +21 -7
  271. package/studio/lifecycle-client.d.ts +164 -0
  272. package/studio/lifecycle-client.d.ts.map +1 -0
  273. package/studio/lifecycle-client.js +299 -0
  274. package/studio/lifecycle-errors.d.ts +91 -0
  275. package/studio/lifecycle-errors.d.ts.map +1 -0
  276. package/studio/lifecycle-errors.js +77 -0
  277. package/studio/lifecycle-types.d.ts +321 -0
  278. package/studio/lifecycle-types.d.ts.map +1 -0
  279. package/studio/lifecycle-types.js +22 -0
  280. package/webmap/convert-label.js +0 -1
  281. 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 `maplibre-gl` / `pmtiles` slices are injectable so the wiring is
20
- * unit-testable without either real package.
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
- /** The MapLibre `addProtocol` / `removeProtocol` surface this module drives. */
25
- export interface MaplibreProtocolRegistrar {
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;;;;;;;;;;;;;;;;;;;;;;GAsBG;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;AAED,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;AAmCjD;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,GAAE,yBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB/F;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,MAAM,GAAE,MAAgC,GAAG,OAAO,CAE7F;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAM3C;AAcD;;;;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,CAOT"}
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 `maplibre-gl` / `pmtiles` slices are injectable so the wiring is
20
- * unit-testable without either real package.
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
- if (registration && registration.scheme === scheme)
57
- return;
58
- if (inFlight)
59
- return inFlight;
60
- inFlight = (async () => {
61
- const registrar = deps.maplibre ?? (await loadMaplibreRegistrar());
62
- const pmtilesModule = deps.pmtilesModule ?? (await loadPmtilesModule());
63
- // `metadata: true` lets MapLibre auto-populate source attribution and the
64
- // inspect surface from the archive header without a second wiring step.
65
- const protocol = new pmtilesModule.Protocol({ metadata: true });
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 registration?.scheme === scheme;
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
- if (registration) {
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
- const sources = style?.sources;
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
+ }
@@ -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