@honua/react 0.1.1-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,157 @@
1
+ /**
2
+ * Raw WebSocket wire transport for `@honua/sdk-js/realtime`. Mirrors
3
+ * `sse.ts`'s adapter shape (subscribe params encoded onto the connection URL,
4
+ * default JSON event decoding, `HonuaRealtimeResumeError` failure tagging)
5
+ * so the two transports are interchangeable everywhere a
6
+ * `RealtimeFeatureTransport` is expected, including
7
+ * {@link "./resumable-transport.js".createResumableRealtimeTransport}.
8
+ *
9
+ * This module opens exactly one socket per `subscribe()` call and never
10
+ * reconnects on its own — reconnect/backoff, bounded queueing, and resume
11
+ * ownership live in `resumable-transport.ts` (#557), matching the resumable
12
+ * delivery gate's explicit non-goal ("the gate never reconnects a
13
+ * transport itself").
14
+ *
15
+ * @module
16
+ */
17
+ import { encodeDefaultRealtimeRequest } from "./sse.js";
18
+ import { decodeDefaultRealtimeEnvelope, normalizeRealtimeErrorEvent, realtimeFailure } from "./wire.js";
19
+ const DEFAULT_CLEAN_CLOSE_CODES = [1000];
20
+ export function createRealtimeWebSocketTransport(options) {
21
+ return {
22
+ capabilities: {
23
+ kind: "websocket",
24
+ resumeModes: ["cursor", "watermark", "timestamp", "sequence", "delta-token"],
25
+ emitsHeartbeats: true,
26
+ emitsWatermarks: true,
27
+ },
28
+ subscribe(request, observer) {
29
+ // Mirrors sse.ts: a signal already aborted at subscribe time will never
30
+ // fire its "abort" listener, so bail out before opening a socket that
31
+ // would otherwise leak.
32
+ if (request.signal?.aborted) {
33
+ observer.complete();
34
+ return { close: () => { } };
35
+ }
36
+ let socket;
37
+ try {
38
+ const url = new URL(options.url, "http://honua.local");
39
+ encodeDefaultRealtimeRequest(url, request);
40
+ options.encodeRequest?.(url, request);
41
+ socket = createSocket(resolveWebSocketUrl(options.url, url), options);
42
+ }
43
+ catch (cause) {
44
+ throw realtimeFailure("delivery-failed", "Unable to initialize the realtime WebSocket transport.", cause);
45
+ }
46
+ let closed = false;
47
+ const emitPayload = (payload) => {
48
+ if (closed || payload.trim() === "")
49
+ return;
50
+ let event;
51
+ try {
52
+ const decoded = (options.decodeEvent ?? (decodeDefaultRealtimeEnvelope))(JSON.parse(payload));
53
+ event = normalizeRealtimeErrorEvent(decoded);
54
+ }
55
+ catch (cause) {
56
+ observer.error(realtimeFailure("invalid-event", "Realtime WebSocket payload decoding failed.", cause));
57
+ return;
58
+ }
59
+ try {
60
+ observer.next(event);
61
+ }
62
+ catch (cause) {
63
+ observer.error(realtimeFailure("consumer-failed", "Realtime event observer rejected delivery.", cause));
64
+ }
65
+ };
66
+ socket.onopen = () => {
67
+ if (closed)
68
+ return;
69
+ observer.next({ type: "status", status: "live", receivedAt: Date.now() });
70
+ if (options.encodeSubscribeMessage) {
71
+ try {
72
+ socket.send(JSON.stringify(options.encodeSubscribeMessage(request)));
73
+ }
74
+ catch (cause) {
75
+ observer.error(realtimeFailure("delivery-failed", "Unable to send the realtime WebSocket subscribe message.", cause));
76
+ }
77
+ }
78
+ };
79
+ socket.onmessage = (event) => emitPayload(event.data);
80
+ socket.onerror = () => {
81
+ if (!closed)
82
+ observer.next({ type: "status", status: "reconnecting", reason: "websocket-error", receivedAt: Date.now() });
83
+ };
84
+ socket.onclose = (event) => {
85
+ if (closed)
86
+ return;
87
+ const cleanCodes = options.cleanCloseCodes ?? DEFAULT_CLEAN_CLOSE_CODES;
88
+ const clean = event.wasClean !== false && event.code !== undefined && cleanCodes.includes(event.code);
89
+ closed = true;
90
+ request.signal?.removeEventListener("abort", abortListener);
91
+ detachSocket(socket);
92
+ if (clean) {
93
+ observer.complete();
94
+ return;
95
+ }
96
+ observer.error(realtimeFailure("transport-gap", `Realtime WebSocket transport closed unexpectedly (code ${event.code ?? "unknown"}).`, event));
97
+ };
98
+ const abortListener = () => closeSocket();
99
+ request.signal?.addEventListener("abort", abortListener, { once: true });
100
+ function closeSocket() {
101
+ if (closed)
102
+ return;
103
+ closed = true;
104
+ request.signal?.removeEventListener("abort", abortListener);
105
+ detachSocket(socket);
106
+ try {
107
+ socket.close(1000, "Subscription closed by caller.");
108
+ }
109
+ catch {
110
+ // Closing an already-broken socket is not itself a delivery
111
+ // failure; the caller asked to stop, and stop is what happens.
112
+ }
113
+ observer.complete();
114
+ }
115
+ return {
116
+ close: closeSocket,
117
+ };
118
+ },
119
+ };
120
+ }
121
+ function detachSocket(socket) {
122
+ socket.onopen = null;
123
+ socket.onmessage = null;
124
+ socket.onerror = null;
125
+ socket.onclose = null;
126
+ }
127
+ function createSocket(url, options) {
128
+ if (options.webSocketFactory) {
129
+ return options.webSocketFactory(url, options.protocols);
130
+ }
131
+ // The global `WebSocket` is a constructor; guard rather than assume it is
132
+ // present so Node runtimes without a global WebSocket (or older Node) get
133
+ // an actionable error instead of a silent `undefined` crash, mirroring the
134
+ // `EventSource` guard in sse.ts. No runtime dependency is added for this:
135
+ // `WebSocket` is a web-standard global, optionally polyfilled by callers.
136
+ const WebSocketCtor = globalThis.WebSocket;
137
+ if (!WebSocketCtor) {
138
+ throw new Error("WebSocket is not available; provide webSocketFactory for this runtime.");
139
+ }
140
+ return new WebSocketCtor(url, options.protocols);
141
+ }
142
+ function resolveWebSocketUrl(input, url) {
143
+ if (input.startsWith("ws://") ||
144
+ input.startsWith("wss://") ||
145
+ input.startsWith("http://") ||
146
+ input.startsWith("https://")) {
147
+ // A WebSocket URL must use the ws(s) scheme; rewrite an http(s) origin
148
+ // the same way callers commonly configure REST base URLs.
149
+ const rewritten = new URL(url.toString());
150
+ if (rewritten.protocol === "http:")
151
+ rewritten.protocol = "ws:";
152
+ else if (rewritten.protocol === "https:")
153
+ rewritten.protocol = "wss:";
154
+ return rewritten.toString();
155
+ }
156
+ return `${url.pathname}${url.search}`;
157
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Wire-decoding and failure-tagging helpers shared by every raw realtime
3
+ * transport adapter (`sse.ts`, `websocket.ts`). Extracted so the two
4
+ * transports decode the same default JSON event vocabulary and classify
5
+ * failures through the exact same `HonuaRealtimeResumeError` taxonomy
6
+ * instead of maintaining two copies of the same parsing logic.
7
+ *
8
+ * @module
9
+ */
10
+ import { HonuaRealtimeResumeError } from "./resumable.js";
11
+ import type { RealtimeFeatureEvent } from "./types.js";
12
+ /**
13
+ * Default JSON envelope decoder shared by the SSE and WebSocket transports.
14
+ * Accepts a bare `{ type: ... }` event, a `{ event: { type: ... } } }`
15
+ * wrapper, or a `{ kind: ... }` alias for `type`.
16
+ */
17
+ export declare function decodeDefaultRealtimeEnvelope<TFeature = unknown>(payload: unknown): RealtimeFeatureEvent<TFeature>;
18
+ /**
19
+ * Never trust a structural tag received over the wire. A server could spoof
20
+ * the common envelope while retaining unsanitized context and no `toJSON`.
21
+ * Only a locally constructed realtime error is already inside the boundary.
22
+ */
23
+ export declare function normalizeRealtimeErrorEvent<TFeature>(event: RealtimeFeatureEvent<TFeature>): RealtimeFeatureEvent<TFeature>;
24
+ export type RealtimeTransportFailureCode = "consumer-failed" | "delivery-failed" | "invalid-event" | "transport-gap";
25
+ export type RealtimeWireFailureCode = RealtimeTransportFailureCode | "cursor-expired" | "resume-unsupported";
26
+ export declare function realtimeFailure(code: RealtimeWireFailureCode, message: string, cause: unknown): HonuaRealtimeResumeError;
27
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
28
+ //# sourceMappingURL=wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../../src/realtime/wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAclH;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAClD,KAAK,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GACpC,oBAAoB,CAAC,QAAQ,CAAC,CAuBhC;AAED,MAAM,MAAM,4BAA4B,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,eAAe,GAAG,eAAe,CAAC;AACrH,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAE7G,wBAAgB,eAAe,CAC7B,IAAI,EAAE,uBAAuB,EAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,GACb,wBAAwB,CAM1B;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Wire-decoding and failure-tagging helpers shared by every raw realtime
3
+ * transport adapter (`sse.ts`, `websocket.ts`). Extracted so the two
4
+ * transports decode the same default JSON event vocabulary and classify
5
+ * failures through the exact same `HonuaRealtimeResumeError` taxonomy
6
+ * instead of maintaining two copies of the same parsing logic.
7
+ *
8
+ * @module
9
+ */
10
+ import { isHonuaSdkError } from "../core/error-envelope.js";
11
+ import { HonuaRealtimeResumeError } from "./resumable.js";
12
+ /**
13
+ * Default JSON envelope decoder shared by the SSE and WebSocket transports.
14
+ * Accepts a bare `{ type: ... }` event, a `{ event: { type: ... } } }`
15
+ * wrapper, or a `{ kind: ... }` alias for `type`.
16
+ */
17
+ export function decodeDefaultRealtimeEnvelope(payload) {
18
+ if (!isRecord(payload)) {
19
+ throw new HonuaRealtimeResumeError("invalid-event", "Realtime payload must be a JSON object.");
20
+ }
21
+ if (typeof payload.type === "string") {
22
+ return normalizeRealtimeErrorEvent(payload);
23
+ }
24
+ if (isRecord(payload.event) && typeof payload.event.type === "string") {
25
+ return normalizeRealtimeErrorEvent(payload.event);
26
+ }
27
+ if (typeof payload.kind === "string") {
28
+ return normalizeRealtimeErrorEvent({ ...payload, type: payload.kind });
29
+ }
30
+ throw new HonuaRealtimeResumeError("invalid-event", "Realtime payload is missing an event type.");
31
+ }
32
+ /**
33
+ * Never trust a structural tag received over the wire. A server could spoof
34
+ * the common envelope while retaining unsanitized context and no `toJSON`.
35
+ * Only a locally constructed realtime error is already inside the boundary.
36
+ */
37
+ export function normalizeRealtimeErrorEvent(event) {
38
+ if (event.type !== "error")
39
+ return event;
40
+ const terminal = event.terminal === true;
41
+ const code = terminal ? "invalid-event" : normalizeReconnectableWireCode(event.code);
42
+ const error = realtimeFailure(code, terminal
43
+ ? "Realtime stream reported a terminal protocol failure."
44
+ : code === "cursor-expired"
45
+ ? "Realtime stream reported that its resume cursor expired."
46
+ : code === "resume-unsupported"
47
+ ? "Realtime stream reported that resume is unsupported."
48
+ : "Realtime stream reported a reconnectable transport failure.", undefined);
49
+ return {
50
+ type: "error",
51
+ code,
52
+ error,
53
+ ...(typeof event.terminal === "boolean" ? { terminal: event.terminal } : {}),
54
+ ...(isNonNegativeFiniteNumber(event.retryAfterMs) ? { retryAfterMs: event.retryAfterMs } : {}),
55
+ ...(isNonNegativeFiniteNumber(event.receivedAt) ? { receivedAt: event.receivedAt } : {}),
56
+ };
57
+ }
58
+ export function realtimeFailure(code, message, cause) {
59
+ return cause instanceof HonuaRealtimeResumeError && isHonuaSdkError(cause) && cause.code === code
60
+ ? cause
61
+ : cause === undefined
62
+ ? new HonuaRealtimeResumeError(code, message)
63
+ : new HonuaRealtimeResumeError(code, message, { cause });
64
+ }
65
+ function normalizeReconnectableWireCode(value) {
66
+ return value === "cursor-expired" || value === "resume-unsupported" ? value : "transport-gap";
67
+ }
68
+ function isNonNegativeFiniteNumber(value) {
69
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
70
+ }
71
+ export function isRecord(value) {
72
+ return typeof value === "object" && value !== null;
73
+ }
@@ -7,7 +7,7 @@
7
7
  * ```ts
8
8
  * import { HonuaClient } from "@honua/sdk-js";
9
9
  * import { loadMapPackage } from "@honua/sdk-js/runtime";
10
- * import maplibregl from "maplibre-gl";
10
+ * import * as maplibregl from "maplibre-gl";
11
11
  *
12
12
  * const map = new maplibregl.Map({ container: "map" });
13
13
  * const runtime = await loadMapPackage(pkg, map, {
@@ -21,7 +21,7 @@
21
21
  * @packageDocumentation
22
22
  */
23
23
  export { loadMapPackage } from "./load-package.js";
24
- export type { LoadMapPackageOptions, SourceErrorPolicy } from "./load-package.js";
24
+ export type { LoadMapPackageOfflineRegion, LoadMapPackageOptions, SourceErrorPolicy } from "./load-package.js";
25
25
  export { maplibreRenderer } from "./maplibre-renderer.js";
26
26
  export type { MapLibreRendererFactoryOptions, MapLibreRendererMap, MapLibreRendererOptions, MapLibreRendererPeer, } from "./maplibre-renderer.js";
27
27
  export { BoundedMapPackageFetchCache, DEFAULT_MAP_PACKAGE_CACHE_LIMIT, DEFAULT_MAP_PACKAGE_PATH_PREFIX, defaultMapPackagePath, fetchMapPackage, loadMapPackageFromId, mapPackageFingerprint, resolveMapPackagePath, } from "./map-package-fetch.js";
@@ -46,6 +46,10 @@ export { applyStyleRefs, applyTheme, composeStyle } from "./style-compose.js";
46
46
  export type { StyleComposeOptions, StyleRefResolver, ThemeResolver } from "./style-compose.js";
47
47
  export { PMTILES_PROTOCOL_SCHEME, ensurePmtilesProtocol, isPmtilesProtocolRegistered, resetPmtilesProtocol, styleUsesPmtiles, } from "./pmtiles-protocol.js";
48
48
  export type { EnsurePmtilesProtocolDeps, MaplibreProtocolRegistrar, PmtilesProtocolLike, PmtilesProtocolModuleLike, } from "./pmtiles-protocol.js";
49
+ export { ensureOfflineRegionProtocol, isOfflineRegionProtocolRegistered, OFFLINE_REGION_PROTOCOL_SCHEME, resetOfflineRegionProtocol, styleUsesOfflineRegion, } from "./offline-region-protocol.js";
50
+ export type { EnsureOfflineRegionProtocolDeps, OfflineRegionTileHandler } from "./offline-region-protocol.js";
51
+ export { revertOfflineRegionStyleRewrite, rewriteStyleTilesForOfflineRegion } from "./offline-region-style.js";
52
+ export type { OfflineRegionStyleRefusalReason, OfflineRegionStyleRefusalV1, OfflineRegionStyleRewriteEntryV1, OfflineRegionStyleRewriteV1, RewriteStyleTilesForOfflineRegionOptions, } from "./offline-region-style.js";
49
53
  export { DEFAULT_OGC_STYLES_PATH_PREFIX, MAPLIBRE_STYLE_MEDIA_TYPE, OgcStylesClient, createOgcStyleRefResolver, styleDocumentToRefBody, } from "./ogc-styles.js";
50
54
  export type { OgcStyleLink, OgcStyleList, OgcStyleListEntry, OgcStyleRefResolverOptions, OgcStylesClientOptions, OgcStylesRequestOptions, } from "./ogc-styles.js";
51
55
  export { prepareRuntimeStyleSpecValidation, validateRuntimeFilterStyleSpec, validateRuntimeLayerStyleSpec, validateRuntimeSourceStyleSpec, validateRuntimeStyleExpressionStyleSpec, validateRuntimeStyleSpec, } from "./style-spec-validation.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"}
package/runtime/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * ```ts
8
8
  * import { HonuaClient } from "@honua/sdk-js";
9
9
  * import { loadMapPackage } from "@honua/sdk-js/runtime";
10
- * import maplibregl from "maplibre-gl";
10
+ * import * as maplibregl from "maplibre-gl";
11
11
  *
12
12
  * const map = new maplibregl.Map({ container: "map" });
13
13
  * const runtime = await loadMapPackage(pkg, map, {
@@ -33,6 +33,8 @@ export { buildLegend } from "./legend.js";
33
33
  export { bindPopup, defaultPopupRenderer } from "./popups.js";
34
34
  export { applyStyleRefs, applyTheme, composeStyle } from "./style-compose.js";
35
35
  export { PMTILES_PROTOCOL_SCHEME, ensurePmtilesProtocol, isPmtilesProtocolRegistered, resetPmtilesProtocol, styleUsesPmtiles, } from "./pmtiles-protocol.js";
36
+ export { ensureOfflineRegionProtocol, isOfflineRegionProtocolRegistered, OFFLINE_REGION_PROTOCOL_SCHEME, resetOfflineRegionProtocol, styleUsesOfflineRegion, } from "./offline-region-protocol.js";
37
+ export { revertOfflineRegionStyleRewrite, rewriteStyleTilesForOfflineRegion } from "./offline-region-style.js";
36
38
  export { DEFAULT_OGC_STYLES_PATH_PREFIX, MAPLIBRE_STYLE_MEDIA_TYPE, OgcStylesClient, createOgcStyleRefResolver, styleDocumentToRefBody, } from "./ogc-styles.js";
37
39
  export { prepareRuntimeStyleSpecValidation, validateRuntimeFilterStyleSpec, validateRuntimeLayerStyleSpec, validateRuntimeSourceStyleSpec, validateRuntimeStyleExpressionStyleSpec, validateRuntimeStyleSpec, } from "./style-spec-validation.js";
38
40
  export { buildWmsRasterSourceSpec, buildWmtsRasterSourceSpec, projectSourceBindings, toHonuaSourceSpec, } from "./source-bridge.js";
@@ -10,6 +10,8 @@
10
10
  import { type SourceResolver } from "../contract/index.js";
11
11
  import type { HonuaClient } from "../core/client.js";
12
12
  import { type HonuaMapPackage } from "./map-package.js";
13
+ import { type OfflineRegionTileHandler } from "./offline-region-protocol.js";
14
+ import { type MaplibreProtocolRegistrar } from "./pmtiles-protocol.js";
13
15
  import type { PopupFactory, PopupRenderer } from "./popups.js";
14
16
  import { HonuaMapRuntime, type HonuaRuntimeEventListener, type HonuaRuntimeTelemetry, type MaplibreMap } from "./runtime.js";
15
17
  import { type StyleRefResolver, type ThemeResolver } from "./style-compose.js";
@@ -103,6 +105,28 @@ export interface LoadMapPackageOptions {
103
105
  * style-spec checks and let the renderer report invalid style values.
104
106
  */
105
107
  styleSpecValidationMode?: RuntimeStyleSpecValidationMode;
108
+ /**
109
+ * Serve the named style sources from a persisted offline region.
110
+ *
111
+ * The handler comes from `@honua/sdk-js/offline` because it is bound to one
112
+ * region manifest, one store, and one authorization scope — none of which the
113
+ * runtime can invent. When `sourceIds` are given the composed style's tile
114
+ * templates are rewritten onto `offline-region://` before `map.setStyle`, and
115
+ * a source that cannot be rewritten exactly fails the load rather than
116
+ * quietly continuing to render live tiles.
117
+ */
118
+ offlineRegion?: LoadMapPackageOfflineRegion;
119
+ }
120
+ /** Binding between a composed style and one persisted offline region. */
121
+ export interface LoadMapPackageOfflineRegion {
122
+ /** Handler from `createOfflineRegionTileProtocol()` in `@honua/sdk-js/offline`. */
123
+ readonly tileHandler: OfflineRegionTileHandler;
124
+ /** Style source ids to rewrite onto the region. Omit to bind an already-rewritten style. */
125
+ readonly sourceIds?: readonly string[];
126
+ /** Tile-matrix-set segment of the rewritten URLs. Defaults to `"default"`. */
127
+ readonly tileMatrixSetId?: string;
128
+ /** Injected MapLibre registrar; defaults to the lazily imported peer. */
129
+ readonly maplibre?: MaplibreProtocolRegistrar;
106
130
  }
107
131
  /**
108
132
  * Load a `MapPackage` onto a caller-provided `MaplibreMap`. Returns a
@@ -1 +1 @@
1
- {"version":3,"file":"load-package.d.ts","sourceRoot":"","sources":["../../../src/runtime/load-package.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAuC,KAAK,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,OAAO,EAA+B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGrF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,eAAe,EAEf,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAgB,MAAM,oBAAoB,CAAC;AAG7F,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzD,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,mGAAmG;IACnG,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qFAAqF;IACrF,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,8BAA8B,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAoN1B"}
1
+ {"version":3,"file":"load-package.d.ts","sourceRoot":"","sources":["../../../src/runtime/load-package.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAuC,KAAK,cAAc,EAAiB,MAAM,sBAAsB,CAAC;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,OAAO,EAA+B,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAEL,KAAK,wBAAwB,EAG9B,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,KAAK,yBAAyB,EAA2C,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,eAAe,EAEf,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAgB,MAAM,oBAAoB,CAAC;AAG7F,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,WAAW,CAAC;AAEzD,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,mGAAmG;IACnG,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qFAAqF;IACrF,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,8BAA8B,CAAC;IACzD;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,2BAA2B,CAAC;CAC7C;AAED,yEAAyE;AACzE,MAAM,WAAW,2BAA2B;IAC1C,mFAAmF;IACnF,QAAQ,CAAC,WAAW,EAAE,wBAAwB,CAAC;IAC/C,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;CAC/C;AA6BD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA0O1B"}
@@ -11,6 +11,8 @@ import { createDataset } from "../contract/index.js";
11
11
  import { HonuaMap } from "../map/honua-map.js";
12
12
  import { HonuaMapPackageError } from "./errors.js";
13
13
  import { HONUA_MAP_PACKAGE_FORMAT_V1 } from "./map-package.js";
14
+ import { OFFLINE_REGION_PROTOCOL_SCHEME, ensureOfflineRegionProtocol, styleUsesOfflineRegion, } from "./offline-region-protocol.js";
15
+ import { rewriteStyleTilesForOfflineRegion } from "./offline-region-style.js";
14
16
  import { createOgcStyleRefResolver } from "./ogc-styles.js";
15
17
  import { ensurePmtilesProtocol, styleUsesPmtiles } from "./pmtiles-protocol.js";
16
18
  import { HonuaMapRuntime, } from "./runtime.js";
@@ -18,6 +20,29 @@ import { projectSourceBindings, toHonuaSourceSpec } from "./source-bridge.js";
18
20
  import { composeStyle } from "./style-compose.js";
19
21
  import { throwRuntimeDiagnostics } from "./style-interactions.js";
20
22
  import { prepareRuntimeStyleSpecValidation } from "./style-spec-validation.js";
23
+ /**
24
+ * Point the named sources at the region, or fail the load.
25
+ *
26
+ * A refusal is fatal here on purpose: the caller named these sources precisely
27
+ * because they must come from storage, so leaving one on its network template
28
+ * would render live tiles while the application believed it was offline-backed.
29
+ */
30
+ function bindOfflineRegionStyle(style, packageId, region) {
31
+ if (!region?.sourceIds || region.sourceIds.length === 0)
32
+ return style;
33
+ const rewrite = rewriteStyleTilesForOfflineRegion(style, {
34
+ sourceIds: region.sourceIds,
35
+ ...(region.tileMatrixSetId !== undefined ? { tileMatrixSetId: region.tileMatrixSetId } : {}),
36
+ });
37
+ if (rewrite.refusals.length > 0) {
38
+ throw new HonuaMapPackageError("offline-region style binding refused a source it cannot rewrite exactly", {
39
+ ...(packageId === undefined ? {} : { packageId }),
40
+ stage: "style-compose",
41
+ detail: { refusals: rewrite.refusals },
42
+ });
43
+ }
44
+ return rewrite.style;
45
+ }
21
46
  /**
22
47
  * Load a `MapPackage` onto a caller-provided `MaplibreMap`. Returns a
23
48
  * runtime handle that exposes the operational API. Throws
@@ -121,10 +146,11 @@ export async function loadMapPackage(pkg, map, options) {
121
146
  if (!honuaMap.hasLayer(layer.id))
122
147
  honuaMap.addLayer(layer);
123
148
  }
124
- const composed = await composeStyle(target, preComposed, {
149
+ const styled = await composeStyle(target, preComposed, {
125
150
  resolveStyleRef: styleRefResolver,
126
151
  resolveTheme: options.resolveTheme,
127
152
  });
153
+ const composed = bindOfflineRegionStyle(styled, target.mapPackageId, options.offlineRegion);
128
154
  // Auto-register the MapLibre `pmtiles://` protocol before the caller (or
129
155
  // `runtime.reload`) hands this style to `map.setStyle`, so PMTiles-backed
130
156
  // sources render with no manual `addProtocol` wiring. Idempotent across
@@ -132,6 +158,24 @@ export async function loadMapPackage(pkg, map, options) {
132
158
  if (styleUsesPmtiles(composed)) {
133
159
  await ensurePmtilesProtocol();
134
160
  }
161
+ // Same contract for a persisted offline region: register on the evidence of
162
+ // the composed style, and refuse to hand MapLibre a style that addresses a
163
+ // region without the handler that can answer it — a missing handler renders
164
+ // blank tiles instead of failing.
165
+ if (styleUsesOfflineRegion(composed)) {
166
+ const region = options.offlineRegion;
167
+ if (!region) {
168
+ throw new HonuaMapPackageError("the composed style addresses an offline region but no offlineRegion tile handler was supplied", {
169
+ packageId: target.mapPackageId,
170
+ stage: "style-compose",
171
+ detail: { scheme: OFFLINE_REGION_PROTOCOL_SCHEME },
172
+ });
173
+ }
174
+ await ensureOfflineRegionProtocol({
175
+ tileHandler: region.tileHandler,
176
+ ...(region.maplibre ? { maplibre: region.maplibre } : {}),
177
+ });
178
+ }
135
179
  return { composed, dataset, honuaMap, failedSources };
136
180
  };
137
181
  try {
@@ -1,5 +1,6 @@
1
1
  import type { RendererAdapter } from "../kernel/renderer.js";
2
2
  import { type ExplainAutomaticMapLibreOptions, type SourceToMapLibreMap } from "../map/index.js";
3
+ import { type OfflineRegionTileHandler } from "./offline-region-protocol.js";
3
4
  import type { PmtilesProtocolModuleLike } from "./pmtiles-protocol.js";
4
5
  /** MapLibre module slice consumed from the caller-injected optional peer. */
5
6
  export interface MapLibreRendererPeer {
@@ -30,6 +31,16 @@ export interface MapLibreRendererOptions extends Omit<ExplainAutomaticMapLibreOp
30
31
  readonly mapOptions?: Readonly<Record<string, unknown>>;
31
32
  /** Defaults to `render`, the first frame that can contain the mounted layer. */
32
33
  readonly firstFrameEvent?: "render" | "idle";
34
+ /**
35
+ * Tile handler for a style that addresses a persisted offline region.
36
+ *
37
+ * Registered before an owned map is constructed, but only when the style
38
+ * actually references the `offline-region://` scheme. A style that references
39
+ * it without a handler fails construction instead of rendering blank tiles.
40
+ */
41
+ readonly offlineRegion?: {
42
+ readonly tileHandler: OfflineRegionTileHandler;
43
+ };
33
44
  }
34
45
  /**
35
46
  * Create an executable MapLibre adapter without importing `maplibre-gl`.
@@ -1 +1 @@
1
- {"version":3,"file":"maplibre-renderer.d.ts","sourceRoot":"","sources":["../../../src/runtime/maplibre-renderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,+BAA+B,EAEpC,KAAK,mBAAmB,EAGzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAGvE,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,0FAA0F;IAC1F,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAQD,yFAAyF;AACzF,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,MAAM,CAAC,IAAI,OAAO,CAAC;IACnB,kFAAkF;IAClF,aAAa,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,OAAO,CAAC;IACrB,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IACpD,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IACnD,cAAc,CAAC,IAAI,IAAI,CAAC;IACxB,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,8BAA8B;IAC7C,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC;CAC9C;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,+BAA+B,EAAE,WAAW,CAAC;IACjG,sGAAsG;IACtG,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,gFAAgF;IAChF,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC9C;AAQD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,8BAAmC,GAC3C,eAAe,CAAC,UAAU,EAAE,mBAAmB,EAAE,uBAAuB,CAAC,CA6G3E"}
1
+ {"version":3,"file":"maplibre-renderer.d.ts","sourceRoot":"","sources":["../../../src/runtime/maplibre-renderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,+BAA+B,EAEpC,KAAK,mBAAmB,EAGzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,wBAAwB,EAG9B,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAA6B,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAGlG,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,0FAA0F;IAC1F,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAQD,yFAAyF;AACzF,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,MAAM,CAAC,IAAI,OAAO,CAAC;IACnB,kFAAkF;IAClF,aAAa,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,OAAO,CAAC;IACrB,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IACpD,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IACnD,cAAc,CAAC,IAAI,IAAI,CAAC;IACxB,MAAM,CAAC,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,8BAA8B;IAC7C,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC;CAC9C;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,+BAA+B,EAAE,WAAW,CAAC;IACjG,sGAAsG;IACtG,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,gFAAgF;IAChF,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,wBAAwB,CAAA;KAAE,CAAC;CAC7E;AAQD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,GAAE,8BAAmC,GAC3C,eAAe,CAAC,UAAU,EAAE,mBAAmB,EAAE,uBAAuB,CAAC,CAwH3E"}
@@ -1,5 +1,6 @@
1
1
  import { HonuaAbortError } from "../core/errors.js";
2
2
  import { HonuaAutomaticMapLibreStrategyError, explainAutomaticSourceToMapLibre, mountAutomaticSourceToMapLibre, } from "../map/index.js";
3
+ import { ensureOfflineRegionProtocol, styleUsesOfflineRegion, } from "./offline-region-protocol.js";
3
4
  import { ensurePmtilesProtocol } from "./pmtiles-protocol.js";
4
5
  const EMPTY_STYLE = Object.freeze({
5
6
  version: 8,
@@ -24,6 +25,20 @@ export function maplibreRenderer(peer, options = {}) {
24
25
  },
25
26
  async mount(target, request) {
26
27
  const rendererOptions = request.rendererOptions ?? {};
28
+ // A style that addresses a persisted region needs its protocol before the
29
+ // map is constructed with it; registration is driven by the style's own
30
+ // evidence, and a style that names the scheme without a handler fails here
31
+ // rather than rendering blank tiles.
32
+ if (styleUsesOfflineRegion(request.style)) {
33
+ const registrar = protocolRegistrar(maplibre);
34
+ if (rendererOptions.offlineRegion === undefined || registrar === undefined) {
35
+ throw new TypeError("Rendering an offline-region style requires caller-injected MapLibre and a rendererOptions.offlineRegion tile handler.");
36
+ }
37
+ await ensureOfflineRegionProtocol({
38
+ tileHandler: rendererOptions.offlineRegion.tileHandler,
39
+ maplibre: registrar,
40
+ });
41
+ }
27
42
  const host = resolveMapHost(maplibre, target, request, rendererOptions);
28
43
  const map = host.map;
29
44
  try {
@@ -50,15 +65,10 @@ export function maplibreRenderer(peer, options = {}) {
50
65
  });
51
66
  }
52
67
  if (plan.selected?.strategy.startsWith("pmtiles")) {
53
- if (pmtiles === undefined || typeof maplibre.addProtocol !== "function") {
68
+ const registrar = protocolRegistrar(maplibre);
69
+ if (pmtiles === undefined || registrar === undefined) {
54
70
  throw new HonuaAutomaticMapLibreStrategyError("no-eligible-strategy", "PMTiles mounting requires caller-injected MapLibre and PMTiles protocol peers.");
55
71
  }
56
- const registrar = {
57
- addProtocol: (scheme, handler) => maplibre.addProtocol(scheme, handler),
58
- ...(typeof maplibre.removeProtocol === "function"
59
- ? { removeProtocol: (scheme) => maplibre.removeProtocol(scheme) }
60
- : {}),
61
- };
62
72
  await ensurePmtilesProtocol({ maplibre: registrar, pmtilesModule: pmtiles });
63
73
  }
64
74
  const mounted = await mountAutomaticSourceToMapLibre(map, request.source, plan, {
@@ -131,6 +141,21 @@ function maplibrePeer(value) {
131
141
  : {}),
132
142
  });
133
143
  }
144
+ /**
145
+ * Adapt the injected peer to the shared protocol registrar, or report that it
146
+ * cannot register protocols. This adapter never imports `maplibre-gl` itself, so
147
+ * an absent `addProtocol` is a caller-visible failure rather than a lazy import.
148
+ */
149
+ function protocolRegistrar(peer) {
150
+ const addProtocol = peer.addProtocol;
151
+ if (typeof addProtocol !== "function")
152
+ return undefined;
153
+ const removeProtocol = peer.removeProtocol;
154
+ return {
155
+ addProtocol: (scheme, handler) => addProtocol(scheme, handler),
156
+ ...(typeof removeProtocol === "function" ? { removeProtocol: (scheme) => removeProtocol(scheme) } : {}),
157
+ };
158
+ }
134
159
  function resolveMapHost(peer, target, request, options) {
135
160
  if (isMapHost(target)) {
136
161
  if (request.style !== undefined) {
@@ -0,0 +1,73 @@
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 { type MaplibreProtocolRegistrar } from "./protocol-registry.js";
24
+ /** The MapLibre protocol scheme persisted offline regions are addressed under. */
25
+ export declare const OFFLINE_REGION_PROTOCOL_SCHEME = "offline-region";
26
+ /**
27
+ * The handler shape `createOfflineRegionTileProtocol()` returns.
28
+ *
29
+ * Declared structurally so the runtime never imports the offline entrypoint; it
30
+ * is the same shape MapLibre itself expects from `addProtocol`.
31
+ */
32
+ export type OfflineRegionTileHandler = (request: {
33
+ readonly url: string;
34
+ }, abortController?: AbortController) => Promise<{
35
+ readonly data: ArrayBuffer;
36
+ readonly cacheControl?: string;
37
+ readonly expires?: string;
38
+ }>;
39
+ /** Injectable dependencies for {@link ensureOfflineRegionProtocol}. */
40
+ export interface EnsureOfflineRegionProtocolDeps {
41
+ /** Handler from `@honua/sdk-js/offline`'s `createOfflineRegionTileProtocol()`. */
42
+ readonly tileHandler: OfflineRegionTileHandler;
43
+ /** Override the lazily-imported MapLibre `addProtocol` registrar. */
44
+ readonly maplibre?: MaplibreProtocolRegistrar;
45
+ /** Protocol scheme to register. Defaults to `"offline-region"`. */
46
+ readonly scheme?: string;
47
+ }
48
+ /**
49
+ * Register the `offline-region://` protocol on MapLibre if it is not registered
50
+ * already. Idempotent per scheme, exactly like the PMTiles registration: several
51
+ * maps loading the same region concurrently share one registration.
52
+ *
53
+ * Because MapLibre's protocol table is process-global, the *first* handler wins
54
+ * for a given scheme. A host that needs to serve a different region on the same
55
+ * scheme must {@link resetOfflineRegionProtocol} first, or register the second
56
+ * region under its own scheme.
57
+ */
58
+ export declare function ensureOfflineRegionProtocol(deps: EnsureOfflineRegionProtocolDeps): Promise<void>;
59
+ /** Whether the `offline-region://` protocol (or `scheme`) is currently registered. */
60
+ export declare function isOfflineRegionProtocolRegistered(scheme?: string): boolean;
61
+ /**
62
+ * Release a prior {@link ensureOfflineRegionProtocol} registration, so a later
63
+ * call can bind a different region's handler to the same scheme.
64
+ */
65
+ export declare function resetOfflineRegionProtocol(scheme?: string): void;
66
+ /**
67
+ * Whether a composed MapLibre style references at least one `offline-region://`
68
+ * source. This is the evidence `loadMapPackage` registers on.
69
+ */
70
+ export declare function styleUsesOfflineRegion(style: {
71
+ sources?: Record<string, unknown>;
72
+ } | null | undefined, scheme?: string): boolean;
73
+ //# sourceMappingURL=offline-region-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offline-region-protocol.d.ts","sourceRoot":"","sources":["../../../src/runtime/offline-region-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACL,KAAK,yBAAyB,EAK/B,MAAM,wBAAwB,CAAC;AAEhC,kFAAkF;AAClF,eAAO,MAAM,8BAA8B,mBAAmB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACjC,eAAe,CAAC,EAAE,eAAe,KAC9B,OAAO,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAExG,uEAAuE;AACvE,MAAM,WAAW,+BAA+B;IAC9C,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,wBAAwB,CAAC;IAC/C,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IAC9C,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,+BAA+B,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtG;AAED,sFAAsF;AACtF,wBAAgB,iCAAiC,CAAC,MAAM,GAAE,MAAuC,GAAG,OAAO,CAE1G;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,GAAE,MAAuC,GAAG,IAAI,CAEhG;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EAC/D,MAAM,GAAE,MAAuC,GAC9C,OAAO,CAET"}