@honua/app-platform 0.1.0-beta.0 → 0.1.2-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 (381) hide show
  1. package/contract/discovery.d.ts +231 -0
  2. package/contract/discovery.d.ts.map +1 -0
  3. package/contract/discovery.js +554 -0
  4. package/contract/edit-sketch.d.ts +8 -0
  5. package/contract/edit-sketch.d.ts.map +1 -1
  6. package/contract/edit-sketch.js +15 -0
  7. package/contract/edit-snapping.d.ts +160 -0
  8. package/contract/edit-snapping.d.ts.map +1 -0
  9. package/contract/edit-snapping.js +675 -0
  10. package/contract/generated/projjson-v0.7-crs-validator.d.ts +35 -0
  11. package/contract/generated/projjson-v0.7-crs-validator.d.ts.map +1 -0
  12. package/contract/generated/projjson-v0.7-crs-validator.js +3941 -0
  13. package/contract/index.d.ts +11 -2
  14. package/contract/index.d.ts.map +1 -1
  15. package/contract/index.js +4 -1
  16. package/contract/pmtiles.d.ts +31 -0
  17. package/contract/pmtiles.d.ts.map +1 -1
  18. package/contract/pmtiles.js +60 -20
  19. package/contract/protocol-module.d.ts +70 -0
  20. package/contract/protocol-module.d.ts.map +1 -0
  21. package/contract/protocol-module.js +1 -0
  22. package/contract/schema-envelope.d.ts +26 -0
  23. package/contract/schema-envelope.d.ts.map +1 -0
  24. package/contract/schema-envelope.js +25 -0
  25. package/contract/schema.d.ts +582 -0
  26. package/contract/schema.d.ts.map +1 -0
  27. package/contract/schema.js +2483 -0
  28. package/contract/source-capability-support.d.ts +6 -0
  29. package/contract/source-capability-support.d.ts.map +1 -0
  30. package/contract/source-capability-support.js +154 -0
  31. package/contract/source.d.ts +35 -17
  32. package/contract/source.d.ts.map +1 -1
  33. package/contract/source.js +267 -71
  34. package/contract/types.d.ts +140 -4
  35. package/contract/types.d.ts.map +1 -1
  36. package/contract/types.js +6 -14
  37. package/core/bounded-json.d.ts +4 -0
  38. package/core/bounded-json.d.ts.map +1 -0
  39. package/core/bounded-json.js +38 -0
  40. package/core/cache-state.d.ts +9 -0
  41. package/core/cache-state.d.ts.map +1 -1
  42. package/core/cache-state.js +10 -0
  43. package/core/capabilities-xml.d.ts +33 -0
  44. package/core/capabilities-xml.d.ts.map +1 -0
  45. package/core/capabilities-xml.js +331 -0
  46. package/core/client.d.ts +4 -1
  47. package/core/client.d.ts.map +1 -1
  48. package/core/client.js +115 -29
  49. package/core/error-classifications.d.ts +153 -0
  50. package/core/error-classifications.d.ts.map +1 -0
  51. package/core/error-classifications.js +140 -0
  52. package/core/error-code-registry.d.ts +158 -0
  53. package/core/error-code-registry.d.ts.map +1 -0
  54. package/core/error-code-registry.js +143 -0
  55. package/core/error-envelope.d.ts +68 -0
  56. package/core/error-envelope.d.ts.map +1 -0
  57. package/core/error-envelope.js +357 -0
  58. package/core/errors.d.ts +45 -29
  59. package/core/errors.d.ts.map +1 -1
  60. package/core/errors.js +97 -50
  61. package/core/geoparquet-sql.d.ts +30 -2
  62. package/core/geoparquet-sql.d.ts.map +1 -1
  63. package/core/geoparquet-sql.js +38 -3
  64. package/core/odata-key-path.d.ts +12 -0
  65. package/core/odata-key-path.d.ts.map +1 -0
  66. package/core/odata-key-path.js +28 -0
  67. package/core/odata-write-codec.d.ts +66 -0
  68. package/core/odata-write-codec.d.ts.map +1 -0
  69. package/core/odata-write-codec.js +1083 -0
  70. package/core/odata.d.ts +59 -7
  71. package/core/odata.d.ts.map +1 -1
  72. package/core/odata.js +431 -99
  73. package/core/ogc-features.d.ts.map +1 -1
  74. package/core/ogc-features.js +3 -0
  75. package/core/ogc-maps.d.ts +7 -0
  76. package/core/ogc-maps.d.ts.map +1 -1
  77. package/core/ogc-maps.js +46 -7
  78. package/core/ogc-processes.d.ts +2 -1
  79. package/core/ogc-processes.d.ts.map +1 -1
  80. package/core/ogc-processes.js +33 -5
  81. package/core/ogc-records.d.ts +9 -0
  82. package/core/ogc-records.d.ts.map +1 -1
  83. package/core/ogc-records.js +78 -29
  84. package/core/ogc-tiles.d.ts +10 -1
  85. package/core/ogc-tiles.d.ts.map +1 -1
  86. package/core/ogc-tiles.js +56 -17
  87. package/core/path-utils.d.ts +9 -0
  88. package/core/path-utils.d.ts.map +1 -1
  89. package/core/path-utils.js +19 -0
  90. package/core/protocol-transport.d.ts +1 -0
  91. package/core/protocol-transport.d.ts.map +1 -1
  92. package/core/request-pipeline.d.ts.map +1 -1
  93. package/core/request-pipeline.js +1 -1
  94. package/core/spatial-filter.d.ts +8 -4
  95. package/core/spatial-filter.d.ts.map +1 -1
  96. package/core/spatial-filter.js +206 -16
  97. package/core/stac-static.d.ts +6 -2
  98. package/core/stac-static.d.ts.map +1 -1
  99. package/core/stac-static.js +260 -69
  100. package/core/surfaces.d.ts.map +1 -1
  101. package/core/surfaces.js +69 -5
  102. package/core/types.d.ts +125 -7
  103. package/core/types.d.ts.map +1 -1
  104. package/core/wfs-capabilities.d.ts +2 -0
  105. package/core/wfs-capabilities.d.ts.map +1 -1
  106. package/core/wfs-capabilities.js +8 -1
  107. package/core/wfs.d.ts.map +1 -1
  108. package/core/wfs.js +10 -0
  109. package/core/wms-capabilities.d.ts +56 -84
  110. package/core/wms-capabilities.d.ts.map +1 -1
  111. package/core/wms-capabilities.js +212 -509
  112. package/core/wmts-capabilities.d.ts +62 -62
  113. package/core/wmts-capabilities.d.ts.map +1 -1
  114. package/core/wmts-capabilities.js +224 -371
  115. package/esri-compat/editor.d.ts +8 -0
  116. package/esri-compat/editor.d.ts.map +1 -1
  117. package/esri-compat/editor.js +13 -0
  118. package/esri-compat/feature-layer.d.ts +2 -0
  119. package/esri-compat/feature-layer.d.ts.map +1 -1
  120. package/esri-compat/feature-layer.js +1 -0
  121. package/esri-compat/layer-list.d.ts +11 -0
  122. package/esri-compat/layer-list.d.ts.map +1 -1
  123. package/esri-compat/layer-list.js +49 -0
  124. package/esri-compat/legend.d.ts +10 -0
  125. package/esri-compat/legend.d.ts.map +1 -1
  126. package/esri-compat/legend.js +27 -0
  127. package/esri-compat/portal.d.ts +197 -0
  128. package/esri-compat/portal.d.ts.map +1 -0
  129. package/esri-compat/portal.js +251 -0
  130. package/esri-compat/renderer-objects.d.ts +40 -0
  131. package/esri-compat/renderer-objects.d.ts.map +1 -0
  132. package/esri-compat/renderer-objects.js +62 -0
  133. package/esri-compat/sketch.d.ts +43 -0
  134. package/esri-compat/sketch.d.ts.map +1 -1
  135. package/esri-compat/sketch.js +46 -0
  136. package/esri-compat/snapping.d.ts +43 -0
  137. package/esri-compat/snapping.d.ts.map +1 -0
  138. package/esri-compat/snapping.js +45 -0
  139. package/esri-compat/url.d.ts.map +1 -1
  140. package/esri-compat/url.js +1 -1
  141. package/esri-compat/widget-host.d.ts +84 -0
  142. package/esri-compat/widget-host.d.ts.map +1 -0
  143. package/esri-compat/widget-host.js +159 -0
  144. package/generated-app/errors.d.ts +18 -2
  145. package/generated-app/errors.d.ts.map +1 -1
  146. package/generated-app/errors.js +44 -11
  147. package/geocoding/index.d.ts +7 -0
  148. package/geocoding/index.d.ts.map +1 -1
  149. package/geocoding/index.js +5 -0
  150. package/geocoding/provider-http.d.ts +37 -0
  151. package/geocoding/provider-http.d.ts.map +1 -0
  152. package/geocoding/provider-http.js +91 -0
  153. package/geocoding/provider.d.ts +145 -0
  154. package/geocoding/provider.d.ts.map +1 -0
  155. package/geocoding/provider.js +41 -0
  156. package/geocoding/providers/honua.d.ts +28 -0
  157. package/geocoding/providers/honua.d.ts.map +1 -0
  158. package/geocoding/providers/honua.js +68 -0
  159. package/geocoding/providers/nominatim.d.ts +47 -0
  160. package/geocoding/providers/nominatim.d.ts.map +1 -0
  161. package/geocoding/providers/nominatim.js +105 -0
  162. package/geocoding/providers/pelias.d.ts +40 -0
  163. package/geocoding/providers/pelias.d.ts.map +1 -0
  164. package/geocoding/providers/pelias.js +115 -0
  165. package/geocoding/providers/photon.d.ts +39 -0
  166. package/geocoding/providers/photon.d.ts.map +1 -0
  167. package/geocoding/providers/photon.js +107 -0
  168. package/geometry/convert.d.ts +13 -0
  169. package/geometry/convert.d.ts.map +1 -0
  170. package/geometry/convert.js +12 -0
  171. package/geometry/index.d.ts +17 -0
  172. package/geometry/index.d.ts.map +1 -0
  173. package/geometry/index.js +15 -0
  174. package/geometry/internal.d.ts +25 -0
  175. package/geometry/internal.d.ts.map +1 -0
  176. package/geometry/internal.js +40 -0
  177. package/geometry/ops.d.ts +71 -0
  178. package/geometry/ops.d.ts.map +1 -0
  179. package/geometry/ops.js +147 -0
  180. package/geometry/project.d.ts +40 -0
  181. package/geometry/project.d.ts.map +1 -0
  182. package/geometry/project.js +88 -0
  183. package/geometry/types.d.ts +36 -0
  184. package/geometry/types.d.ts.map +1 -0
  185. package/geometry/types.js +12 -0
  186. package/map/automatic-mount-integration.d.ts +134 -0
  187. package/map/automatic-mount-integration.d.ts.map +1 -0
  188. package/map/automatic-mount-integration.js +305 -0
  189. package/map/automatic-source-strategy.d.ts +125 -0
  190. package/map/automatic-source-strategy.d.ts.map +1 -0
  191. package/map/automatic-source-strategy.js +494 -0
  192. package/map/data-to-map-bridge.d.ts +293 -0
  193. package/map/data-to-map-bridge.d.ts.map +1 -0
  194. package/map/data-to-map-bridge.js +817 -0
  195. package/map/geojson-projection.d.ts +33 -0
  196. package/map/geojson-projection.d.ts.map +1 -0
  197. package/map/geojson-projection.js +118 -0
  198. package/map/index.d.ts +14 -0
  199. package/map/index.d.ts.map +1 -1
  200. package/map/index.js +8 -0
  201. package/map/raster-source-spec.d.ts +30 -0
  202. package/map/raster-source-spec.d.ts.map +1 -0
  203. package/map/raster-source-spec.js +190 -0
  204. package/map/raster-source-strategy.d.ts +65 -0
  205. package/map/raster-source-strategy.d.ts.map +1 -0
  206. package/map/raster-source-strategy.js +232 -0
  207. package/map/source-to-maplibre.d.ts +91 -0
  208. package/map/source-to-maplibre.d.ts.map +1 -0
  209. package/map/source-to-maplibre.js +454 -0
  210. package/map/temporal-playback.d.ts +139 -0
  211. package/map/temporal-playback.d.ts.map +1 -0
  212. package/map/temporal-playback.js +247 -0
  213. package/package.json +28 -2
  214. package/query-planner/canonical.d.ts +7 -0
  215. package/query-planner/canonical.d.ts.map +1 -0
  216. package/query-planner/canonical.js +145 -0
  217. package/query-planner/cql2-json.d.ts +17 -0
  218. package/query-planner/cql2-json.d.ts.map +1 -0
  219. package/query-planner/cql2-json.js +646 -0
  220. package/query-planner/diagnostics.d.ts +35 -0
  221. package/query-planner/diagnostics.d.ts.map +1 -0
  222. package/query-planner/diagnostics.js +373 -0
  223. package/query-planner/duckdb.d.ts +79 -0
  224. package/query-planner/duckdb.d.ts.map +1 -0
  225. package/query-planner/duckdb.js +758 -0
  226. package/query-planner/execution-context.d.ts +5 -0
  227. package/query-planner/execution-context.d.ts.map +1 -0
  228. package/query-planner/execution-context.js +50 -0
  229. package/query-planner/executor.d.ts +5 -0
  230. package/query-planner/executor.d.ts.map +1 -0
  231. package/query-planner/executor.js +223 -0
  232. package/query-planner/geoservices.d.ts +91 -0
  233. package/query-planner/geoservices.d.ts.map +1 -0
  234. package/query-planner/geoservices.js +667 -0
  235. package/query-planner/grpc.d.ts +100 -0
  236. package/query-planner/grpc.d.ts.map +1 -0
  237. package/query-planner/grpc.js +736 -0
  238. package/query-planner/index.d.ts +44 -0
  239. package/query-planner/index.d.ts.map +1 -0
  240. package/query-planner/index.js +30 -0
  241. package/query-planner/ir.d.ts +20 -0
  242. package/query-planner/ir.d.ts.map +1 -0
  243. package/query-planner/ir.js +417 -0
  244. package/query-planner/local-aggregate.d.ts +5 -0
  245. package/query-planner/local-aggregate.d.ts.map +1 -0
  246. package/query-planner/local-aggregate.js +126 -0
  247. package/query-planner/odata.d.ts +48 -0
  248. package/query-planner/odata.d.ts.map +1 -0
  249. package/query-planner/odata.js +662 -0
  250. package/query-planner/ogc-compiler.d.ts +55 -0
  251. package/query-planner/ogc-compiler.d.ts.map +1 -0
  252. package/query-planner/ogc-compiler.js +480 -0
  253. package/query-planner/ogc-features.d.ts +53 -0
  254. package/query-planner/ogc-features.d.ts.map +1 -0
  255. package/query-planner/ogc-features.js +617 -0
  256. package/query-planner/planner.d.ts +17 -0
  257. package/query-planner/planner.d.ts.map +1 -0
  258. package/query-planner/planner.js +818 -0
  259. package/query-planner/resource.d.ts +94 -0
  260. package/query-planner/resource.d.ts.map +1 -0
  261. package/query-planner/resource.js +526 -0
  262. package/query-planner/semantic-canonical.d.ts +15 -0
  263. package/query-planner/semantic-canonical.d.ts.map +1 -0
  264. package/query-planner/semantic-canonical.js +62 -0
  265. package/query-planner/semantic-compat.d.ts +10 -0
  266. package/query-planner/semantic-compat.d.ts.map +1 -0
  267. package/query-planner/semantic-compat.js +35 -0
  268. package/query-planner/semantic-compiler.d.ts +64 -0
  269. package/query-planner/semantic-compiler.d.ts.map +1 -0
  270. package/query-planner/semantic-compiler.js +81 -0
  271. package/query-planner/semantic-literals.d.ts +30 -0
  272. package/query-planner/semantic-literals.d.ts.map +1 -0
  273. package/query-planner/semantic-literals.js +133 -0
  274. package/query-planner/semantic-types.d.ts +265 -0
  275. package/query-planner/semantic-types.d.ts.map +1 -0
  276. package/query-planner/semantic-types.js +1 -0
  277. package/query-planner/semantic.d.ts +54 -0
  278. package/query-planner/semantic.d.ts.map +1 -0
  279. package/query-planner/semantic.js +1421 -0
  280. package/query-planner/types.d.ts +560 -0
  281. package/query-planner/types.d.ts.map +1 -0
  282. package/query-planner/types.js +49 -0
  283. package/query-planner/wfs-semantic.d.ts +58 -0
  284. package/query-planner/wfs-semantic.d.ts.map +1 -0
  285. package/query-planner/wfs-semantic.js +547 -0
  286. package/query-planner/wfs.d.ts +6 -0
  287. package/query-planner/wfs.d.ts.map +1 -0
  288. package/query-planner/wfs.js +71 -0
  289. package/realtime/contract.d.ts +142 -0
  290. package/realtime/contract.d.ts.map +1 -0
  291. package/realtime/contract.js +154 -0
  292. package/realtime/honua-server.d.ts.map +1 -1
  293. package/realtime/honua-server.js +13 -8
  294. package/realtime/index.d.ts +19 -4
  295. package/realtime/index.d.ts.map +1 -1
  296. package/realtime/index.js +14 -4
  297. package/realtime/odata-delta.d.ts +114 -0
  298. package/realtime/odata-delta.d.ts.map +1 -0
  299. package/realtime/odata-delta.js +483 -0
  300. package/realtime/resumable-transport.d.ts +111 -0
  301. package/realtime/resumable-transport.d.ts.map +1 -0
  302. package/realtime/resumable-transport.js +406 -0
  303. package/realtime/resumable.d.ts +104 -0
  304. package/realtime/resumable.d.ts.map +1 -0
  305. package/realtime/resumable.js +632 -0
  306. package/realtime/sse.d.ts.map +1 -1
  307. package/realtime/sse.js +27 -23
  308. package/realtime/websocket.d.ts +60 -0
  309. package/realtime/websocket.d.ts.map +1 -0
  310. package/realtime/websocket.js +157 -0
  311. package/realtime/wire.d.ts +27 -0
  312. package/realtime/wire.d.ts.map +1 -0
  313. package/realtime/wire.js +57 -0
  314. package/replica-sync/errors.d.ts +2 -1
  315. package/replica-sync/errors.d.ts.map +1 -1
  316. package/replica-sync/errors.js +33 -2
  317. package/runtime/edit-snapping.d.ts +107 -0
  318. package/runtime/edit-snapping.d.ts.map +1 -0
  319. package/runtime/edit-snapping.js +190 -0
  320. package/runtime/errors.d.ts +3 -2
  321. package/runtime/errors.d.ts.map +1 -1
  322. package/runtime/errors.js +19 -2
  323. package/runtime/index.d.ts +6 -0
  324. package/runtime/index.d.ts.map +1 -1
  325. package/runtime/index.js +3 -0
  326. package/runtime/maplibre-renderer.d.ts +41 -0
  327. package/runtime/maplibre-renderer.d.ts.map +1 -0
  328. package/runtime/maplibre-renderer.js +322 -0
  329. package/runtime/query-tiles.d.ts +2 -1
  330. package/runtime/query-tiles.d.ts.map +1 -1
  331. package/runtime/query-tiles.js +6 -2
  332. package/runtime/source-bridge.d.ts +4 -4
  333. package/runtime/source-bridge.d.ts.map +1 -1
  334. package/runtime/source-bridge.js +9 -56
  335. package/runtime/style-interactions.d.ts +3 -2
  336. package/runtime/style-interactions.d.ts.map +1 -1
  337. package/runtime/style-interactions.js +11 -3
  338. package/runtime/terra-draw-sketch.d.ts +275 -0
  339. package/runtime/terra-draw-sketch.d.ts.map +1 -0
  340. package/runtime/terra-draw-sketch.js +404 -0
  341. package/scene-workspace/index.d.ts +4 -0
  342. package/scene-workspace/index.d.ts.map +1 -1
  343. package/scene-workspace/index.js +2 -0
  344. package/scene-workspace/source-to-cesium.d.ts +116 -0
  345. package/scene-workspace/source-to-cesium.d.ts.map +1 -0
  346. package/scene-workspace/source-to-cesium.js +791 -0
  347. package/scene-workspace/state-sync.d.ts +147 -0
  348. package/scene-workspace/state-sync.d.ts.map +1 -0
  349. package/scene-workspace/state-sync.js +1123 -0
  350. package/source-capability-registry.d.ts +1 -0
  351. package/source-capability-registry.js +1 -0
  352. package/source-capability-types.d.ts +186 -0
  353. package/source-capability-types.js +7 -0
  354. package/style/index.d.ts +2 -0
  355. package/style/index.d.ts.map +1 -1
  356. package/style/index.js +2 -0
  357. package/style/renderers.d.ts +326 -0
  358. package/style/renderers.d.ts.map +1 -0
  359. package/style/renderers.js +517 -0
  360. package/web-components/controller.d.ts +2 -0
  361. package/web-components/controller.d.ts.map +1 -1
  362. package/web-components/controller.js +49 -8
  363. package/web-components/elements.d.ts +95 -1
  364. package/web-components/elements.d.ts.map +1 -1
  365. package/web-components/elements.js +458 -19
  366. package/web-components/index.d.ts +8 -1
  367. package/web-components/index.d.ts.map +1 -1
  368. package/web-components/index.js +7 -0
  369. package/web-components/maplibre-renderer.d.ts.map +1 -1
  370. package/web-components/maplibre-renderer.js +87 -0
  371. package/web-components/measurement.d.ts +69 -0
  372. package/web-components/measurement.d.ts.map +1 -0
  373. package/web-components/measurement.js +523 -0
  374. package/web-components/types.d.ts +109 -0
  375. package/web-components/types.d.ts.map +1 -1
  376. package/webmap/convert-renderer.d.ts +24 -3
  377. package/webmap/convert-renderer.d.ts.map +1 -1
  378. package/webmap/convert-renderer.js +93 -112
  379. package/webmap/index.d.ts +1 -1
  380. package/webmap/index.d.ts.map +1 -1
  381. package/webmap/index.js +1 -1
package/realtime/sse.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { decodeDefaultRealtimeEnvelope, normalizeRealtimeErrorEvent, realtimeFailure } from "./wire.js";
1
2
  const DEFAULT_EVENT_TYPES = ["snapshot", "upsert", "delete", "delta", "heartbeat", "status", "error"];
2
3
  export function createRealtimeServerSentEventsTransport(options) {
3
4
  return {
@@ -18,20 +19,35 @@ export function createRealtimeServerSentEventsTransport(options) {
18
19
  observer.complete();
19
20
  return { close: () => { } };
20
21
  }
21
- const url = new URL(options.url, "http://honua.local");
22
- encodeDefaultRealtimeRequest(url, request);
23
- options.encodeRequest?.(url, request);
24
- const source = createEventSource(resolveEventSourceUrl(options.url, url), options);
22
+ let source;
23
+ try {
24
+ const url = new URL(options.url, "http://honua.local");
25
+ encodeDefaultRealtimeRequest(url, request);
26
+ options.encodeRequest?.(url, request);
27
+ source = createEventSource(resolveEventSourceUrl(options.url, url), options);
28
+ }
29
+ catch (cause) {
30
+ throw realtimeFailure("delivery-failed", "Unable to initialize the realtime Server-Sent Events transport.", cause);
31
+ }
25
32
  let closed = false;
26
33
  const listeners = [];
27
34
  const emitPayload = (payload) => {
28
35
  if (closed || payload.trim() === "")
29
36
  return;
37
+ let event;
38
+ try {
39
+ const decoded = (options.decodeEvent ?? (decodeRealtimeServerSentEvent))(JSON.parse(payload));
40
+ event = normalizeRealtimeErrorEvent(decoded);
41
+ }
42
+ catch (cause) {
43
+ observer.error(realtimeFailure("invalid-event", "Realtime Server-Sent Events payload decoding failed.", cause));
44
+ return;
45
+ }
30
46
  try {
31
- observer.next((options.decodeEvent ?? (decodeRealtimeServerSentEvent))(JSON.parse(payload)));
47
+ observer.next(event);
32
48
  }
33
- catch (error) {
34
- observer.error(error);
49
+ catch (cause) {
50
+ observer.error(realtimeFailure("consumer-failed", "Realtime event observer rejected delivery.", cause));
35
51
  }
36
52
  };
37
53
  const messageListener = (event) => emitPayload(event.data);
@@ -43,8 +59,9 @@ export function createRealtimeServerSentEventsTransport(options) {
43
59
  source.onerror = (event) => {
44
60
  if (!closed)
45
61
  observer.next({ type: "status", status: "reconnecting", reason: "sse-error", receivedAt: Date.now() });
46
- if (isEventSourceClosed(source))
47
- observer.error(event);
62
+ if (isEventSourceClosed(source)) {
63
+ observer.error(realtimeFailure("transport-gap", "Realtime Server-Sent Events transport closed unexpectedly.", event));
64
+ }
48
65
  };
49
66
  for (const type of options.eventTypes ?? DEFAULT_EVENT_TYPES) {
50
67
  if (!source.addEventListener)
@@ -106,17 +123,7 @@ export function encodeDefaultRealtimeRequest(url, request) {
106
123
  return url;
107
124
  }
108
125
  export function decodeRealtimeServerSentEvent(payload) {
109
- if (!isRecord(payload))
110
- throw new Error("Realtime SSE payload must be a JSON object.");
111
- if (typeof payload.type === "string")
112
- return payload;
113
- if (isRecord(payload.event) && typeof payload.event.type === "string") {
114
- return payload.event;
115
- }
116
- if (typeof payload.kind === "string") {
117
- return { ...payload, type: payload.kind };
118
- }
119
- throw new Error("Realtime SSE payload is missing an event type.");
126
+ return decodeDefaultRealtimeEnvelope(payload);
120
127
  }
121
128
  function createEventSource(url, options) {
122
129
  if (options.eventSourceFactory) {
@@ -138,6 +145,3 @@ function resolveEventSourceUrl(input, url) {
138
145
  function isEventSourceClosed(source) {
139
146
  return source.readyState === 2;
140
147
  }
141
- function isRecord(value) {
142
- return typeof value === "object" && value !== null;
143
- }
@@ -0,0 +1,60 @@
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 type { RealtimeFeatureEvent, RealtimeFeatureTransport, RealtimeSubscriptionRequest } from "./types.js";
18
+ /**
19
+ * Minimal WebSocket surface the transport depends on. The global `WebSocket`
20
+ * constructor (browsers, and Node's built-in client since Node 22) already
21
+ * satisfies this; pass `webSocketFactory` to supply a polyfill or a mock in
22
+ * tests without adding a runtime dependency.
23
+ */
24
+ export interface RealtimeWebSocket {
25
+ readonly readyState?: number;
26
+ onopen: ((event: Event) => void) | null;
27
+ onmessage: ((event: MessageEvent<string>) => void) | null;
28
+ onerror: ((event: Event) => void) | null;
29
+ onclose: ((event: RealtimeWebSocketCloseEvent) => void) | null;
30
+ close(code?: number, reason?: string): void;
31
+ send(data: string): void;
32
+ }
33
+ /** Subset of `CloseEvent` the transport reads; avoids depending on the DOM lib for `wasClean`. */
34
+ export interface RealtimeWebSocketCloseEvent {
35
+ readonly code?: number;
36
+ readonly reason?: string;
37
+ readonly wasClean?: boolean;
38
+ }
39
+ export type RealtimeWebSocketFactory = (url: string, protocols: string | ReadonlyArray<string> | undefined) => RealtimeWebSocket;
40
+ export interface RealtimeWebSocketTransportOptions<TFeature = unknown> {
41
+ readonly url: string;
42
+ readonly protocols?: string | ReadonlyArray<string>;
43
+ readonly webSocketFactory?: RealtimeWebSocketFactory;
44
+ readonly encodeRequest?: (url: URL, request: RealtimeSubscriptionRequest) => void;
45
+ readonly decodeEvent?: (payload: unknown) => RealtimeFeatureEvent<TFeature>;
46
+ /**
47
+ * Sent as a single JSON text frame immediately after the socket opens, for
48
+ * servers that expect an explicit subscribe message instead of (or in
49
+ * addition to) URL query parameters. The default transport never sends a
50
+ * subscribe frame on its own.
51
+ */
52
+ readonly encodeSubscribeMessage?: (request: RealtimeSubscriptionRequest) => unknown;
53
+ /**
54
+ * WebSocket close codes treated as a normal, non-reconnectable end of the
55
+ * stream rather than a `transport-gap` failure. @default [1000]
56
+ */
57
+ readonly cleanCloseCodes?: ReadonlyArray<number>;
58
+ }
59
+ export declare function createRealtimeWebSocketTransport<TFeature = unknown>(options: RealtimeWebSocketTransportOptions<TFeature>): RealtimeFeatureTransport<TFeature>;
60
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/realtime/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EACV,oBAAoB,EAEpB,wBAAwB,EAExB,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAGpB;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,kGAAkG;AAClG,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,wBAAwB,GAAG,CACrC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,KAClD,iBAAiB,CAAC;AAEvB,MAAM,WAAW,iCAAiC,CAAC,QAAQ,GAAG,OAAO;IACnE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACpD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,wBAAwB,CAAC;IACrD,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAC;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC5E;;;;;OAKG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,OAAO,CAAC;IACpF;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAClD;AAID,wBAAgB,gCAAgC,CAAC,QAAQ,GAAG,OAAO,EACjE,OAAO,EAAE,iCAAiC,CAAC,QAAQ,CAAC,GACnD,wBAAwB,CAAC,QAAQ,CAAC,CAwGpC"}
@@ -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,27 @@
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 declare function realtimeFailure(code: RealtimeTransportFailureCode, message: string, cause: unknown): HonuaRealtimeResumeError;
26
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
27
+ //# 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,CAehC;AAED,MAAM,MAAM,4BAA4B,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,eAAe,GAAG,eAAe,CAAC;AAErH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,4BAA4B,EAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,GACb,wBAAwB,CAI1B;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
@@ -0,0 +1,57 @@
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 code = event.terminal ? "invalid-event" : "transport-gap";
41
+ if (event.error instanceof HonuaRealtimeResumeError && isHonuaSdkError(event.error) && event.error.code === code)
42
+ return event;
43
+ return {
44
+ ...event,
45
+ error: realtimeFailure(code, event.terminal
46
+ ? "Realtime stream reported a terminal protocol failure."
47
+ : "Realtime stream reported a reconnectable transport failure.", event.error),
48
+ };
49
+ }
50
+ export function realtimeFailure(code, message, cause) {
51
+ return cause instanceof HonuaRealtimeResumeError && isHonuaSdkError(cause) && cause.code === code
52
+ ? cause
53
+ : new HonuaRealtimeResumeError(code, message, { cause });
54
+ }
55
+ export function isRecord(value) {
56
+ return typeof value === "object" && value !== null;
57
+ }
@@ -7,8 +7,9 @@
7
7
  *
8
8
  * @module
9
9
  */
10
+ import { HonuaSdkError } from "../core/error-envelope.js";
10
11
  export type ReplicaSyncErrorCode = "unsupported-sync" | "unsupported-conflict-review" | "unsupported-conflict-resolution" | "replica-not-found" | "conflict-not-found" | "replica-expired" | "conflict-already-resolved" | "merge-required" | "permission-denied" | "transport-failure";
11
- export declare class HonuaReplicaSyncError extends Error {
12
+ export declare class HonuaReplicaSyncError extends HonuaSdkError {
12
13
  readonly code: ReplicaSyncErrorCode;
13
14
  readonly details: unknown;
14
15
  constructor(code: ReplicaSyncErrorCode, message: string, options?: {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/replica-sync/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,oBAAoB,GAC5B,kBAAkB,GAClB,6BAA6B,GAC7B,iCAAiC,GACjC,mBAAmB,GACnB,oBAAoB,GACpB,iBAAiB,GACjB,2BAA2B,GAC3B,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,CAAC;AAExB,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,SAAgB,IAAI,EAAE,oBAAoB,CAAC;IAC3C,SAAgB,OAAO,EAAE,OAAO,CAAC;gBAG/B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAOzE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,oDAAoD;AACpD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAO5F"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/replica-sync/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAuB,aAAa,EAAyC,MAAM,2BAA2B,CAAC;AAEtH,MAAM,MAAM,oBAAoB,GAC5B,kBAAkB,GAClB,6BAA6B,GAC7B,iCAAiC,GACjC,mBAAmB,GACnB,oBAAoB,GACpB,iBAAiB,GACjB,2BAA2B,GAC3B,gBAAgB,GAChB,mBAAmB,GACnB,mBAAmB,CAAC;AAExB,qBAAa,qBAAsB,SAAQ,aAAa;IACtD,SAAgB,IAAI,EAAE,oBAAoB,CAAC;IAC3C,SAAgB,OAAO,EAAE,OAAO,CAAC;gBAG/B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAWzE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,oDAAoD;AACpD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAO5F"}
@@ -7,11 +7,16 @@
7
7
  *
8
8
  * @module
9
9
  */
10
- export class HonuaReplicaSyncError extends Error {
10
+ import { HonuaSdkError, isRetryableNetworkOrTimeoutHonuaError } from "../core/error-envelope.js";
11
+ export class HonuaReplicaSyncError extends HonuaSdkError {
11
12
  code;
12
13
  details;
13
14
  constructor(code, message, options = {}) {
14
- super(message, options.cause === undefined ? undefined : { cause: options.cause });
15
+ const cause = options.cause;
16
+ super(replicaSyncSdkCode(code, cause), message, {
17
+ ...(cause === undefined ? {} : { cause }),
18
+ context: { reasonCode: replicaSyncContextReason(code) },
19
+ });
15
20
  this.name = "HonuaReplicaSyncError";
16
21
  this.code = code;
17
22
  this.details = options.details;
@@ -27,3 +32,29 @@ export function isUnsupportedReplicaSyncError(error) {
27
32
  error.code === "unsupported-conflict-review" ||
28
33
  error.code === "unsupported-conflict-resolution"));
29
34
  }
35
+ const REPLICA_SYNC_ERROR_CODES = {
36
+ "unsupported-sync": "offline.replica-sync.capability",
37
+ "unsupported-conflict-review": "offline.replica-sync.capability",
38
+ "unsupported-conflict-resolution": "offline.replica-sync.capability",
39
+ "replica-not-found": "offline.replica-sync.validation",
40
+ "conflict-not-found": "offline.replica-sync.validation",
41
+ "replica-expired": "offline.replica-sync.validation",
42
+ "conflict-already-resolved": "offline.replica-sync.validation",
43
+ "merge-required": "offline.replica-sync.validation",
44
+ "permission-denied": "offline.replica-sync.permission-denied",
45
+ "transport-failure": "offline.transport.failure",
46
+ };
47
+ function replicaSyncSdkCode(code, cause) {
48
+ if (!isReplicaSyncErrorCode(code))
49
+ return "offline.replica-sync.validation";
50
+ if (code === "transport-failure" && isRetryableNetworkOrTimeoutHonuaError(cause)) {
51
+ return "offline.transport.transient";
52
+ }
53
+ return REPLICA_SYNC_ERROR_CODES[code];
54
+ }
55
+ function replicaSyncContextReason(code) {
56
+ return isReplicaSyncErrorCode(code) ? code : "invalid-error-code";
57
+ }
58
+ function isReplicaSyncErrorCode(code) {
59
+ return typeof code === "string" && Object.hasOwn(REPLICA_SYNC_ERROR_CODES, code);
60
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * MapLibre runtime binding for edit-sketch snapping.
3
+ *
4
+ * Wires pointer-move on a MapLibre-shaped map to the renderer-neutral
5
+ * snapping engine in `contract/edit-snapping.ts`, applies snapped
6
+ * coordinates to an `EditSketchWorkflowModel`, surfaces snapped / unsnapped
7
+ * events, and maintains a default visual indicator via a lightweight GeoJSON
8
+ * circle layer.
9
+ *
10
+ * The map interfaces are duck-typed (same pattern as
11
+ * `interactions/feature-state.ts`) so the SDK carries no hard runtime
12
+ * dependency on `maplibre-gl`.
13
+ *
14
+ * @module
15
+ */
16
+ import type { EditSketchTool, EditSketchWorkflowModel } from "../contract/edit-sketch.js";
17
+ import { type SnapCandidate, type SnapIndex, type SnapPosition, type SnapResolution, type SnapScreenPoint, type SnappingConfig } from "../contract/edit-snapping.js";
18
+ /** Minimal subset of a MapLibre `Map` needed for snapping. */
19
+ export interface SnappingMap {
20
+ on(event: string, handler: (...args: unknown[]) => void): void;
21
+ off(event: string, handler: (...args: unknown[]) => void): void;
22
+ project(position: readonly [number, number]): SnapScreenPoint | {
23
+ x: number;
24
+ y: number;
25
+ };
26
+ addSource?(id: string, source: Record<string, unknown>): void;
27
+ removeSource?(id: string): void;
28
+ addLayer?(layer: Record<string, unknown>, beforeId?: string): void;
29
+ removeLayer?(id: string): void;
30
+ getSource?(id: string): unknown;
31
+ getLayer?(id: string): unknown;
32
+ }
33
+ export interface EditSketchSnapIndicatorOptions {
34
+ /** Render the default indicator layer. @default true */
35
+ enabled?: boolean;
36
+ /** Indicator source and layer id. @default "honua-snap-indicator" */
37
+ id?: string;
38
+ /** Paint overrides merged over the default circle paint. */
39
+ paint?: Record<string, unknown>;
40
+ /** Insert the indicator layer before this layer id. */
41
+ beforeId?: string;
42
+ }
43
+ export interface EditSketchSnappingEvents {
44
+ /** Fired when the pointer acquires or changes a snap target. */
45
+ onSnap?(resolution: SnapResolution): void;
46
+ /** Fired when the pointer leaves a snap target; receives the lost candidate. */
47
+ onUnsnap?(previous: SnapCandidate): void;
48
+ }
49
+ export interface BindEditSketchSnappingOptions<T = Record<string, unknown>> extends EditSketchSnappingEvents {
50
+ /** Snap index over the loaded snap-source features. */
51
+ index: SnapIndex;
52
+ /**
53
+ * Sketch workflow whose snapping config drives resolution and that
54
+ * receives snapped geometry via {@link EditSketchSnappingHandle.applySketchGeometry}.
55
+ * When omitted, pass `config` and consume snaps through events / `current`.
56
+ */
57
+ model?: EditSketchWorkflowModel<T>;
58
+ /** Snapping configuration when no model is bound (or overrides for one-off use). */
59
+ config?: Partial<SnappingConfig>;
60
+ /** Pointer event name to listen for. @default "mousemove" */
61
+ pointerEvent?: string;
62
+ /** Default snap indicator; `false` disables it. */
63
+ indicator?: boolean | EditSketchSnapIndicatorOptions;
64
+ }
65
+ export interface EditSketchSnappingHandle {
66
+ /** The currently snapped candidate, if any. */
67
+ readonly current: SnapCandidate | undefined;
68
+ /** Resolve a pointer position without going through a map event. */
69
+ resolve(input: {
70
+ point: SnapScreenPoint;
71
+ position: SnapPosition;
72
+ }): SnapResolution;
73
+ /** Return the snapped position for `position`, or `position` unchanged. */
74
+ snapPosition(position: SnapPosition): SnapPosition;
75
+ /** Effective snapping configuration. */
76
+ config(): SnappingConfig;
77
+ /** Merge configuration changes (writes through to the bound model). */
78
+ setConfig(config: Partial<SnappingConfig>): void;
79
+ /**
80
+ * Apply `geometry` to the bound sketch model with its active vertex
81
+ * replaced by the current snap position (no-op replacement when the
82
+ * pointer is not snapped). Returns `true` when the model accepted the
83
+ * geometry.
84
+ */
85
+ applySketchGeometry(tool: EditSketchTool, geometry: Record<string, unknown> | null): boolean;
86
+ /** Detach event handlers and remove the indicator layer. */
87
+ remove(): void;
88
+ }
89
+ /**
90
+ * Bind edit-sketch snapping to a MapLibre-shaped map.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const index = createSnapIndex();
95
+ * index.setSourceFeatures("parcels", parcels);
96
+ * const snapping = bindEditSketchSnapping(map, {
97
+ * index,
98
+ * model: workflow,
99
+ * onSnap: ({ candidate }) => showGuide(candidate),
100
+ * });
101
+ * map.on("click", (e) => {
102
+ * snapping.applySketchGeometry("point", { type: "Point", coordinates: [e.lngLat.lng, e.lngLat.lat] });
103
+ * });
104
+ * ```
105
+ */
106
+ export declare function bindEditSketchSnapping<T = Record<string, unknown>>(map: SnappingMap, options: BindEditSketchSnappingOptions<T>): EditSketchSnappingHandle;
107
+ //# sourceMappingURL=edit-snapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-snapping.d.ts","sourceRoot":"","sources":["../../../src/runtime/edit-snapping.ts"],"names":[],"mappings":"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"}