@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"odata-delta.d.ts","sourceRoot":"","sources":["../../../src/realtime/odata-delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAIV,wBAAwB,EAEzB,MAAM,YAAY,CAAC;AAGpB,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,6FAA6F;AAC7F,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,8GAA8G;AAC9G,MAAM,WAAW,uBAAuB;IACtC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uGAAuG;IACvG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,0BAA0B,CAAC,QAAQ,GAAG,OAAO;IAC5D;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,SAAS,CAAC;IAC3D,sHAAsH;IACtH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,QAAQ,CAAC;IAC5D,gGAAgG;IAChG,QAAQ,CAAC,YAAY,CAAC,EAAE,sBAAsB,CAAC;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IACjF;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACzE,sFAAsF;IACtF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,6FAA6F;IAC7F,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC/D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,GAAG,OAAO,EAC1D,OAAO,EAAE,0BAA0B,CAAC,QAAQ,CAAC,GAC5C,wBAAwB,CAAC,QAAQ,CAAC,CAkYpC"}
@@ -0,0 +1,483 @@
1
+ /**
2
+ * OData v4 delta-link pull adapter for `@honua/sdk-js/realtime` (issue #558).
3
+ *
4
+ * OData delta links (`@odata.deltaLink`) are a *pull* change feed, not a
5
+ * socket transport: a client requests a scoped delta-link URL and the
6
+ * server returns only what changed since that link was minted, plus a fresh
7
+ * delta link for the next request. This module maps that request/response
8
+ * paging protocol onto the transport-neutral `RealtimeFeatureTransport`
9
+ * surface (`types.ts`, #556) so it composes with `createRealtimeFeatureStore`
10
+ * / `createResumableRealtimeSubscription` exactly like the SSE and WebSocket
11
+ * adapters (`sse.ts`, `websocket.ts`, #557) — with one deliberate
12
+ * difference dictated by REQ-004: this transport never claims to be live.
13
+ * `capabilities.kind` is `"polling"`, it never emits a `"heartbeat"`, and
14
+ * `onPoll` reports an explicit cadence/freshness snapshot on every request
15
+ * cycle so a consumer can render "checked N seconds ago, next check in M"
16
+ * rather than a live badge that misrepresents a poll as a stream.
17
+ *
18
+ * Ownership split from the SSE/WebSocket adapters: those open exactly one
19
+ * connection per `subscribe()` and never reconnect on their own, deferring
20
+ * reconnect entirely to `resumable-transport.ts`. This transport has no
21
+ * connection to reconnect — every cycle is an independent request/response —
22
+ * so it owns its own bounded poll loop, including the on-expiry resnapshot
23
+ * recovery a socket transport cannot perform for itself: an expired or
24
+ * rejected delta link (REQ per the User Workflow, "Expired/invalid delta
25
+ * state requires an explicit resnapshot") is recovered by re-running a full
26
+ * snapshot cycle and emitting a fresh `type: "snapshot", replace: true`
27
+ * event, bounded by `maxConsecutiveResnapshots` so a server that keeps
28
+ * rejecting the token cannot loop forever.
29
+ *
30
+ * Security posture (REQ-002): every `@odata.nextLink` / `@odata.deltaLink`
31
+ * this transport follows, and any caller-supplied `resumeFrom.deltaToken`,
32
+ * must resolve to the exact same origin and collection path as the
33
+ * configured `url`. A link that does not is rejected rather than followed —
34
+ * a delta token is an opaque, potentially attacker-influenced value once it
35
+ * has round-tripped through a checkpoint store, and this transport never
36
+ * trusts it to redirect a request elsewhere.
37
+ *
38
+ * @module
39
+ */
40
+ import { HonuaRealtimeResumeError } from "./resumable.js";
41
+ import { realtimeFailure } from "./wire.js";
42
+ const DEFAULT_MAX_PAGES_PER_CYCLE = 500;
43
+ const DEFAULT_MAX_SNAPSHOT_ROWS = 50_000;
44
+ const DEFAULT_MAX_CONSECUTIVE_RESNAPSHOTS = 3;
45
+ /**
46
+ * Build a {@link RealtimeFeatureTransport} that polls an OData v4 entity
47
+ * set's delta link. See the module doc for the full recovery/security model.
48
+ */
49
+ export function createOdataDeltaTransport(options) {
50
+ if (typeof options.entityId !== "function") {
51
+ throw new TypeError("createOdataDeltaTransport requires options.entityId.");
52
+ }
53
+ const pollIntervalMs = positiveInteger(options.pollIntervalMs, "pollIntervalMs");
54
+ const maxPagesPerCycle = positiveInteger(options.maxPagesPerCycle ?? DEFAULT_MAX_PAGES_PER_CYCLE, "maxPagesPerCycle");
55
+ const maxSnapshotRows = positiveInteger(options.maxSnapshotRows ?? DEFAULT_MAX_SNAPSHOT_ROWS, "maxSnapshotRows");
56
+ const maxConsecutiveResnapshots = positiveInteger(options.maxConsecutiveResnapshots ?? DEFAULT_MAX_CONSECUTIVE_RESNAPSHOTS, "maxConsecutiveResnapshots");
57
+ const collectionUrl = parseAbsoluteUrl(options.url, `createOdataDeltaTransport requires an absolute options.url ("${options.url}").`);
58
+ return {
59
+ capabilities: {
60
+ kind: "polling",
61
+ resumeModes: ["delta-token"],
62
+ emitsHeartbeats: false,
63
+ emitsWatermarks: false,
64
+ },
65
+ subscribe(request, observer) {
66
+ if (request.signal?.aborted) {
67
+ observer.complete();
68
+ return { close: () => { } };
69
+ }
70
+ const resumeDeltaToken = request.deltaToken ?? request.resumeFrom?.deltaToken;
71
+ let initialDeltaLink;
72
+ if (resumeDeltaToken !== undefined) {
73
+ const resumeUrl = parseRelativeOdataUrl(resumeDeltaToken, collectionUrl, `Realtime resumeFrom.deltaToken "${resumeDeltaToken}" is not a valid URL.`);
74
+ assertSameOdataCollection(collectionUrl, resumeUrl);
75
+ initialDeltaLink = resumeUrl.toString();
76
+ }
77
+ const now = () => options.now?.() ?? Date.now();
78
+ const controller = new AbortController();
79
+ let closed = false;
80
+ let sequence = request.resumeFrom?.sequence ?? 0;
81
+ let resnapshotStreak = 0;
82
+ let timer;
83
+ const abortListener = () => teardown("Subscription signal was aborted.", true);
84
+ request.signal?.addEventListener("abort", abortListener, { once: true });
85
+ function teardown(reason, complete) {
86
+ if (closed)
87
+ return;
88
+ closed = true;
89
+ if (timer !== undefined)
90
+ clearTimeout(timer);
91
+ request.signal?.removeEventListener("abort", abortListener);
92
+ if (!controller.signal.aborted)
93
+ controller.abort(reason);
94
+ if (complete)
95
+ observer.complete();
96
+ }
97
+ function fail(error) {
98
+ if (closed)
99
+ return;
100
+ closed = true;
101
+ if (timer !== undefined)
102
+ clearTimeout(timer);
103
+ request.signal?.removeEventListener("abort", abortListener);
104
+ if (!controller.signal.aborted)
105
+ controller.abort("OData delta transport failed.");
106
+ observer.error(error);
107
+ }
108
+ function emit(event) {
109
+ if (closed)
110
+ return false;
111
+ try {
112
+ observer.next(event);
113
+ return true;
114
+ }
115
+ catch (cause) {
116
+ fail(realtimeFailure("consumer-failed", "Realtime event observer rejected delivery.", cause));
117
+ return false;
118
+ }
119
+ }
120
+ function reportPoll(partial) {
121
+ if (!options.onPoll)
122
+ return;
123
+ try {
124
+ options.onPoll({
125
+ polledAt: now(),
126
+ intervalMs: pollIntervalMs,
127
+ sequence,
128
+ changed: partial.changed,
129
+ upsertCount: partial.upsertCount,
130
+ deleteCount: partial.deleteCount,
131
+ ...(partial.scheduled ? { nextPollAt: now() + pollIntervalMs } : {}),
132
+ });
133
+ }
134
+ catch {
135
+ // Telemetry is diagnostic only; a throwing onPoll callback must
136
+ // never affect delivery.
137
+ }
138
+ }
139
+ function schedulePoll(link) {
140
+ if (closed)
141
+ return;
142
+ timer = setTimeout(() => {
143
+ timer = undefined;
144
+ void runDeltaCycle(link);
145
+ }, pollIntervalMs);
146
+ }
147
+ async function fetchOdataDocument(target, trackChanges) {
148
+ const fetchImpl = resolveFetch(options.fetchImpl);
149
+ const headers = { Accept: "application/json", ...(options.headers?.() ?? {}) };
150
+ if (trackChanges)
151
+ headers.Prefer = "odata.track-changes";
152
+ let response;
153
+ try {
154
+ response = await fetchImpl(target, { method: "GET", headers, signal: controller.signal });
155
+ }
156
+ catch (cause) {
157
+ if (controller.signal.aborted)
158
+ throw cause;
159
+ throw realtimeFailure("transport-gap", "OData delta request failed.", cause);
160
+ }
161
+ if (!response.ok) {
162
+ const body = await safeReadJson(response);
163
+ const isExpired = (options.isDeltaLinkExpiredResponse ?? defaultIsDeltaLinkExpiredResponse)(response.status, body);
164
+ if (isExpired) {
165
+ throw new HonuaRealtimeResumeError("cursor-expired", `OData delta link expired or was rejected by the server (HTTP ${String(response.status)}).`);
166
+ }
167
+ throw realtimeFailure(response.status >= 500 ? "transport-gap" : "invalid-event", `OData delta request failed with HTTP ${String(response.status)}${response.statusText ? ` ${response.statusText}` : ""}.`, body);
168
+ }
169
+ const body = await safeReadJson(response);
170
+ if (!isRecord(body) || !Array.isArray(body.value)) {
171
+ throw realtimeFailure("invalid-event", "OData delta response is missing a JSON `value` array.", body);
172
+ }
173
+ return body;
174
+ }
175
+ function parseEntry(raw) {
176
+ if (!isRecord(raw)) {
177
+ throw realtimeFailure("invalid-event", "OData delta entry must be a JSON object.", raw);
178
+ }
179
+ const removed = raw["@removed"] ?? raw["@odata.removed"];
180
+ if (removed !== undefined) {
181
+ return { kind: "delete", patch: { id: removedEntryId(raw) } };
182
+ }
183
+ const isRelationshipDelta = options.isRelationshipDeltaEntry ?? defaultIsRelationshipDeltaEntry;
184
+ if (isRelationshipDelta(raw)) {
185
+ throw realtimeFailure("invalid-event", "OData relationship (link) deltas are not supported by createOdataDeltaTransport; only entity upserts and removals are normalized (REQ-003).", raw);
186
+ }
187
+ try {
188
+ const id = options.entityId(raw);
189
+ const feature = (options.toFeature ?? defaultToFeature)(raw);
190
+ return { kind: "upsert", patch: { id, feature } };
191
+ }
192
+ catch (cause) {
193
+ throw realtimeFailure("invalid-event", "OData delta entry projection (entityId/toFeature) failed.", cause);
194
+ }
195
+ }
196
+ function removedEntryId(entry) {
197
+ const withoutAnnotations = Object.fromEntries(Object.entries(entry).filter(([key]) => !key.startsWith("@")));
198
+ if (Object.keys(withoutAnnotations).length > 0) {
199
+ try {
200
+ return options.entityId(withoutAnnotations);
201
+ }
202
+ catch {
203
+ // Fall through to @id parsing below.
204
+ }
205
+ }
206
+ const idValue = entry["@id"] ?? entry["@odata.id"];
207
+ if (typeof idValue !== "string") {
208
+ throw realtimeFailure("invalid-event", "OData removed delta entry has neither key properties nor an @id/@odata.id to derive an id from.", entry);
209
+ }
210
+ const key = parseODataIdKey(idValue);
211
+ if (key === undefined) {
212
+ throw realtimeFailure("invalid-event", `OData removed delta entry's id "${idValue}" uses a composite or unparseable key; the removed entry must retain key properties instead.`, entry);
213
+ }
214
+ return key;
215
+ }
216
+ async function runCycle(startUrl, mode) {
217
+ let target = startUrl;
218
+ let pages = 0;
219
+ const upserts = [];
220
+ const deletes = [];
221
+ let deltaLink;
222
+ while (true) {
223
+ pages += 1;
224
+ if (pages > maxPagesPerCycle) {
225
+ throw realtimeFailure("delivery-failed", `OData delta paging exceeded the configured ${String(maxPagesPerCycle)}-page bound.`, undefined);
226
+ }
227
+ const envelope = await fetchOdataDocument(target, mode === "snapshot" && pages === 1);
228
+ for (const raw of envelope.value) {
229
+ const parsed = parseEntry(raw);
230
+ if (parsed.kind === "delete")
231
+ deletes.push(parsed.patch);
232
+ else
233
+ upserts.push(parsed.patch);
234
+ if (mode === "snapshot" && upserts.length > maxSnapshotRows) {
235
+ throw realtimeFailure("delivery-failed", `OData snapshot exceeded the configured ${String(maxSnapshotRows)}-row bound.`, undefined);
236
+ }
237
+ }
238
+ const pageDeltaLink = envelope["@odata.deltaLink"];
239
+ if (pageDeltaLink !== undefined) {
240
+ const resolved = parseRelativeOdataUrl(pageDeltaLink, target, `OData response @odata.deltaLink "${pageDeltaLink}" is not a valid URL.`);
241
+ assertSameOdataCollection(collectionUrl, resolved);
242
+ deltaLink = resolved.toString();
243
+ }
244
+ const nextLink = envelope["@odata.nextLink"];
245
+ if (nextLink === undefined)
246
+ break;
247
+ const resolvedNext = parseRelativeOdataUrl(nextLink, target, `OData response @odata.nextLink "${nextLink}" is not a valid URL.`);
248
+ assertSameOdataCollection(collectionUrl, resolvedNext);
249
+ target = resolvedNext.toString();
250
+ }
251
+ if (deltaLink === undefined) {
252
+ throw realtimeFailure("invalid-event", "OData response did not include a terminal @odata.deltaLink; the server may not support delta-link change tracking for this collection.", undefined);
253
+ }
254
+ return { upserts, deletes, deltaLink };
255
+ }
256
+ function buildInitialUrl() {
257
+ const url = new URL(collectionUrl.toString());
258
+ const query = options.initialQuery;
259
+ if (query?.filter)
260
+ url.searchParams.set("$filter", query.filter);
261
+ if (query?.select?.length)
262
+ url.searchParams.set("$select", query.select.join(","));
263
+ if (query?.orderBy?.length)
264
+ url.searchParams.set("$orderby", query.orderBy.join(","));
265
+ if (typeof query?.top === "number" && Number.isFinite(query.top)) {
266
+ url.searchParams.set("$top", String(query.top));
267
+ }
268
+ return url.toString();
269
+ }
270
+ /**
271
+ * Shared recovery path for a `cursor-expired` failure from *either*
272
+ * cycle: a real server should only ever reject a `$deltatoken`, but a
273
+ * caller-supplied `isDeltaLinkExpiredResponse` could in principle
274
+ * classify any response that way, so both cycles route through the
275
+ * same bounded streak counter (REQ-005) rather than the snapshot
276
+ * cycle failing closed on its very first retry.
277
+ */
278
+ async function recoverFromExpiredDeltaLink(cause) {
279
+ resnapshotStreak += 1;
280
+ if (resnapshotStreak > maxConsecutiveResnapshots) {
281
+ fail(realtimeFailure("delivery-failed", `OData delta link expired ${String(resnapshotStreak)} times consecutively; giving up after the configured ${String(maxConsecutiveResnapshots)}-resnapshot bound.`, cause));
282
+ return;
283
+ }
284
+ reportPoll({ changed: false, upsertCount: 0, deleteCount: 0, scheduled: false });
285
+ const delivered = emit({
286
+ type: "status",
287
+ status: "reconnecting",
288
+ reason: "cursor-expired",
289
+ receivedAt: now(),
290
+ });
291
+ if (!delivered)
292
+ return;
293
+ await runSnapshotCycle();
294
+ }
295
+ async function runSnapshotCycle() {
296
+ try {
297
+ const cycle = await runCycle(buildInitialUrl(), "snapshot");
298
+ if (closed)
299
+ return;
300
+ resnapshotStreak = 0;
301
+ sequence += 1;
302
+ const delivered = emit({
303
+ type: "snapshot",
304
+ sequence,
305
+ deltaToken: cycle.deltaLink,
306
+ receivedAt: now(),
307
+ replace: true,
308
+ features: cycle.upserts,
309
+ });
310
+ if (!delivered)
311
+ return;
312
+ reportPoll({
313
+ changed: true,
314
+ upsertCount: cycle.upserts.length,
315
+ deleteCount: 0,
316
+ scheduled: true,
317
+ });
318
+ schedulePoll(cycle.deltaLink);
319
+ }
320
+ catch (cause) {
321
+ if (closed)
322
+ return;
323
+ if (cause instanceof HonuaRealtimeResumeError && cause.code === "cursor-expired") {
324
+ await recoverFromExpiredDeltaLink(cause);
325
+ return;
326
+ }
327
+ fail(cause);
328
+ }
329
+ }
330
+ async function runDeltaCycle(link) {
331
+ try {
332
+ const cycle = await runCycle(link, "delta");
333
+ if (closed)
334
+ return;
335
+ resnapshotStreak = 0;
336
+ const changed = cycle.upserts.length > 0 || cycle.deletes.length > 0;
337
+ if (changed)
338
+ sequence += 1;
339
+ const delivered = emit(changed
340
+ ? {
341
+ type: "delta",
342
+ sequence,
343
+ deltaToken: cycle.deltaLink,
344
+ receivedAt: now(),
345
+ ...(cycle.upserts.length ? { upserts: cycle.upserts } : {}),
346
+ ...(cycle.deletes.length ? { deletes: cycle.deletes } : {}),
347
+ }
348
+ : {
349
+ type: "status",
350
+ status: "live",
351
+ sequence,
352
+ deltaToken: cycle.deltaLink,
353
+ receivedAt: now(),
354
+ reason: "poll-unchanged",
355
+ });
356
+ if (!delivered)
357
+ return;
358
+ reportPoll({
359
+ changed,
360
+ upsertCount: cycle.upserts.length,
361
+ deleteCount: cycle.deletes.length,
362
+ scheduled: true,
363
+ });
364
+ schedulePoll(cycle.deltaLink);
365
+ }
366
+ catch (cause) {
367
+ if (closed)
368
+ return;
369
+ if (cause instanceof HonuaRealtimeResumeError && cause.code === "cursor-expired") {
370
+ await recoverFromExpiredDeltaLink(cause);
371
+ return;
372
+ }
373
+ fail(cause);
374
+ }
375
+ }
376
+ void (initialDeltaLink !== undefined ? runDeltaCycle(initialDeltaLink) : runSnapshotCycle());
377
+ return {
378
+ close() {
379
+ teardown("Subscription closed by caller.", true);
380
+ },
381
+ };
382
+ },
383
+ };
384
+ }
385
+ function defaultIsDeltaLinkExpiredResponse(status) {
386
+ return status === 410;
387
+ }
388
+ function defaultIsRelationshipDeltaEntry(entry) {
389
+ return typeof entry.source === "string" && typeof entry.relationship === "string" && typeof entry.target === "string";
390
+ }
391
+ function defaultToFeature(entity) {
392
+ const clean = {};
393
+ for (const [key, value] of Object.entries(entity)) {
394
+ if (!key.startsWith("@"))
395
+ clean[key] = value;
396
+ }
397
+ return clean;
398
+ }
399
+ /**
400
+ * Reject a next/delta link that does not resolve to the exact origin and
401
+ * collection path this transport was configured for (REQ-002). Trailing
402
+ * slashes are normalized so `.../Incidents` and `.../Incidents/` are treated
403
+ * as the same collection.
404
+ */
405
+ function assertSameOdataCollection(expected, candidate) {
406
+ if (candidate.origin !== expected.origin || normalizedPathname(candidate) !== normalizedPathname(expected)) {
407
+ throw new HonuaRealtimeResumeError("invalid-event", `OData delta/next link "${candidate.toString()}" does not resolve to the configured collection "${expected.toString()}"; refusing to follow a foreign link.`);
408
+ }
409
+ }
410
+ function normalizedPathname(url) {
411
+ return url.pathname.length > 1 && url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname;
412
+ }
413
+ /**
414
+ * Parse the single-value key predicate out of an OData `@id`/`@odata.id`
415
+ * value like `Incidents('AB-12')` or `Incidents(42)`. Returns `undefined`
416
+ * for composite keys (`Key1=1,Key2='a'`) or an unparseable shape — callers
417
+ * treat that as unsupported rather than guessing.
418
+ */
419
+ function parseODataIdKey(idValue) {
420
+ const open = idValue.lastIndexOf("(");
421
+ if (open === -1 || !idValue.endsWith(")"))
422
+ return undefined;
423
+ const inner = idValue.slice(open + 1, -1);
424
+ if (inner.includes("=") || hasTopLevelComma(inner))
425
+ return undefined;
426
+ const unquoted = inner.startsWith("'") && inner.endsWith("'") ? inner.slice(1, -1).replace(/''/g, "'") : inner;
427
+ if (unquoted.length === 0)
428
+ return undefined;
429
+ if (/^-?\d+$/.test(unquoted) && Number.isSafeInteger(Number(unquoted)))
430
+ return Number(unquoted);
431
+ return unquoted;
432
+ }
433
+ function hasTopLevelComma(inner) {
434
+ let quoted = false;
435
+ for (const character of inner) {
436
+ if (character === "'")
437
+ quoted = !quoted;
438
+ else if (character === "," && !quoted)
439
+ return true;
440
+ }
441
+ return false;
442
+ }
443
+ function parseAbsoluteUrl(input, message) {
444
+ try {
445
+ return new URL(input);
446
+ }
447
+ catch (cause) {
448
+ throw new TypeError(message, { cause });
449
+ }
450
+ }
451
+ function parseRelativeOdataUrl(value, base, message) {
452
+ try {
453
+ return new URL(value, base);
454
+ }
455
+ catch (cause) {
456
+ throw new HonuaRealtimeResumeError("invalid-event", message, { cause });
457
+ }
458
+ }
459
+ function resolveFetch(custom) {
460
+ if (custom)
461
+ return custom;
462
+ const globalFetch = globalThis.fetch;
463
+ if (!globalFetch)
464
+ throw new Error("fetch is not available; provide fetchImpl for this runtime.");
465
+ return globalFetch.bind(globalThis);
466
+ }
467
+ async function safeReadJson(response) {
468
+ try {
469
+ return await response.json();
470
+ }
471
+ catch {
472
+ return undefined;
473
+ }
474
+ }
475
+ function isRecord(value) {
476
+ return typeof value === "object" && value !== null;
477
+ }
478
+ function positiveInteger(value, name) {
479
+ if (!Number.isSafeInteger(value) || value < 1) {
480
+ throw new TypeError(`createOdataDeltaTransport: ${name} must be a safe integer greater than zero.`);
481
+ }
482
+ return value;
483
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Bounded, resumable SSE and WebSocket transports for `@honua/sdk-js/realtime`
3
+ * (issue #557), built on the #556 snapshot/delta/cursor/resume/plan-identity
4
+ * contract.
5
+ *
6
+ * `resumable.ts` deliberately never reconnects a transport — that ownership
7
+ * is explicitly deferred to this module (see
8
+ * `docs/decisions/realtime-snapshot-delta-cursor-resume-plan-identity-contract.md`,
9
+ * "the gate never reconnects a transport itself"). This module closes that
10
+ * gap by wrapping any raw {@link RealtimeFeatureTransport} (the SSE adapter
11
+ * in `sse.ts`, the WebSocket adapter in `websocket.ts`, or a custom one) with:
12
+ *
13
+ * - the bounded delivery gate from `resumable.ts` (`maxPendingEvents`,
14
+ * duplicate/gap detection, cross-scope checkpoint rejection);
15
+ * - reconnect ownership with exponential-backoff-and-jitter retry, bounded by
16
+ * `reconnect.maxAttempts` — exhausting attempts fails closed rather than
17
+ * retrying forever;
18
+ * - a heartbeat/liveness timeout that treats prolonged silence as a
19
+ * transport-detected gap;
20
+ * - resume-vs-resnapshot selection driven entirely by the gate's own
21
+ * `phase`: a reconnect resumes from the last accepted checkpoint's cursor
22
+ * only while the gate considers it valid, and requests a fresh snapshot
23
+ * the moment the gate (or this module, via `requireResnapshot`) decides
24
+ * otherwise — REQ-003's "resume only with a valid scoped cursor";
25
+ * - idempotent disposal that stops timers, the active connection, and the
26
+ * delivery gate exactly once, however disposal was triggered
27
+ * (caller `close()`, external `AbortSignal`, or an unrecoverable failure);
28
+ * - redacted telemetry (`onTelemetry`) built on `contract.ts`'s
29
+ * `deriveRealtimeContractAuthority` / `redactRealtimeCheckpoint`, so a raw
30
+ * cursor, watermark, or delta-token never reaches a log or metrics sink.
31
+ *
32
+ * The result still satisfies `RealtimeFeatureTransport`, so it composes with
33
+ * `createRealtimeFeatureStore` exactly like any other transport.
34
+ *
35
+ * @module
36
+ */
37
+ import type { RealtimeContractAuthority, RedactedRealtimeCheckpointV1 } from "./contract.js";
38
+ import { type RealtimeCheckpointStore, type RealtimeDurableCheckpointV1, type RealtimeResumeContextV1 } from "./resumable.js";
39
+ import type { RealtimeServerSentEventsTransportOptions } from "./sse.js";
40
+ import type { RealtimeFeatureTransport } from "./types.js";
41
+ import type { RealtimeWebSocketTransportOptions } from "./websocket.js";
42
+ export interface RealtimeReconnectPolicy {
43
+ /** Consecutive reconnect attempts allowed before failing closed. `0` disables reconnect entirely. @default 8 */
44
+ readonly maxAttempts?: number;
45
+ /** Delay before the first reconnect attempt. @default 250 */
46
+ readonly baseDelayMs?: number;
47
+ /** Upper bound on the exponential backoff delay, before jitter. @default 30000 */
48
+ readonly maxDelayMs?: number;
49
+ /** How long a connection must stay live before a subsequent failure resets the attempt counter. @default 15000 */
50
+ readonly resetAfterMs?: number;
51
+ }
52
+ export interface RealtimeResumableTransportTelemetry {
53
+ readonly authority: RealtimeContractAuthority;
54
+ readonly reconnectAttempt: number;
55
+ readonly acceptedEventCount: number;
56
+ readonly duplicateEventCount: number;
57
+ readonly gapCount: number;
58
+ readonly overflowCount: number;
59
+ /** Never a raw cursor, watermark, or delta-token value. */
60
+ readonly checkpoint?: RedactedRealtimeCheckpointV1;
61
+ }
62
+ export interface RealtimeResumableTransportOptions<TFeature = unknown> {
63
+ readonly context: RealtimeResumeContextV1;
64
+ readonly checkpointStore?: RealtimeCheckpointStore;
65
+ /**
66
+ * Seed resume position for the very first connection, validated the same
67
+ * way a loaded `checkpointStore` checkpoint is (`evaluateRealtimeCheckpoint`).
68
+ * This is the only supported way to seed a resume position: `subscribe()`'s
69
+ * `request.cursor` / `resumeFrom` and similar fields are ignored by this
70
+ * wrapper so a stale or unscoped caller-supplied position can never bypass
71
+ * checkpoint compatibility validation.
72
+ */
73
+ readonly initialCheckpoint?: RealtimeDurableCheckpointV1;
74
+ /** Includes the currently applying event. @default 64 */
75
+ readonly maxPendingEvents?: number;
76
+ /** Bounded event-id history persisted with each checkpoint. @default 256 */
77
+ readonly maxRecentEventIds?: number;
78
+ readonly reconnect?: RealtimeReconnectPolicy;
79
+ /** No event (including heartbeats) within this window is treated as a transport-detected gap. Disabled when omitted. */
80
+ readonly heartbeatTimeoutMs?: number;
81
+ /** Forwarded to {@link deriveRealtimeContractAuthority} for telemetry. */
82
+ readonly staleAfterMs?: number;
83
+ readonly onTelemetry?: (telemetry: RealtimeResumableTransportTelemetry) => void;
84
+ readonly now?: () => number;
85
+ }
86
+ /**
87
+ * Exponential backoff with jitter in the [0.5x, 1x] band for the given
88
+ * zero-based reconnect attempt — the same shape as
89
+ * `core/request-pipeline.ts`'s `resolveRetryDelayMs`, reimplemented locally
90
+ * so `@honua/sdk-js/realtime` does not pull in the HTTP request pipeline's
91
+ * error/type graph for one small helper. Exported so the schedule can be
92
+ * asserted deterministically without driving a fake transport end-to-end.
93
+ */
94
+ export declare function computeReconnectDelayMs(policy: RealtimeReconnectPolicy | undefined, attempt: number): number;
95
+ /**
96
+ * Wrap a raw {@link RealtimeFeatureTransport} with bounded, resumable
97
+ * delivery: the #556 delivery gate, reconnect/backoff, heartbeat timeout,
98
+ * and redacted telemetry. See the module doc for the full behavior.
99
+ */
100
+ export declare function createResumableRealtimeTransport<TFeature = unknown>(transport: RealtimeFeatureTransport<TFeature>, options: RealtimeResumableTransportOptions<TFeature>): RealtimeFeatureTransport<TFeature>;
101
+ /**
102
+ * Convenience factory combining {@link createRealtimeServerSentEventsTransport}
103
+ * with {@link createResumableRealtimeTransport}.
104
+ */
105
+ export declare function createResumableServerSentEventsTransport<TFeature = unknown>(sseOptions: RealtimeServerSentEventsTransportOptions<TFeature>, resumableOptions: RealtimeResumableTransportOptions<TFeature>): RealtimeFeatureTransport<TFeature>;
106
+ /**
107
+ * Convenience factory combining {@link createRealtimeWebSocketTransport}
108
+ * with {@link createResumableRealtimeTransport}.
109
+ */
110
+ export declare function createResumableWebSocketTransport<TFeature = unknown>(webSocketOptions: RealtimeWebSocketTransportOptions<TFeature>, resumableOptions: RealtimeResumableTransportOptions<TFeature>): RealtimeFeatureTransport<TFeature>;
111
+ //# sourceMappingURL=resumable-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumable-transport.d.ts","sourceRoot":"","sources":["../../../src/realtime/resumable-transport.ts"],"names":[],"mappings":"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"}