@honua/app-platform 0.0.20-alpha.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 (840) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +11 -0
  3. package/app/index.d.ts +164 -0
  4. package/app/index.d.ts.map +1 -0
  5. package/app/index.js +424 -0
  6. package/app-controller/controller.d.ts +425 -0
  7. package/app-controller/controller.d.ts.map +1 -0
  8. package/app-controller/controller.js +1173 -0
  9. package/app-controller/index.d.ts +14 -0
  10. package/app-controller/index.d.ts.map +1 -0
  11. package/app-controller/index.js +12 -0
  12. package/app-workspace/index.d.ts +421 -0
  13. package/app-workspace/index.d.ts.map +1 -0
  14. package/app-workspace/index.js +722 -0
  15. package/collaboration/client.d.ts +40 -0
  16. package/collaboration/client.d.ts.map +1 -0
  17. package/collaboration/client.js +299 -0
  18. package/collaboration/errors.d.ts +15 -0
  19. package/collaboration/errors.d.ts.map +1 -0
  20. package/collaboration/errors.js +17 -0
  21. package/collaboration/fixture.d.ts +41 -0
  22. package/collaboration/fixture.d.ts.map +1 -0
  23. package/collaboration/fixture.js +362 -0
  24. package/collaboration/index.d.ts +18 -0
  25. package/collaboration/index.d.ts.map +1 -0
  26. package/collaboration/index.js +14 -0
  27. package/collaboration/types.d.ts +240 -0
  28. package/collaboration/types.d.ts.map +1 -0
  29. package/collaboration/types.js +1 -0
  30. package/contract/analytics-sources.d.ts +149 -0
  31. package/contract/analytics-sources.d.ts.map +1 -0
  32. package/contract/analytics-sources.js +235 -0
  33. package/contract/edit-session.d.ts +203 -0
  34. package/contract/edit-session.d.ts.map +1 -0
  35. package/contract/edit-session.js +760 -0
  36. package/contract/edit-sketch.d.ts +91 -0
  37. package/contract/edit-sketch.d.ts.map +1 -0
  38. package/contract/edit-sketch.js +281 -0
  39. package/contract/index.d.ts +63 -0
  40. package/contract/index.d.ts.map +1 -0
  41. package/contract/index.js +52 -0
  42. package/contract/jobs.d.ts +149 -0
  43. package/contract/jobs.d.ts.map +1 -0
  44. package/contract/jobs.js +40 -0
  45. package/contract/pmtiles.d.ts +162 -0
  46. package/contract/pmtiles.d.ts.map +1 -0
  47. package/contract/pmtiles.js +155 -0
  48. package/contract/source.d.ts +447 -0
  49. package/contract/source.d.ts.map +1 -0
  50. package/contract/source.js +3909 -0
  51. package/contract/spatial-aggregation.d.ts +336 -0
  52. package/contract/spatial-aggregation.d.ts.map +1 -0
  53. package/contract/spatial-aggregation.js +298 -0
  54. package/contract/temporal.d.ts +455 -0
  55. package/contract/temporal.d.ts.map +1 -0
  56. package/contract/temporal.js +146 -0
  57. package/contract/tiles.d.ts +370 -0
  58. package/contract/tiles.d.ts.map +1 -0
  59. package/contract/tiles.js +519 -0
  60. package/contract/types.d.ts +694 -0
  61. package/contract/types.d.ts.map +1 -0
  62. package/contract/types.js +183 -0
  63. package/contract/widget-source.d.ts +205 -0
  64. package/contract/widget-source.d.ts.map +1 -0
  65. package/contract/widget-source.js +1473 -0
  66. package/control-plane/client.d.ts +95 -0
  67. package/control-plane/client.d.ts.map +1 -0
  68. package/control-plane/client.js +374 -0
  69. package/control-plane/index.d.ts +18 -0
  70. package/control-plane/index.d.ts.map +1 -0
  71. package/control-plane/index.js +14 -0
  72. package/control-plane/types.d.ts +233 -0
  73. package/control-plane/types.d.ts.map +1 -0
  74. package/control-plane/types.js +7 -0
  75. package/controls/basemap-style-binding.d.ts +54 -0
  76. package/controls/basemap-style-binding.d.ts.map +1 -0
  77. package/controls/basemap-style-binding.js +199 -0
  78. package/controls/basemap-switcher.d.ts +95 -0
  79. package/controls/basemap-switcher.d.ts.map +1 -0
  80. package/controls/basemap-switcher.js +379 -0
  81. package/controls/element-utils.d.ts +48 -0
  82. package/controls/element-utils.d.ts.map +1 -0
  83. package/controls/element-utils.js +78 -0
  84. package/controls/index.d.ts +33 -0
  85. package/controls/index.d.ts.map +1 -0
  86. package/controls/index.js +30 -0
  87. package/controls/layer-list.d.ts +98 -0
  88. package/controls/layer-list.d.ts.map +1 -0
  89. package/controls/layer-list.js +375 -0
  90. package/controls/legend-derive.d.ts +53 -0
  91. package/controls/legend-derive.d.ts.map +1 -0
  92. package/controls/legend-derive.js +196 -0
  93. package/controls/legend.d.ts +104 -0
  94. package/controls/legend.d.ts.map +1 -0
  95. package/controls/legend.js +381 -0
  96. package/controls/swipe-control.d.ts +80 -0
  97. package/controls/swipe-control.d.ts.map +1 -0
  98. package/controls/swipe-control.js +368 -0
  99. package/controls/types.d.ts +227 -0
  100. package/controls/types.d.ts.map +1 -0
  101. package/controls/types.js +11 -0
  102. package/core/auth/client-credentials-provider.d.ts +51 -0
  103. package/core/auth/client-credentials-provider.d.ts.map +1 -0
  104. package/core/auth/client-credentials-provider.js +115 -0
  105. package/core/auth/credential-store.d.ts +52 -0
  106. package/core/auth/credential-store.d.ts.map +1 -0
  107. package/core/auth/credential-store.js +82 -0
  108. package/core/auth/index.d.ts +23 -0
  109. package/core/auth/index.d.ts.map +1 -0
  110. package/core/auth/index.js +20 -0
  111. package/core/auth/oauth2-provider.d.ts +114 -0
  112. package/core/auth/oauth2-provider.d.ts.map +1 -0
  113. package/core/auth/oauth2-provider.js +408 -0
  114. package/core/auth/pkce.d.ts +25 -0
  115. package/core/auth/pkce.d.ts.map +1 -0
  116. package/core/auth/pkce.js +46 -0
  117. package/core/auth/static-providers.d.ts +20 -0
  118. package/core/auth/static-providers.d.ts.map +1 -0
  119. package/core/auth/static-providers.js +26 -0
  120. package/core/auth/token-endpoint.d.ts +40 -0
  121. package/core/auth/token-endpoint.d.ts.map +1 -0
  122. package/core/auth/token-endpoint.js +133 -0
  123. package/core/auth/types.d.ts +144 -0
  124. package/core/auth/types.d.ts.map +1 -0
  125. package/core/auth/types.js +8 -0
  126. package/core/batch.d.ts +37 -0
  127. package/core/batch.d.ts.map +1 -0
  128. package/core/batch.js +79 -0
  129. package/core/cache-state.d.ts +79 -0
  130. package/core/cache-state.d.ts.map +1 -0
  131. package/core/cache-state.js +87 -0
  132. package/core/client.d.ts +607 -0
  133. package/core/client.d.ts.map +1 -0
  134. package/core/client.js +1716 -0
  135. package/core/compatibility.d.ts +18 -0
  136. package/core/compatibility.d.ts.map +1 -0
  137. package/core/compatibility.js +245 -0
  138. package/core/errors.d.ts +139 -0
  139. package/core/errors.d.ts.map +1 -0
  140. package/core/errors.js +176 -0
  141. package/core/esri-geojson.d.ts +66 -0
  142. package/core/esri-geojson.d.ts.map +1 -0
  143. package/core/esri-geojson.js +363 -0
  144. package/core/geoparquet-sql.d.ts +162 -0
  145. package/core/geoparquet-sql.d.ts.map +1 -0
  146. package/core/geoparquet-sql.js +333 -0
  147. package/core/geoservices.d.ts +34 -0
  148. package/core/geoservices.d.ts.map +1 -0
  149. package/core/geoservices.js +434 -0
  150. package/core/grpc-adapter.d.ts +23 -0
  151. package/core/grpc-adapter.d.ts.map +1 -0
  152. package/core/grpc-adapter.js +688 -0
  153. package/core/odata.d.ts +347 -0
  154. package/core/odata.d.ts.map +1 -0
  155. package/core/odata.js +913 -0
  156. package/core/ogc-conformance.d.ts +35 -0
  157. package/core/ogc-conformance.d.ts.map +1 -0
  158. package/core/ogc-conformance.js +134 -0
  159. package/core/ogc-endpoint-layout.d.ts +70 -0
  160. package/core/ogc-endpoint-layout.d.ts.map +1 -0
  161. package/core/ogc-endpoint-layout.js +173 -0
  162. package/core/ogc-features.d.ts +23 -0
  163. package/core/ogc-features.d.ts.map +1 -0
  164. package/core/ogc-features.js +129 -0
  165. package/core/ogc-maps.d.ts +49 -0
  166. package/core/ogc-maps.d.ts.map +1 -0
  167. package/core/ogc-maps.js +126 -0
  168. package/core/ogc-processes.d.ts +118 -0
  169. package/core/ogc-processes.d.ts.map +1 -0
  170. package/core/ogc-processes.js +423 -0
  171. package/core/ogc-records.d.ts +75 -0
  172. package/core/ogc-records.d.ts.map +1 -0
  173. package/core/ogc-records.js +251 -0
  174. package/core/ogc-tiles.d.ts +125 -0
  175. package/core/ogc-tiles.d.ts.map +1 -0
  176. package/core/ogc-tiles.js +183 -0
  177. package/core/path-utils.d.ts +69 -0
  178. package/core/path-utils.d.ts.map +1 -0
  179. package/core/path-utils.js +123 -0
  180. package/core/pbf-decoder.d.ts +39 -0
  181. package/core/pbf-decoder.d.ts.map +1 -0
  182. package/core/pbf-decoder.js +702 -0
  183. package/core/process-runner.d.ts +104 -0
  184. package/core/process-runner.d.ts.map +1 -0
  185. package/core/process-runner.js +315 -0
  186. package/core/protocol-transport.d.ts +76 -0
  187. package/core/protocol-transport.d.ts.map +1 -0
  188. package/core/protocol-transport.js +15 -0
  189. package/core/query-builder.d.ts +261 -0
  190. package/core/query-builder.d.ts.map +1 -0
  191. package/core/query-builder.js +538 -0
  192. package/core/request-pipeline.d.ts +88 -0
  193. package/core/request-pipeline.d.ts.map +1 -0
  194. package/core/request-pipeline.js +273 -0
  195. package/core/spatial-filter.d.ts +93 -0
  196. package/core/spatial-filter.d.ts.map +1 -0
  197. package/core/spatial-filter.js +153 -0
  198. package/core/stac-static.d.ts +51 -0
  199. package/core/stac-static.d.ts.map +1 -0
  200. package/core/stac-static.js +195 -0
  201. package/core/stac.d.ts +67 -0
  202. package/core/stac.d.ts.map +1 -0
  203. package/core/stac.js +259 -0
  204. package/core/surfaces.d.ts +540 -0
  205. package/core/surfaces.d.ts.map +1 -0
  206. package/core/surfaces.js +1964 -0
  207. package/core/terrain-elevation.d.ts +114 -0
  208. package/core/terrain-elevation.d.ts.map +1 -0
  209. package/core/terrain-elevation.js +150 -0
  210. package/core/types.d.ts +1404 -0
  211. package/core/types.d.ts.map +1 -0
  212. package/core/types.js +13 -0
  213. package/core/wfs-capabilities.d.ts +153 -0
  214. package/core/wfs-capabilities.d.ts.map +1 -0
  215. package/core/wfs-capabilities.js +490 -0
  216. package/core/wfs-filter.d.ts +118 -0
  217. package/core/wfs-filter.d.ts.map +1 -0
  218. package/core/wfs-filter.js +634 -0
  219. package/core/wfs.d.ts +232 -0
  220. package/core/wfs.d.ts.map +1 -0
  221. package/core/wfs.js +426 -0
  222. package/core/wire-shared.d.ts +32 -0
  223. package/core/wire-shared.d.ts.map +1 -0
  224. package/core/wire-shared.js +76 -0
  225. package/core/wms-axis.d.ts +36 -0
  226. package/core/wms-axis.d.ts.map +1 -0
  227. package/core/wms-axis.js +73 -0
  228. package/core/wms-capabilities.d.ts +110 -0
  229. package/core/wms-capabilities.d.ts.map +1 -0
  230. package/core/wms-capabilities.js +559 -0
  231. package/core/wms-types.d.ts +128 -0
  232. package/core/wms-types.d.ts.map +1 -0
  233. package/core/wms-types.js +32 -0
  234. package/core/wms.d.ts +144 -0
  235. package/core/wms.d.ts.map +1 -0
  236. package/core/wms.js +338 -0
  237. package/core/wmts-capabilities.d.ts +82 -0
  238. package/core/wmts-capabilities.d.ts.map +1 -0
  239. package/core/wmts-capabilities.js +402 -0
  240. package/core/wmts.d.ts +103 -0
  241. package/core/wmts.d.ts.map +1 -0
  242. package/core/wmts.js +332 -0
  243. package/core/xml-text.d.ts +20 -0
  244. package/core/xml-text.d.ts.map +1 -0
  245. package/core/xml-text.js +85 -0
  246. package/esri-compat/basemap-gallery.d.ts +38 -0
  247. package/esri-compat/basemap-gallery.d.ts.map +1 -0
  248. package/esri-compat/basemap-gallery.js +159 -0
  249. package/esri-compat/basemap-layer-list.d.ts +35 -0
  250. package/esri-compat/basemap-layer-list.d.ts.map +1 -0
  251. package/esri-compat/basemap-layer-list.js +139 -0
  252. package/esri-compat/basemap.d.ts +32 -0
  253. package/esri-compat/basemap.d.ts.map +1 -0
  254. package/esri-compat/basemap.js +84 -0
  255. package/esri-compat/bookmarks.d.ts +36 -0
  256. package/esri-compat/bookmarks.d.ts.map +1 -0
  257. package/esri-compat/bookmarks.js +108 -0
  258. package/esri-compat/class-breaks-renderer.d.ts +50 -0
  259. package/esri-compat/class-breaks-renderer.d.ts.map +1 -0
  260. package/esri-compat/class-breaks-renderer.js +164 -0
  261. package/esri-compat/color.d.ts +22 -0
  262. package/esri-compat/color.d.ts.map +1 -0
  263. package/esri-compat/color.js +106 -0
  264. package/esri-compat/controls.d.ts +174 -0
  265. package/esri-compat/controls.d.ts.map +1 -0
  266. package/esri-compat/controls.js +479 -0
  267. package/esri-compat/coordinate-conversion.d.ts +41 -0
  268. package/esri-compat/coordinate-conversion.d.ts.map +1 -0
  269. package/esri-compat/coordinate-conversion.js +125 -0
  270. package/esri-compat/directions.d.ts +45 -0
  271. package/esri-compat/directions.d.ts.map +1 -0
  272. package/esri-compat/directions.js +123 -0
  273. package/esri-compat/editor.d.ts +47 -0
  274. package/esri-compat/editor.d.ts.map +1 -0
  275. package/esri-compat/editor.js +170 -0
  276. package/esri-compat/esri-config.d.ts +16 -0
  277. package/esri-compat/esri-config.d.ts.map +1 -0
  278. package/esri-compat/esri-config.js +23 -0
  279. package/esri-compat/esri-request.d.ts +17 -0
  280. package/esri-compat/esri-request.d.ts.map +1 -0
  281. package/esri-compat/esri-request.js +127 -0
  282. package/esri-compat/event-bus.d.ts +106 -0
  283. package/esri-compat/event-bus.d.ts.map +1 -0
  284. package/esri-compat/event-bus.js +90 -0
  285. package/esri-compat/expand.d.ts +36 -0
  286. package/esri-compat/expand.d.ts.map +1 -0
  287. package/esri-compat/expand.js +97 -0
  288. package/esri-compat/extent.d.ts +43 -0
  289. package/esri-compat/extent.d.ts.map +1 -0
  290. package/esri-compat/extent.js +140 -0
  291. package/esri-compat/feature-filter.d.ts +55 -0
  292. package/esri-compat/feature-filter.d.ts.map +1 -0
  293. package/esri-compat/feature-filter.js +109 -0
  294. package/esri-compat/feature-form.d.ts +64 -0
  295. package/esri-compat/feature-form.d.ts.map +1 -0
  296. package/esri-compat/feature-form.js +137 -0
  297. package/esri-compat/feature-layer.d.ts +173 -0
  298. package/esri-compat/feature-layer.d.ts.map +1 -0
  299. package/esri-compat/feature-layer.js +661 -0
  300. package/esri-compat/feature-set.d.ts +32 -0
  301. package/esri-compat/feature-set.d.ts.map +1 -0
  302. package/esri-compat/feature-set.js +80 -0
  303. package/esri-compat/feature-table.d.ts +141 -0
  304. package/esri-compat/feature-table.d.ts.map +1 -0
  305. package/esri-compat/feature-table.js +500 -0
  306. package/esri-compat/feature-templates.d.ts +41 -0
  307. package/esri-compat/feature-templates.d.ts.map +1 -0
  308. package/esri-compat/feature-templates.js +97 -0
  309. package/esri-compat/feature.d.ts +33 -0
  310. package/esri-compat/feature.d.ts.map +1 -0
  311. package/esri-compat/feature.js +83 -0
  312. package/esri-compat/geojson-layer.d.ts +86 -0
  313. package/esri-compat/geojson-layer.d.ts.map +1 -0
  314. package/esri-compat/geojson-layer.js +191 -0
  315. package/esri-compat/geometry-engine.d.ts +107 -0
  316. package/esri-compat/geometry-engine.d.ts.map +1 -0
  317. package/esri-compat/geometry-engine.js +266 -0
  318. package/esri-compat/graphic.d.ts +46 -0
  319. package/esri-compat/graphic.d.ts.map +1 -0
  320. package/esri-compat/graphic.js +103 -0
  321. package/esri-compat/graphics-layer.d.ts +49 -0
  322. package/esri-compat/graphics-layer.d.ts.map +1 -0
  323. package/esri-compat/graphics-layer.js +185 -0
  324. package/esri-compat/group-layer.d.ts +48 -0
  325. package/esri-compat/group-layer.d.ts.map +1 -0
  326. package/esri-compat/group-layer.js +212 -0
  327. package/esri-compat/identify.d.ts +71 -0
  328. package/esri-compat/identify.d.ts.map +1 -0
  329. package/esri-compat/identify.js +299 -0
  330. package/esri-compat/identity-manager.d.ts +74 -0
  331. package/esri-compat/identity-manager.d.ts.map +1 -0
  332. package/esri-compat/identity-manager.js +245 -0
  333. package/esri-compat/imagery-layer.d.ts +78 -0
  334. package/esri-compat/imagery-layer.d.ts.map +1 -0
  335. package/esri-compat/imagery-layer.js +167 -0
  336. package/esri-compat/label-class.d.ts +31 -0
  337. package/esri-compat/label-class.d.ts.map +1 -0
  338. package/esri-compat/label-class.js +102 -0
  339. package/esri-compat/layer-list.d.ts +77 -0
  340. package/esri-compat/layer-list.d.ts.map +1 -0
  341. package/esri-compat/layer-list.js +342 -0
  342. package/esri-compat/legend.d.ts +53 -0
  343. package/esri-compat/legend.d.ts.map +1 -0
  344. package/esri-compat/legend.js +254 -0
  345. package/esri-compat/map-image-layer.d.ts +162 -0
  346. package/esri-compat/map-image-layer.d.ts.map +1 -0
  347. package/esri-compat/map-image-layer.js +709 -0
  348. package/esri-compat/map-view.d.ts +323 -0
  349. package/esri-compat/map-view.d.ts.map +1 -0
  350. package/esri-compat/map-view.js +1175 -0
  351. package/esri-compat/map.d.ts +47 -0
  352. package/esri-compat/map.d.ts.map +1 -0
  353. package/esri-compat/map.js +209 -0
  354. package/esri-compat/measurement-2d.d.ts +61 -0
  355. package/esri-compat/measurement-2d.d.ts.map +1 -0
  356. package/esri-compat/measurement-2d.js +184 -0
  357. package/esri-compat/measurement.d.ts +45 -0
  358. package/esri-compat/measurement.d.ts.map +1 -0
  359. package/esri-compat/measurement.js +193 -0
  360. package/esri-compat/oauth-info.d.ts +50 -0
  361. package/esri-compat/oauth-info.d.ts.map +1 -0
  362. package/esri-compat/oauth-info.js +142 -0
  363. package/esri-compat/picture-marker-symbol.d.ts +35 -0
  364. package/esri-compat/picture-marker-symbol.d.ts.map +1 -0
  365. package/esri-compat/picture-marker-symbol.js +126 -0
  366. package/esri-compat/point.d.ts +31 -0
  367. package/esri-compat/point.d.ts.map +1 -0
  368. package/esri-compat/point.js +102 -0
  369. package/esri-compat/polygon.d.ts +31 -0
  370. package/esri-compat/polygon.d.ts.map +1 -0
  371. package/esri-compat/polygon.js +107 -0
  372. package/esri-compat/polyline.d.ts +31 -0
  373. package/esri-compat/polyline.d.ts.map +1 -0
  374. package/esri-compat/polyline.js +107 -0
  375. package/esri-compat/popup-template.d.ts +55 -0
  376. package/esri-compat/popup-template.d.ts.map +1 -0
  377. package/esri-compat/popup-template.js +128 -0
  378. package/esri-compat/popup.d.ts +54 -0
  379. package/esri-compat/popup.d.ts.map +1 -0
  380. package/esri-compat/popup.js +312 -0
  381. package/esri-compat/print.d.ts +47 -0
  382. package/esri-compat/print.d.ts.map +1 -0
  383. package/esri-compat/print.js +105 -0
  384. package/esri-compat/query.d.ts +58 -0
  385. package/esri-compat/query.d.ts.map +1 -0
  386. package/esri-compat/query.js +128 -0
  387. package/esri-compat/reactive-utils.d.ts +24 -0
  388. package/esri-compat/reactive-utils.d.ts.map +1 -0
  389. package/esri-compat/reactive-utils.js +193 -0
  390. package/esri-compat/request.d.ts +41 -0
  391. package/esri-compat/request.d.ts.map +1 -0
  392. package/esri-compat/request.js +253 -0
  393. package/esri-compat/route-layer.d.ts +59 -0
  394. package/esri-compat/route-layer.d.ts.map +1 -0
  395. package/esri-compat/route-layer.js +223 -0
  396. package/esri-compat/route-task.d.ts +88 -0
  397. package/esri-compat/route-task.d.ts.map +1 -0
  398. package/esri-compat/route-task.js +225 -0
  399. package/esri-compat/scene-view.d.ts +41 -0
  400. package/esri-compat/scene-view.d.ts.map +1 -0
  401. package/esri-compat/scene-view.js +68 -0
  402. package/esri-compat/search.d.ts +112 -0
  403. package/esri-compat/search.d.ts.map +1 -0
  404. package/esri-compat/search.js +820 -0
  405. package/esri-compat/simple-fill-symbol.d.ts +27 -0
  406. package/esri-compat/simple-fill-symbol.d.ts.map +1 -0
  407. package/esri-compat/simple-fill-symbol.js +85 -0
  408. package/esri-compat/simple-line-symbol.d.ts +27 -0
  409. package/esri-compat/simple-line-symbol.d.ts.map +1 -0
  410. package/esri-compat/simple-line-symbol.js +85 -0
  411. package/esri-compat/simple-marker-symbol.d.ts +29 -0
  412. package/esri-compat/simple-marker-symbol.d.ts.map +1 -0
  413. package/esri-compat/simple-marker-symbol.js +92 -0
  414. package/esri-compat/simple-renderer.d.ts +29 -0
  415. package/esri-compat/simple-renderer.d.ts.map +1 -0
  416. package/esri-compat/simple-renderer.js +92 -0
  417. package/esri-compat/sketch.d.ts +64 -0
  418. package/esri-compat/sketch.d.ts.map +1 -0
  419. package/esri-compat/sketch.js +227 -0
  420. package/esri-compat/spatial-reference.d.ts +31 -0
  421. package/esri-compat/spatial-reference.d.ts.map +1 -0
  422. package/esri-compat/spatial-reference.js +102 -0
  423. package/esri-compat/swipe.d.ts +34 -0
  424. package/esri-compat/swipe.d.ts.map +1 -0
  425. package/esri-compat/swipe.js +93 -0
  426. package/esri-compat/table-list.d.ts +36 -0
  427. package/esri-compat/table-list.d.ts.map +1 -0
  428. package/esri-compat/table-list.js +126 -0
  429. package/esri-compat/text-symbol.d.ts +37 -0
  430. package/esri-compat/text-symbol.d.ts.map +1 -0
  431. package/esri-compat/text-symbol.js +123 -0
  432. package/esri-compat/tile-layer.d.ts +52 -0
  433. package/esri-compat/tile-layer.d.ts.map +1 -0
  434. package/esri-compat/tile-layer.js +168 -0
  435. package/esri-compat/time-slider.d.ts +70 -0
  436. package/esri-compat/time-slider.d.ts.map +1 -0
  437. package/esri-compat/time-slider.js +208 -0
  438. package/esri-compat/track.d.ts +51 -0
  439. package/esri-compat/track.d.ts.map +1 -0
  440. package/esri-compat/track.js +174 -0
  441. package/esri-compat/unique-value-renderer.d.ts +41 -0
  442. package/esri-compat/unique-value-renderer.d.ts.map +1 -0
  443. package/esri-compat/unique-value-renderer.js +127 -0
  444. package/esri-compat/url.d.ts +13 -0
  445. package/esri-compat/url.d.ts.map +1 -0
  446. package/esri-compat/url.js +68 -0
  447. package/esri-compat/vector-tile-layer.d.ts +47 -0
  448. package/esri-compat/vector-tile-layer.d.ts.map +1 -0
  449. package/esri-compat/vector-tile-layer.js +130 -0
  450. package/esri-compat/web-map.d.ts +14 -0
  451. package/esri-compat/web-map.d.ts.map +1 -0
  452. package/esri-compat/web-map.js +24 -0
  453. package/esri-compat/wfs-layer.d.ts +64 -0
  454. package/esri-compat/wfs-layer.d.ts.map +1 -0
  455. package/esri-compat/wfs-layer.js +145 -0
  456. package/esri-compat/wms-layer.d.ts +76 -0
  457. package/esri-compat/wms-layer.d.ts.map +1 -0
  458. package/esri-compat/wms-layer.js +157 -0
  459. package/exploration/context.d.ts +25 -0
  460. package/exploration/context.d.ts.map +1 -0
  461. package/exploration/context.js +396 -0
  462. package/exploration/index.d.ts +27 -0
  463. package/exploration/index.d.ts.map +1 -0
  464. package/exploration/index.js +24 -0
  465. package/exploration/presets.d.ts +27 -0
  466. package/exploration/presets.d.ts.map +1 -0
  467. package/exploration/presets.js +114 -0
  468. package/exploration/reducer.d.ts +23 -0
  469. package/exploration/reducer.d.ts.map +1 -0
  470. package/exploration/reducer.js +332 -0
  471. package/exploration/selection.d.ts +25 -0
  472. package/exploration/selection.d.ts.map +1 -0
  473. package/exploration/selection.js +34 -0
  474. package/exploration/selectors.d.ts +56 -0
  475. package/exploration/selectors.d.ts.map +1 -0
  476. package/exploration/selectors.js +110 -0
  477. package/exploration/types.d.ts +294 -0
  478. package/exploration/types.d.ts.map +1 -0
  479. package/exploration/types.js +33 -0
  480. package/expr/expression.d.ts +457 -0
  481. package/expr/expression.d.ts.map +1 -0
  482. package/expr/expression.js +663 -0
  483. package/expr/index.d.ts +32 -0
  484. package/expr/index.d.ts.map +1 -0
  485. package/expr/index.js +30 -0
  486. package/filter-registry/index.d.ts +145 -0
  487. package/filter-registry/index.d.ts.map +1 -0
  488. package/filter-registry/index.js +531 -0
  489. package/gen/honua/v1/feature_service_pb.d.ts +918 -0
  490. package/gen/honua/v1/feature_service_pb.d.ts.map +1 -0
  491. package/gen/honua/v1/feature_service_pb.js +375 -0
  492. package/generated-app/errors.d.ts +41 -0
  493. package/generated-app/errors.d.ts.map +1 -0
  494. package/generated-app/errors.js +41 -0
  495. package/generated-app/index.d.ts +17 -0
  496. package/generated-app/index.d.ts.map +1 -0
  497. package/generated-app/index.js +12 -0
  498. package/generated-app/manifest.d.ts +183 -0
  499. package/generated-app/manifest.d.ts.map +1 -0
  500. package/generated-app/manifest.js +14 -0
  501. package/generated-app/projection.d.ts +44 -0
  502. package/generated-app/projection.d.ts.map +1 -0
  503. package/generated-app/projection.js +234 -0
  504. package/generated-app/runtime.d.ts +215 -0
  505. package/generated-app/runtime.d.ts.map +1 -0
  506. package/generated-app/runtime.js +1196 -0
  507. package/geocoding/index.d.ts +106 -0
  508. package/geocoding/index.d.ts.map +1 -0
  509. package/geocoding/index.js +278 -0
  510. package/interactions/detail-model.d.ts +54 -0
  511. package/interactions/detail-model.d.ts.map +1 -0
  512. package/interactions/detail-model.js +105 -0
  513. package/interactions/exploration-bindings.d.ts +120 -0
  514. package/interactions/exploration-bindings.d.ts.map +1 -0
  515. package/interactions/exploration-bindings.js +218 -0
  516. package/interactions/feature-state.d.ts +144 -0
  517. package/interactions/feature-state.d.ts.map +1 -0
  518. package/interactions/feature-state.js +169 -0
  519. package/interactions/hit-test.d.ts +112 -0
  520. package/interactions/hit-test.d.ts.map +1 -0
  521. package/interactions/hit-test.js +291 -0
  522. package/interactions/index.d.ts +31 -0
  523. package/interactions/index.d.ts.map +1 -0
  524. package/interactions/index.js +24 -0
  525. package/interactions/share-state.d.ts +36 -0
  526. package/interactions/share-state.d.ts.map +1 -0
  527. package/interactions/share-state.js +123 -0
  528. package/map/feature-service-adapter.d.ts +138 -0
  529. package/map/feature-service-adapter.d.ts.map +1 -0
  530. package/map/feature-service-adapter.js +279 -0
  531. package/map/honua-map.d.ts +203 -0
  532. package/map/honua-map.d.ts.map +1 -0
  533. package/map/honua-map.js +347 -0
  534. package/map/index.d.ts +27 -0
  535. package/map/index.d.ts.map +1 -0
  536. package/map/index.js +22 -0
  537. package/map/maplibre-target.d.ts +103 -0
  538. package/map/maplibre-target.d.ts.map +1 -0
  539. package/map/maplibre-target.js +164 -0
  540. package/map/webmap-maplibre.d.ts +60 -0
  541. package/map/webmap-maplibre.d.ts.map +1 -0
  542. package/map/webmap-maplibre.js +212 -0
  543. package/operate/client.d.ts +94 -0
  544. package/operate/client.d.ts.map +1 -0
  545. package/operate/client.js +361 -0
  546. package/operate/index.d.ts +22 -0
  547. package/operate/index.d.ts.map +1 -0
  548. package/operate/index.js +19 -0
  549. package/operate/types.d.ts +397 -0
  550. package/operate/types.d.ts.map +1 -0
  551. package/operate/types.js +17 -0
  552. package/operator/client.d.ts +60 -0
  553. package/operator/client.d.ts.map +1 -0
  554. package/operator/client.js +20 -0
  555. package/operator/controllers/approval.d.ts +52 -0
  556. package/operator/controllers/approval.d.ts.map +1 -0
  557. package/operator/controllers/approval.js +123 -0
  558. package/operator/controllers/base.d.ts +27 -0
  559. package/operator/controllers/base.d.ts.map +1 -0
  560. package/operator/controllers/base.js +53 -0
  561. package/operator/controllers/builder-workspace.d.ts +55 -0
  562. package/operator/controllers/builder-workspace.d.ts.map +1 -0
  563. package/operator/controllers/builder-workspace.js +108 -0
  564. package/operator/controllers/chat.d.ts +61 -0
  565. package/operator/controllers/chat.d.ts.map +1 -0
  566. package/operator/controllers/chat.js +154 -0
  567. package/operator/controllers/clarification.d.ts +52 -0
  568. package/operator/controllers/clarification.d.ts.map +1 -0
  569. package/operator/controllers/clarification.js +121 -0
  570. package/operator/controllers/execution.d.ts +60 -0
  571. package/operator/controllers/execution.d.ts.map +1 -0
  572. package/operator/controllers/execution.js +286 -0
  573. package/operator/controllers/index.d.ts +23 -0
  574. package/operator/controllers/index.d.ts.map +1 -0
  575. package/operator/controllers/index.js +15 -0
  576. package/operator/controllers/map-workspace.d.ts +85 -0
  577. package/operator/controllers/map-workspace.d.ts.map +1 -0
  578. package/operator/controllers/map-workspace.js +296 -0
  579. package/operator/controllers/plan-review.d.ts +66 -0
  580. package/operator/controllers/plan-review.d.ts.map +1 -0
  581. package/operator/controllers/plan-review.js +124 -0
  582. package/operator/errors.d.ts +62 -0
  583. package/operator/errors.d.ts.map +1 -0
  584. package/operator/errors.js +75 -0
  585. package/operator/i18n/index.d.ts +10 -0
  586. package/operator/i18n/index.d.ts.map +1 -0
  587. package/operator/i18n/index.js +8 -0
  588. package/operator/i18n/messages.d.ts +19 -0
  589. package/operator/i18n/messages.d.ts.map +1 -0
  590. package/operator/i18n/messages.js +54 -0
  591. package/operator/index.d.ts +19 -0
  592. package/operator/index.d.ts.map +1 -0
  593. package/operator/index.js +15 -0
  594. package/operator/telemetry.d.ts +26 -0
  595. package/operator/telemetry.d.ts.map +1 -0
  596. package/operator/telemetry.js +9 -0
  597. package/operator/theming/index.d.ts +12 -0
  598. package/operator/theming/index.d.ts.map +1 -0
  599. package/operator/theming/index.js +9 -0
  600. package/operator/theming/provider.d.ts +27 -0
  601. package/operator/theming/provider.d.ts.map +1 -0
  602. package/operator/theming/provider.js +26 -0
  603. package/operator/theming/tokens.d.ts +28 -0
  604. package/operator/theming/tokens.d.ts.map +1 -0
  605. package/operator/theming/tokens.js +65 -0
  606. package/operator/workspace/events.d.ts +70 -0
  607. package/operator/workspace/events.d.ts.map +1 -0
  608. package/operator/workspace/events.js +9 -0
  609. package/operator/workspace/index.d.ts +12 -0
  610. package/operator/workspace/index.d.ts.map +1 -0
  611. package/operator/workspace/index.js +8 -0
  612. package/operator/workspace/types.d.ts +178 -0
  613. package/operator/workspace/types.d.ts.map +1 -0
  614. package/operator/workspace/types.js +47 -0
  615. package/operator/workspace/workspace.d.ts +58 -0
  616. package/operator/workspace/workspace.d.ts.map +1 -0
  617. package/operator/workspace/workspace.js +339 -0
  618. package/package.json +105 -0
  619. package/realtime/exploration.d.ts +16 -0
  620. package/realtime/exploration.d.ts.map +1 -0
  621. package/realtime/exploration.js +32 -0
  622. package/realtime/honua-server.d.ts +123 -0
  623. package/realtime/honua-server.d.ts.map +1 -0
  624. package/realtime/honua-server.js +188 -0
  625. package/realtime/index.d.ts +20 -0
  626. package/realtime/index.d.ts.map +1 -0
  627. package/realtime/index.js +14 -0
  628. package/realtime/projections.d.ts +30 -0
  629. package/realtime/projections.d.ts.map +1 -0
  630. package/realtime/projections.js +51 -0
  631. package/realtime/reducer.d.ts +14 -0
  632. package/realtime/reducer.d.ts.map +1 -0
  633. package/realtime/reducer.js +351 -0
  634. package/realtime/sse.d.ts +23 -0
  635. package/realtime/sse.d.ts.map +1 -0
  636. package/realtime/sse.js +143 -0
  637. package/realtime/store.d.ts +18 -0
  638. package/realtime/store.d.ts.map +1 -0
  639. package/realtime/store.js +63 -0
  640. package/realtime/types.d.ts +190 -0
  641. package/realtime/types.d.ts.map +1 -0
  642. package/realtime/types.js +10 -0
  643. package/replica-sync/client.d.ts +32 -0
  644. package/replica-sync/client.d.ts.map +1 -0
  645. package/replica-sync/client.js +52 -0
  646. package/replica-sync/errors.d.ts +22 -0
  647. package/replica-sync/errors.d.ts.map +1 -0
  648. package/replica-sync/errors.js +29 -0
  649. package/replica-sync/fixture.d.ts +40 -0
  650. package/replica-sync/fixture.d.ts.map +1 -0
  651. package/replica-sync/fixture.js +364 -0
  652. package/replica-sync/index.d.ts +22 -0
  653. package/replica-sync/index.d.ts.map +1 -0
  654. package/replica-sync/index.js +17 -0
  655. package/replica-sync/types.d.ts +270 -0
  656. package/replica-sync/types.d.ts.map +1 -0
  657. package/replica-sync/types.js +13 -0
  658. package/runtime/diff.d.ts +31 -0
  659. package/runtime/diff.d.ts.map +1 -0
  660. package/runtime/diff.js +143 -0
  661. package/runtime/errors.d.ts +40 -0
  662. package/runtime/errors.d.ts.map +1 -0
  663. package/runtime/errors.js +35 -0
  664. package/runtime/index.d.ts +59 -0
  665. package/runtime/index.d.ts.map +1 -0
  666. package/runtime/index.js +40 -0
  667. package/runtime/legend.d.ts +23 -0
  668. package/runtime/legend.d.ts.map +1 -0
  669. package/runtime/legend.js +38 -0
  670. package/runtime/load-package.d.ts +125 -0
  671. package/runtime/load-package.d.ts.map +1 -0
  672. package/runtime/load-package.js +272 -0
  673. package/runtime/map-package-fetch.d.ts +107 -0
  674. package/runtime/map-package-fetch.d.ts.map +1 -0
  675. package/runtime/map-package-fetch.js +336 -0
  676. package/runtime/map-package-realtime.d.ts +169 -0
  677. package/runtime/map-package-realtime.d.ts.map +1 -0
  678. package/runtime/map-package-realtime.js +350 -0
  679. package/runtime/map-package-validation.d.ts +30 -0
  680. package/runtime/map-package-validation.d.ts.map +1 -0
  681. package/runtime/map-package-validation.js +257 -0
  682. package/runtime/map-package-watch.d.ts +78 -0
  683. package/runtime/map-package-watch.d.ts.map +1 -0
  684. package/runtime/map-package-watch.js +695 -0
  685. package/runtime/map-package.d.ts +167 -0
  686. package/runtime/map-package.d.ts.map +1 -0
  687. package/runtime/map-package.js +15 -0
  688. package/runtime/ogc-styles.d.ts +110 -0
  689. package/runtime/ogc-styles.d.ts.map +1 -0
  690. package/runtime/ogc-styles.js +195 -0
  691. package/runtime/pmtiles-protocol.d.ts +77 -0
  692. package/runtime/pmtiles-protocol.d.ts.map +1 -0
  693. package/runtime/pmtiles-protocol.js +120 -0
  694. package/runtime/popups.d.ts +62 -0
  695. package/runtime/popups.d.ts.map +1 -0
  696. package/runtime/popups.js +95 -0
  697. package/runtime/query-tiles.d.ts +217 -0
  698. package/runtime/query-tiles.d.ts.map +1 -0
  699. package/runtime/query-tiles.js +801 -0
  700. package/runtime/runtime.d.ts +243 -0
  701. package/runtime/runtime.d.ts.map +1 -0
  702. package/runtime/runtime.js +1147 -0
  703. package/runtime/source-bridge.d.ts +99 -0
  704. package/runtime/source-bridge.d.ts.map +1 -0
  705. package/runtime/source-bridge.js +428 -0
  706. package/runtime/style-compose.d.ts +46 -0
  707. package/runtime/style-compose.d.ts.map +1 -0
  708. package/runtime/style-compose.js +144 -0
  709. package/runtime/style-interactions.d.ts +141 -0
  710. package/runtime/style-interactions.d.ts.map +1 -0
  711. package/runtime/style-interactions.js +574 -0
  712. package/runtime/style-spec-validation.d.ts +23 -0
  713. package/runtime/style-spec-validation.d.ts.map +1 -0
  714. package/runtime/style-spec-validation.js +357 -0
  715. package/scene-workspace/analysis-widgets.d.ts +334 -0
  716. package/scene-workspace/analysis-widgets.d.ts.map +1 -0
  717. package/scene-workspace/analysis-widgets.js +424 -0
  718. package/scene-workspace/cesium-adapter.d.ts +438 -0
  719. package/scene-workspace/cesium-adapter.d.ts.map +1 -0
  720. package/scene-workspace/cesium-adapter.js +493 -0
  721. package/scene-workspace/index.d.ts +21 -0
  722. package/scene-workspace/index.d.ts.map +1 -0
  723. package/scene-workspace/index.js +14 -0
  724. package/scene-workspace/primitives.d.ts +162 -0
  725. package/scene-workspace/primitives.d.ts.map +1 -0
  726. package/scene-workspace/primitives.js +255 -0
  727. package/scene-workspace/scene-discovery.d.ts +196 -0
  728. package/scene-workspace/scene-discovery.d.ts.map +1 -0
  729. package/scene-workspace/scene-discovery.js +228 -0
  730. package/scene-workspace/scene-view.d.ts +209 -0
  731. package/scene-workspace/scene-view.d.ts.map +1 -0
  732. package/scene-workspace/scene-view.js +267 -0
  733. package/scene-workspace/types.d.ts +229 -0
  734. package/scene-workspace/types.d.ts.map +1 -0
  735. package/scene-workspace/types.js +23 -0
  736. package/scene-workspace/workspace.d.ts +13 -0
  737. package/scene-workspace/workspace.d.ts.map +1 -0
  738. package/scene-workspace/workspace.js +391 -0
  739. package/share/denial.d.ts +78 -0
  740. package/share/denial.d.ts.map +1 -0
  741. package/share/denial.js +61 -0
  742. package/share/embed-token.d.ts +71 -0
  743. package/share/embed-token.d.ts.map +1 -0
  744. package/share/embed-token.js +99 -0
  745. package/share/index.d.ts +35 -0
  746. package/share/index.d.ts.map +1 -0
  747. package/share/index.js +30 -0
  748. package/share/open-data.d.ts +114 -0
  749. package/share/open-data.d.ts.map +1 -0
  750. package/share/open-data.js +81 -0
  751. package/share/types.d.ts +163 -0
  752. package/share/types.d.ts.map +1 -0
  753. package/share/types.js +17 -0
  754. package/studio/capability-manifest.d.ts +285 -0
  755. package/studio/capability-manifest.d.ts.map +1 -0
  756. package/studio/capability-manifest.js +59 -0
  757. package/studio/chart-spec.d.ts +85 -0
  758. package/studio/chart-spec.d.ts.map +1 -0
  759. package/studio/chart-spec.js +106 -0
  760. package/studio/index.d.ts +34 -0
  761. package/studio/index.d.ts.map +1 -0
  762. package/studio/index.js +27 -0
  763. package/studio/provenance.d.ts +131 -0
  764. package/studio/provenance.d.ts.map +1 -0
  765. package/studio/provenance.js +39 -0
  766. package/studio/publish.d.ts +64 -0
  767. package/studio/publish.d.ts.map +1 -0
  768. package/studio/publish.js +13 -0
  769. package/studio/types.d.ts +278 -0
  770. package/studio/types.d.ts.map +1 -0
  771. package/studio/types.js +71 -0
  772. package/studio/validate.d.ts +45 -0
  773. package/studio/validate.d.ts.map +1 -0
  774. package/studio/validate.js +255 -0
  775. package/studio/validation.d.ts +112 -0
  776. package/studio/validation.d.ts.map +1 -0
  777. package/studio/validation.js +42 -0
  778. package/style/factory.d.ts +30 -0
  779. package/style/factory.d.ts.map +1 -0
  780. package/style/factory.js +61 -0
  781. package/style/index.d.ts +25 -0
  782. package/style/index.d.ts.map +1 -0
  783. package/style/index.js +24 -0
  784. package/style/specification.d.ts +203 -0
  785. package/style/specification.d.ts.map +1 -0
  786. package/style/specification.js +178 -0
  787. package/style/wms-wmts-resolvers.d.ts +38 -0
  788. package/style/wms-wmts-resolvers.d.ts.map +1 -0
  789. package/style/wms-wmts-resolvers.js +92 -0
  790. package/web-components/controller.d.ts +39 -0
  791. package/web-components/controller.d.ts.map +1 -0
  792. package/web-components/controller.js +640 -0
  793. package/web-components/elements.d.ts +210 -0
  794. package/web-components/elements.d.ts.map +1 -0
  795. package/web-components/elements.js +1651 -0
  796. package/web-components/index.d.ts +24 -0
  797. package/web-components/index.d.ts.map +1 -0
  798. package/web-components/index.js +22 -0
  799. package/web-components/maplibre-renderer.d.ts +22 -0
  800. package/web-components/maplibre-renderer.d.ts.map +1 -0
  801. package/web-components/maplibre-renderer.js +474 -0
  802. package/web-components/types.d.ts +397 -0
  803. package/web-components/types.d.ts.map +1 -0
  804. package/web-components/types.js +1 -0
  805. package/webmap/contract.d.ts +28 -0
  806. package/webmap/contract.d.ts.map +1 -0
  807. package/webmap/contract.js +130 -0
  808. package/webmap/convert-basemap.d.ts +17 -0
  809. package/webmap/convert-basemap.d.ts.map +1 -0
  810. package/webmap/convert-basemap.js +78 -0
  811. package/webmap/convert-extent.d.ts +17 -0
  812. package/webmap/convert-extent.d.ts.map +1 -0
  813. package/webmap/convert-extent.js +114 -0
  814. package/webmap/convert-label.d.ts +13 -0
  815. package/webmap/convert-label.d.ts.map +1 -0
  816. package/webmap/convert-label.js +125 -0
  817. package/webmap/convert-layer.d.ts +22 -0
  818. package/webmap/convert-layer.d.ts.map +1 -0
  819. package/webmap/convert-layer.js +181 -0
  820. package/webmap/convert-popup.d.ts +34 -0
  821. package/webmap/convert-popup.d.ts.map +1 -0
  822. package/webmap/convert-popup.js +68 -0
  823. package/webmap/convert-renderer.d.ts +17 -0
  824. package/webmap/convert-renderer.d.ts.map +1 -0
  825. package/webmap/convert-renderer.js +161 -0
  826. package/webmap/convert-symbol.d.ts +17 -0
  827. package/webmap/convert-symbol.d.ts.map +1 -0
  828. package/webmap/convert-symbol.js +122 -0
  829. package/webmap/index.d.ts +44 -0
  830. package/webmap/index.d.ts.map +1 -0
  831. package/webmap/index.js +33 -0
  832. package/webmap/parse.d.ts +25 -0
  833. package/webmap/parse.d.ts.map +1 -0
  834. package/webmap/parse.js +83 -0
  835. package/webmap/types.d.ts +264 -0
  836. package/webmap/types.d.ts.map +1 -0
  837. package/webmap/types.js +13 -0
  838. package/webmap/warnings.d.ts +30 -0
  839. package/webmap/warnings.d.ts.map +1 -0
  840. package/webmap/warnings.js +37 -0
package/core/client.js ADDED
@@ -0,0 +1,1716 @@
1
+ import { HONUA_DEFAULT_METADATA_STALE_IF_ERROR_MS, createHonuaCacheState, honuaCacheValidatorFromHeaders, honuaMetadataRequestHeaders, isHonuaCacheEntryFresh, normalizeHonuaMetadataRequestOptions, withHonuaCacheState, withoutHonuaCacheState, } from "./cache-state.js";
2
+ import { HONUA_MINIMUM_SUPPORTED_SERVER_VERSION, MINIMUM_SUPPORTED_SERVER_RELEASE_CHANNEL, describeCompatibilityError, evaluateCompatibility, parseCompatibilityEnvelope, } from "./compatibility.js";
3
+ import { HonuaHttpError, HonuaNetworkError, HonuaTimeoutError } from "./errors.js";
4
+ import { applyEdits, exportMap, findMap, getFeatureServiceMetadata, getLayerMetadata, getMapLayerMetadata, getMapLegend, getMapServiceMetadata, identifyMap, listServices, queryFeaturesRest, queryMapLayer, queryMapRelatedRecords, queryRelatedRecords, } from "./geoservices.js";
5
+ import { HonuaOdataEntitySet } from "./odata.js";
6
+ import { honuaFacadeFeaturesLayout, resolveOgcEndpointLayout } from "./ogc-endpoint-layout.js";
7
+ import { createOgcItem, deleteOgcItem, getOgcCollection, getOgcFeaturesConformance, getOgcFeaturesLanding, getOgcItem, getOgcQueryables, listOgcCollections, listOgcItems, patchOgcItem, replaceOgcItem, } from "./ogc-features.js";
8
+ import { HonuaOgcMaps, getOgcMapImage, getOgcMapsConformance, getOgcMapsLanding } from "./ogc-maps.js";
9
+ import { HonuaOgcProcesses, cancelOgcProcessJob, executeOgcProcess, getOgcProcess, getOgcProcessJob, getOgcProcessJobResults, getOgcProcessesConformance, getOgcProcessesLanding, listOgcProcesses, } from "./ogc-processes.js";
10
+ import { HonuaOgcRecords, fetchOgcRecordRaw, fetchOgcRecordsRaw, getOgcRecord, getOgcRecordCollection, getOgcRecordsConformance, getOgcRecordsLanding, listOgcRecordCollections, searchOgcRecords, } from "./ogc-records.js";
11
+ import { HonuaOgcTiles, fetchOgcTile, getOgcCollectionTileset, getOgcTileMatrixSet, getOgcTilesConformance, getOgcTilesLanding, listOgcCollectionTilesets, listOgcTileMatrixSets, } from "./ogc-tiles.js";
12
+ import { stripQuery, trimTrailingSlashes } from "./path-utils.js";
13
+ import { decodePbfQueryResponse, isPbfResponse } from "./pbf-decoder.js";
14
+ import { createGeoServicesGpAdapter, createGeospatialGrpcProcessAdapter, createHonuaProcessRunner, createOgcProcessesAdapter, } from "./process-runner.js";
15
+ import { DEFAULT_RETRY_METHODS, createTimeoutSignal, normalizeNetworkError, normalizeRetryOptions, normalizeTimeoutMs, resolveGrpcRetryDelayMs, resolveRetryDelayMs, shouldRetryGrpcCall, shouldRetryRequest, sleep, toHttpError, } from "./request-pipeline.js";
16
+ import { HonuaStacSearch, getStacCollection, getStacItem, getStacLanding, listStacCollections, searchStac, } from "./stac.js";
17
+ import { HonuaFeatureLayer, HonuaGeometryService, HonuaGeoprocessingService, HonuaImageService, HonuaMapLayer, HonuaMapService, HonuaOgcFeatures, HonuaService, } from "./surfaces.js";
18
+ import { HonuaWfs } from "./wfs.js";
19
+ import { mergeHeaders } from "./wire-shared.js";
20
+ import { HonuaWms, getWmsCapabilities, getWmsFeatureInfo, getWmsLegend, getWmsMap } from "./wms.js";
21
+ import { HonuaWmts, fetchWmtsTile, getWmtsCapabilities, getWmtsFeatureInfo } from "./wmts.js";
22
+ // Re-exported so the long-standing `@honua/sdk-js` public export path
23
+ // (`export { HONUA_MINIMUM_SUPPORTED_SERVER_VERSION } from "./core/client.js"`)
24
+ // is preserved now that the constant lives in the compatibility module.
25
+ export { HONUA_MINIMUM_SUPPORTED_SERVER_VERSION } from "./compatibility.js";
26
+ function normalizeBaseUrl(baseUrl) {
27
+ return trimTrailingSlashes(baseUrl);
28
+ }
29
+ function normalizePath(path) {
30
+ if (path.startsWith("http://") || path.startsWith("https://")) {
31
+ return path;
32
+ }
33
+ return path.startsWith("/") ? path : `/${path}`;
34
+ }
35
+ function isAbsoluteHttpUrl(value) {
36
+ return value.startsWith("http://") || value.startsWith("https://");
37
+ }
38
+ function resolveRequestUrl(baseUrl, path) {
39
+ if (isAbsoluteHttpUrl(path)) {
40
+ if (!isAbsoluteHttpUrl(baseUrl)) {
41
+ throw new Error("Absolute request URLs are not allowed when baseUrl is relative.");
42
+ }
43
+ const baseOrigin = new URL(baseUrl).origin;
44
+ const requestUrl = new URL(path);
45
+ if (requestUrl.origin !== baseOrigin) {
46
+ throw new Error(`Cross-origin request URL is not allowed: ${path}`);
47
+ }
48
+ return requestUrl.toString();
49
+ }
50
+ return `${baseUrl}${path}`;
51
+ }
52
+ /**
53
+ * The maximum number of HTTP redirects {@link HonuaClient.fetchWithSafeRedirects}
54
+ * will follow before giving up. Mirrors the conventional browser/undici limit of 20.
55
+ */
56
+ const MAX_SAFE_REDIRECTS = 20;
57
+ /**
58
+ * HTTP status codes that represent a redirect carrying a `Location` header.
59
+ */
60
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
61
+ /**
62
+ * Resolve a redirect `Location` (which may be relative) against the URL that
63
+ * produced the redirect and assert it stays on the configured base origin.
64
+ *
65
+ * The SDK attaches the API key as a custom `X-API-Key` header. The Fetch/undici
66
+ * runtime only strips `Authorization`/`Cookie`/`Host` on a cross-origin redirect,
67
+ * so custom auth headers like `X-API-Key` would otherwise be replayed to an
68
+ * attacker-controlled `Location` host. To prevent that credential disclosure we
69
+ * never auto-follow redirects; we re-run the same origin guard used at request
70
+ * construction and refuse to follow any redirect that leaves the base origin.
71
+ *
72
+ * @throws if the target origin differs from the base origin, or if the
73
+ * `Location` header is missing/unparsable.
74
+ */
75
+ function resolveRedirectUrl(baseUrl, fromUrl, location) {
76
+ if (!location) {
77
+ throw new Error("Redirect response is missing a Location header.");
78
+ }
79
+ let target;
80
+ try {
81
+ target = new URL(location, fromUrl);
82
+ }
83
+ catch {
84
+ throw new Error(`Redirect response has an invalid Location header: ${location}`);
85
+ }
86
+ // Re-run the base-origin guard against the redirect target so the API key is
87
+ // never forwarded off the configured origin.
88
+ return resolveRequestUrl(baseUrl, target.toString());
89
+ }
90
+ function normalizeInterceptorRequestUrl(baseUrl, url) {
91
+ if (isAbsoluteHttpUrl(url)) {
92
+ return resolveRequestUrl(baseUrl, url);
93
+ }
94
+ if (!isAbsoluteHttpUrl(baseUrl)) {
95
+ return url;
96
+ }
97
+ return resolveRequestUrl(baseUrl, normalizePath(url));
98
+ }
99
+ const DEFAULT_AUTH_REFRESH_SKEW_MS = 60_000;
100
+ const DEFAULT_METADATA_CACHE_MAX_ENTRIES = 256;
101
+ /**
102
+ * The main Honua HTTP/gRPC-Web client.
103
+ *
104
+ * `HonuaClient` is the protocol-aware entry point into the Honua server. It speaks
105
+ * GeoServices (FeatureServer, MapServer, ImageServer, GeometryServer, GPServer),
106
+ * OGC API Features / Tiles / Maps / Processes, STAC, WMS, WMTS, WFS 2.0, and OData v4,
107
+ * with one consistent request/response shape, capability negotiation, optional retries,
108
+ * pluggable auth, and a small in-process metadata cache.
109
+ *
110
+ * For cross-protocol code that does not need to know the underlying service shape,
111
+ * prefer the protocol-neutral {@link createDataset} contract from `@honua/sdk-js/contract`
112
+ * — it wraps this client and exposes a single `Source.query(...)` surface that throws
113
+ * {@link HonuaCapabilityNotSupportedError} when a protocol cannot satisfy the request.
114
+ *
115
+ * @example Basic usage
116
+ * ```ts
117
+ * import { HonuaClient } from "@honua/sdk-js/honua";
118
+ *
119
+ * const client = new HonuaClient({
120
+ * baseUrl: "https://your-honua-server.example",
121
+ * apiKey: process.env.HONUA_API_KEY,
122
+ * });
123
+ *
124
+ * const { supported, reasons } = await client.checkCompatibility();
125
+ * if (!supported) {
126
+ * throw new Error(`Unsupported Honua server: ${reasons.join("; ")}`);
127
+ * }
128
+ *
129
+ * const result = await client.queryFeatures({
130
+ * serviceId: "natural-earth",
131
+ * layerId: 0,
132
+ * where: "1=1",
133
+ * outFields: ["*"],
134
+ * returnGeometry: true,
135
+ * resultRecordCount: 25,
136
+ * });
137
+ *
138
+ * console.log(`Loaded ${result.features?.length ?? 0} features`);
139
+ * ```
140
+ *
141
+ * @example Per-service fluent wrappers
142
+ * ```ts
143
+ * const parcels = client.featureLayer<{ NAME: string }>("parcels", 0);
144
+ * const items = await client.ogcFeatures();
145
+ * const wms = client.wms("usgs-imagery");
146
+ * ```
147
+ *
148
+ * @public
149
+ */
150
+ export class HonuaClient {
151
+ /** The minimum Honua server version this SDK is contractually tested against. */
152
+ static minimumSupportedServerVersion = HONUA_MINIMUM_SUPPORTED_SERVER_VERSION;
153
+ static minimumSupportedServerReleaseChannel = MINIMUM_SUPPORTED_SERVER_RELEASE_CHANNEL;
154
+ baseUrl;
155
+ fetchFn;
156
+ defaultHeaders;
157
+ authProvider;
158
+ authRefreshSkewMs;
159
+ interceptors;
160
+ timeoutMs;
161
+ retryOptions;
162
+ preferBinary;
163
+ transport;
164
+ /**
165
+ * Low-level transport handed to the per-protocol wire modules. Binds the
166
+ * client's private request primitives so each protocol family builds its own
167
+ * URLs/params/parsing without reaching into the client.
168
+ */
169
+ protocolTransport;
170
+ serverCompatibilityCache;
171
+ authCredentialsCache;
172
+ authRefreshPromise;
173
+ connectClient;
174
+ metadataCache = new Map();
175
+ ogcLayoutCache = new Map();
176
+ /**
177
+ * Create a new `HonuaClient`.
178
+ *
179
+ * @param options - Connection, auth, transport, retry, and interceptor configuration.
180
+ * See {@link HonuaClientOptions} for every field and `@example` blocks for common shapes.
181
+ *
182
+ * @example Minimal
183
+ * ```ts
184
+ * const client = new HonuaClient({ baseUrl: "https://your-honua-server.example" });
185
+ * ```
186
+ *
187
+ * @example With API key + retries + timeout
188
+ * ```ts
189
+ * const client = new HonuaClient({
190
+ * baseUrl: "https://your-honua-server.example",
191
+ * apiKey: process.env.HONUA_API_KEY,
192
+ * retry: { maxRetries: 3 },
193
+ * timeoutMs: 30_000,
194
+ * });
195
+ * ```
196
+ */
197
+ constructor(options) {
198
+ this.baseUrl = normalizeBaseUrl(options.baseUrl);
199
+ // Bind to `globalThis` at assignment: the default browser `fetch` is an
200
+ // unbound `window.fetch`, and invoking it as `this.fetchFn(...)` rebinds
201
+ // its receiver to the client instance, which browsers reject with
202
+ // "TypeError: Illegal invocation". Binding is a no-op for Node's undici
203
+ // fetch and for caller-supplied wrappers (arrow/bound functions ignore it).
204
+ this.fetchFn = (options.fetchFn ?? fetch).bind(globalThis);
205
+ const headers = {};
206
+ if (options.apiKey) {
207
+ headers["X-API-Key"] = options.apiKey;
208
+ }
209
+ if (options.bearerToken) {
210
+ headers.Authorization = `Bearer ${options.bearerToken}`;
211
+ }
212
+ this.defaultHeaders = headers;
213
+ this.authProvider = normalizeAuthProvider(options.auth);
214
+ this.authRefreshSkewMs = normalizeAuthRefreshSkewMs(options.authRefreshSkewMs);
215
+ this.interceptors = options.interceptors ?? [];
216
+ this.timeoutMs = normalizeTimeoutMs(options.timeoutMs);
217
+ this.retryOptions = normalizeRetryOptions(options.retry);
218
+ this.preferBinary = options.preferBinary === true;
219
+ this.transport = options.transport ?? "rest";
220
+ this.protocolTransport = {
221
+ baseUrl: this.baseUrl,
222
+ requestJson: (method, path, init, signal) => this.requestJson(method, path, init, signal),
223
+ requestText: (method, path, requestTextOptions) => this.requestText(method, path, requestTextOptions),
224
+ requestBytes: (method, path, accept, init, signal) => this.requestBytes(method, path, accept, init, signal),
225
+ requestCachedMetadataJson: (cacheKey, path, metadataOptions) => this.requestCachedMetadataJson(cacheKey, path, metadataOptions),
226
+ pipelineFetch: (method, path, init, callerSignal, pipelineOptions) => this.pipelineFetch(method, path, init, callerSignal, pipelineOptions),
227
+ requestBinaryWithJsonFallback: (method, path, params, signal) => this.requestBinaryWithJsonFallback(method, path, params, signal),
228
+ };
229
+ if (this.transport === "grpc-web") {
230
+ this.initConnectClient();
231
+ }
232
+ }
233
+ /**
234
+ * Connect interceptor that injects the same credentials the REST pipeline
235
+ * uses (`apiKey`/`bearerToken` from {@link defaultHeaders} plus any provider
236
+ * credentials resolved via {@link resolveAuthHeaders}) onto every gRPC-web
237
+ * call. Without it the advertised `transport: "grpc-web"` path would send
238
+ * every RPC unauthenticated.
239
+ */
240
+ buildConnectAuthInterceptor() {
241
+ return (next) => async (req) => {
242
+ const headers = await this.composeHeaders();
243
+ for (const [key, value] of Object.entries(headers)) {
244
+ req.header.set(key, value);
245
+ }
246
+ return next(req);
247
+ };
248
+ }
249
+ /**
250
+ * Connect interceptor that applies the SDK's configured `retry` policy to
251
+ * gRPC-web calls, mirroring the REST request pipeline. It retries only
252
+ * replay-safe **unary** calls (server-streaming responses cannot be safely
253
+ * replayed mid-iteration, the gRPC analog of the REST
254
+ * {@link DEFAULT_RETRY_METHODS} idempotency gate) on the transient
255
+ * {@link shouldRetryGrpcCall} status codes, backing off with the shared
256
+ * exponential-with-jitter math (honoring any `retry-after` metadata) and
257
+ * stopping immediately once the call's abort signal fires (caller abort or the
258
+ * `timeoutMs` deadline). It wraps the auth interceptor so each attempt
259
+ * re-resolves fresh credentials.
260
+ */
261
+ buildConnectRetryInterceptor() {
262
+ return (next) => async (req) => {
263
+ // Only retry replay-safe unary calls; mirror REST idempotency scoping.
264
+ if (req.stream || !this.retryOptions) {
265
+ return next(req);
266
+ }
267
+ const retryOptions = this.retryOptions;
268
+ for (let attempt = 0;; attempt += 1) {
269
+ try {
270
+ return await next(req);
271
+ }
272
+ catch (error) {
273
+ const aborted = req.signal?.aborted === true;
274
+ if (!shouldRetryGrpcCall(retryOptions, attempt, error, aborted)) {
275
+ throw error;
276
+ }
277
+ await sleep(resolveGrpcRetryDelayMs(retryOptions, attempt, error), req.signal);
278
+ }
279
+ }
280
+ };
281
+ }
282
+ /**
283
+ * Shared gRPC-web transport options. The auth interceptor mirrors the REST
284
+ * credential pipeline, the retry interceptor (when `retry` is configured)
285
+ * applies the same retry/backoff policy as REST, and `defaultTimeoutMs`
286
+ * honors the documented `timeoutMs` contract on every RPC (per-call abort
287
+ * signals are threaded by the individual RPC methods).
288
+ */
289
+ connectTransportOptions() {
290
+ // Order matters: the retry interceptor must wrap the auth interceptor so
291
+ // every replayed attempt re-runs auth and re-resolves credential headers.
292
+ const interceptors = [this.buildConnectAuthInterceptor()];
293
+ if (this.retryOptions) {
294
+ interceptors.unshift(this.buildConnectRetryInterceptor());
295
+ }
296
+ return {
297
+ baseUrl: this.baseUrl,
298
+ fetch: this.fetchFn,
299
+ interceptors,
300
+ ...(this.timeoutMs !== undefined ? { defaultTimeoutMs: this.timeoutMs } : {}),
301
+ };
302
+ }
303
+ initConnectClient() {
304
+ // Dynamic imports are used to avoid bundling Connect dependencies
305
+ // when only the REST transport is used. The imports are resolved
306
+ // at module level since they are static ESM imports.
307
+ import("@connectrpc/connect").then(({ createClient }) => import("@connectrpc/connect-web").then(({ createGrpcWebTransport }) => import("../gen/honua/v1/feature_service_pb.js").then(({ FeatureService }) => {
308
+ const transport = createGrpcWebTransport(this.connectTransportOptions());
309
+ this.connectClient = createClient(FeatureService, transport);
310
+ })));
311
+ }
312
+ async ensureConnectClient() {
313
+ if (this.connectClient) {
314
+ return this.connectClient;
315
+ }
316
+ // If initConnectClient hasn't resolved yet, wait for it
317
+ const { createClient } = await import("@connectrpc/connect");
318
+ const { createGrpcWebTransport } = await import("@connectrpc/connect-web");
319
+ const { FeatureService } = await import("../gen/honua/v1/feature_service_pb.js");
320
+ const transport = createGrpcWebTransport(this.connectTransportOptions());
321
+ this.connectClient = createClient(FeatureService, transport);
322
+ return this.connectClient;
323
+ }
324
+ /**
325
+ * Perform a fetch that never auto-follows a cross-origin redirect.
326
+ *
327
+ * Browsers/undici forward custom request headers (such as the SDK's
328
+ * `X-API-Key`) across redirects, stripping only `Authorization`/`Cookie`/`Host`
329
+ * cross-origin. To avoid leaking the API key to an attacker-supplied
330
+ * `Location` host, this issues every request with `redirect: "manual"` and
331
+ * only follows a redirect when its target origin still matches the configured
332
+ * base origin (re-running the {@link resolveRequestUrl} origin guard).
333
+ * Cross-origin redirects throw before the credentialed request is replayed.
334
+ */
335
+ async fetchWithSafeRedirects(url, init) {
336
+ let currentUrl = url;
337
+ let currentInit = init;
338
+ for (let redirects = 0;; redirects += 1) {
339
+ const response = await this.fetchFn(currentUrl, { ...currentInit, redirect: "manual" });
340
+ // `redirect: "manual"` surfaces redirects as status 3xx with a usable
341
+ // `Location` header (and, in fetch, an "opaqueredirect" type with status 0
342
+ // in some runtimes — treated as a same-origin-unverifiable redirect we
343
+ // must refuse to follow blindly).
344
+ if (response.type === "opaqueredirect") {
345
+ throw new HonuaNetworkError("Refusing to follow an opaque cross-origin redirect; the request's API key would be leaked to the redirect target.", undefined);
346
+ }
347
+ if (!REDIRECT_STATUSES.has(response.status)) {
348
+ return response;
349
+ }
350
+ if (redirects >= MAX_SAFE_REDIRECTS) {
351
+ throw new HonuaNetworkError(`Exceeded the maximum of ${MAX_SAFE_REDIRECTS} redirects.`, undefined);
352
+ }
353
+ // Re-validate the redirect target against the base origin. A cross-origin
354
+ // target throws here, so the API key is never replayed off-origin.
355
+ const location = response.headers.get("location");
356
+ const nextUrl = resolveRedirectUrl(this.baseUrl, currentUrl, location);
357
+ // Apply the standard Fetch redirect method/body rewriting so the followed
358
+ // (same-origin) request matches what the runtime would have done natively:
359
+ // 303 always becomes GET; 301/302 turn a non-GET/HEAD into GET. The body
360
+ // is dropped whenever the method changes to GET.
361
+ const method = (currentInit.method ?? "GET").toUpperCase();
362
+ const downgradeToGet = response.status === 303 ||
363
+ ((response.status === 301 || response.status === 302) && method !== "GET" && method !== "HEAD");
364
+ currentInit = downgradeToGet ? { ...currentInit, method: "GET", body: null } : currentInit;
365
+ currentUrl = nextUrl;
366
+ // Drain the redirect body so the underlying connection can be reused.
367
+ await response.body?.cancel().catch(() => undefined);
368
+ }
369
+ }
370
+ static async loadGrpcAdapter() {
371
+ return import("./grpc-adapter.js");
372
+ }
373
+ get isGrpcWeb() {
374
+ return this.transport === "grpc-web";
375
+ }
376
+ /**
377
+ * Normalized base URL the client was constructed with (trailing slashes
378
+ * trimmed). Helpers that build absolute URLs without going through
379
+ * `request()` (e.g. tile URL generators) read this so they produce the
380
+ * same origin and base path the server actually serves from.
381
+ */
382
+ get serverBaseUrl() {
383
+ return this.baseUrl;
384
+ }
385
+ /**
386
+ * Force-refresh credentials from the configured auth provider. The SDK
387
+ * keeps the result in memory only; callers own durable and secure storage.
388
+ */
389
+ async refreshAuthCredentials(reason = "manual") {
390
+ const cached = await this.resolveAuthCredentials({
391
+ forceRefresh: true,
392
+ reason,
393
+ });
394
+ return cached?.credentials;
395
+ }
396
+ /**
397
+ * Resolve the auth headers the client would attach to an outgoing request
398
+ * right now, refreshing provider credentials first if they are expiring.
399
+ *
400
+ * Transports that build their own connection outside the REST/gRPC pipeline —
401
+ * notably realtime SSE streams, which must re-authenticate on every
402
+ * (re)connect so a refreshed token is picked up after a drop — call this per
403
+ * connect to obtain fresh credentials. Returns an empty object when no
404
+ * credentials are configured.
405
+ */
406
+ async getAuthHeaders() {
407
+ return this.composeHeaders();
408
+ }
409
+ /**
410
+ * Resolve just the current bearer/authorization token value (without the
411
+ * `Bearer ` scheme prefix when a plain bearer token is configured), or
412
+ * `undefined` if none. Convenience for realtime transports that must carry the
413
+ * token as a query parameter (native `EventSource` cannot set headers).
414
+ */
415
+ async getAuthToken() {
416
+ const headers = await this.composeHeaders();
417
+ const authorization = headers.Authorization ?? headers.authorization;
418
+ if (authorization) {
419
+ return authorization.startsWith("Bearer ") ? authorization.slice("Bearer ".length) : authorization;
420
+ }
421
+ return headers["X-API-Key"] ?? headers["x-api-key"];
422
+ }
423
+ /** Drop cached provider credentials without calling a revocation endpoint. */
424
+ clearAuthCredentials() {
425
+ this.authCredentialsCache = undefined;
426
+ }
427
+ /**
428
+ * Revoke the currently cached credentials through the provider, when it
429
+ * exposes a revocation hook, then clear the SDK's in-memory cache.
430
+ */
431
+ async revokeAuthCredentials(context = { reason: "manual" }) {
432
+ const cached = this.authCredentialsCache;
433
+ this.authCredentialsCache = undefined;
434
+ if (cached && this.authProvider?.revokeCredentials) {
435
+ await this.authProvider.revokeCredentials(cached.credentials, context);
436
+ }
437
+ }
438
+ /**
439
+ * Drive a paginated FeatureServer query as an async generator. Each yielded
440
+ * chunk is a `HonuaFeature[]` slice; iteration stops when the server stops
441
+ * advertising `exceededTransferLimit`. Lower-level than
442
+ * `dataset.source(...).queryAll()` but suitable for streaming pipelines that
443
+ * want backpressure between pages.
444
+ *
445
+ * @example
446
+ * ```ts
447
+ * for await (const page of client.queryFeaturesStream({ serviceId: "parcels", layerId: 0, where: "1=1" })) {
448
+ * process(page);
449
+ * }
450
+ * ```
451
+ */
452
+ async *queryFeaturesStream(request) {
453
+ const client = await this.ensureConnectClient();
454
+ const grpcAdapter = await HonuaClient.loadGrpcAdapter();
455
+ const protoRequest = grpcAdapter.toProtoQueryRequest(request);
456
+ yield* grpcAdapter.streamProtoPages(client.queryFeaturesStream(protoRequest, request.signal ? { signal: request.signal } : undefined));
457
+ }
458
+ service(serviceId) {
459
+ return new HonuaService({
460
+ client: this,
461
+ serviceId,
462
+ });
463
+ }
464
+ /**
465
+ * Construct a typed wrapper for a single FeatureServer layer.
466
+ *
467
+ * The returned {@link HonuaFeatureLayer} carries the same `serviceId` / `layerId`
468
+ * on every call so you can write `await layer.queryFeatures({ where: "..." })`
469
+ * without restating the address.
470
+ *
471
+ * @typeParam T - The attribute shape of features in this layer.
472
+ *
473
+ * @example
474
+ * ```ts
475
+ * const parcels = client.featureLayer<{ NAME: string; STATUS: string }>("parcels", 0);
476
+ * const { features } = await parcels.queryFeatures({ where: "STATUS = 'ACTIVE'" });
477
+ * ```
478
+ */
479
+ featureLayer(serviceId, layerId) {
480
+ return new HonuaFeatureLayer({
481
+ client: this,
482
+ serviceId,
483
+ layerId,
484
+ });
485
+ }
486
+ mapService(serviceId) {
487
+ return new HonuaMapService({
488
+ client: this,
489
+ serviceId,
490
+ });
491
+ }
492
+ mapLayer(serviceId, layerId) {
493
+ return new HonuaMapLayer({
494
+ client: this,
495
+ serviceId,
496
+ layerId,
497
+ });
498
+ }
499
+ /**
500
+ * Construct the OGC API Features client wrapper.
501
+ *
502
+ * Use this to walk collections (`landing()`, `conformance()`, `collections()`),
503
+ * read items (`items()`, `item()`), and apply edits (`create*` / `replace*` /
504
+ * `patch*` / `delete*`) against an OGC API Features endpoint exposed by the
505
+ * Honua server.
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * const features = client.ogcFeatures();
510
+ * const collections = await features.collections();
511
+ * const items = await features.items("parcels", { limit: 100 });
512
+ * ```
513
+ */
514
+ ogcFeatures() {
515
+ return new HonuaOgcFeatures({
516
+ client: this,
517
+ });
518
+ }
519
+ ogcTiles() {
520
+ return new HonuaOgcTiles({ client: this });
521
+ }
522
+ ogcMaps() {
523
+ return new HonuaOgcMaps({ client: this });
524
+ }
525
+ ogcRecords() {
526
+ return new HonuaOgcRecords({ client: this });
527
+ }
528
+ wms(serviceId) {
529
+ return new HonuaWms({ client: this, serviceId });
530
+ }
531
+ wmts(serviceId) {
532
+ return new HonuaWmts({ client: this, serviceId });
533
+ }
534
+ ogcProcesses() {
535
+ return new HonuaOgcProcesses({ client: this });
536
+ }
537
+ stac() {
538
+ return new HonuaStacSearch({ client: this });
539
+ }
540
+ imageService(serviceId) {
541
+ return new HonuaImageService({ client: this, serviceId });
542
+ }
543
+ geometryService() {
544
+ return new HonuaGeometryService({ client: this });
545
+ }
546
+ geoprocessing(serviceId, taskName) {
547
+ return new HonuaGeoprocessingService({ client: this, serviceId, taskName });
548
+ }
549
+ processRunner(adapter) {
550
+ return createHonuaProcessRunner(adapter);
551
+ }
552
+ ogcProcessRunner() {
553
+ return createHonuaProcessRunner(createOgcProcessesAdapter(this.ogcProcesses()));
554
+ }
555
+ geoprocessingRunner(serviceId, taskName) {
556
+ return createHonuaProcessRunner(createGeoServicesGpAdapter(this.geoprocessing(serviceId, taskName)));
557
+ }
558
+ geospatialGrpcProcessRunner(processClient) {
559
+ return createHonuaProcessRunner(createGeospatialGrpcProcessAdapter(processClient));
560
+ }
561
+ wfs(endpointUrl = "/wfs", options = {}) {
562
+ return new HonuaWfs({ client: this, endpointUrl, version: options.version });
563
+ }
564
+ odata(entitySet, options = {}) {
565
+ return new HonuaOdataEntitySet({ client: this, entitySet, basePath: options.basePath });
566
+ }
567
+ clearMetadataCache(options = {}) {
568
+ if (!options.keyPrefix) {
569
+ this.metadataCache.clear();
570
+ return;
571
+ }
572
+ const prefix = `metadata:${options.keyPrefix}`;
573
+ for (const key of this.metadataCache.keys()) {
574
+ if (key.startsWith(prefix)) {
575
+ this.metadataCache.delete(key);
576
+ }
577
+ }
578
+ }
579
+ async listServices(formatOrOptions = "json", options = {}) {
580
+ const format = typeof formatOrOptions === "string" ? formatOrOptions : "json";
581
+ const metadataOptions = typeof formatOrOptions === "string" ? options : formatOrOptions;
582
+ return listServices(this.protocolTransport, format, metadataOptions);
583
+ }
584
+ /**
585
+ * Fetch and parse the server's compatibility contract from `GET /api/v1/admin/capabilities`.
586
+ *
587
+ * The first call populates an in-process cache; subsequent calls return the cached value
588
+ * unless `options.refresh` is `true`. Use {@link HonuaClient.checkCompatibility} instead
589
+ * when you want a non-throwing pass/fail signal with a list of reasons.
590
+ *
591
+ * @throws {@link HonuaError} when the server response cannot be parsed into a valid
592
+ * compatibility envelope (missing `serverVersion`, `controlPlaneApi`, etc.).
593
+ *
594
+ * @example
595
+ * ```ts
596
+ * const contract = await client.getCompatibility();
597
+ * console.log(contract.serverVersion, contract.releaseChannel);
598
+ * console.log(contract.metadataSchemas);
599
+ * ```
600
+ */
601
+ async getCompatibility(options = {}) {
602
+ if (!options.refresh && this.serverCompatibilityCache) {
603
+ return this.serverCompatibilityCache;
604
+ }
605
+ const response = (await this.requestJson("GET", "/api/v1/admin/capabilities", undefined, options.signal));
606
+ const compatibility = parseCompatibilityEnvelope(response);
607
+ this.serverCompatibilityCache = compatibility;
608
+ return compatibility;
609
+ }
610
+ /**
611
+ * Probe the server's compatibility contract and return a structured pass/fail status.
612
+ *
613
+ * Unlike {@link HonuaClient.getCompatibility}, this method does not throw on transport
614
+ * or parse failures — those are reported as `supported: false` with a human-readable
615
+ * `reasons` entry. Use this at app startup to fail loudly before exercising admin or
616
+ * control-plane flows.
617
+ *
618
+ * @example
619
+ * ```ts
620
+ * const { supported, reasons } = await client.checkCompatibility();
621
+ * if (!supported) {
622
+ * throw new Error(`Unsupported Honua server: ${reasons.join("; ")}`);
623
+ * }
624
+ * ```
625
+ */
626
+ async checkCompatibility(options = {}) {
627
+ try {
628
+ const compatibility = await this.getCompatibility(options);
629
+ const reasons = evaluateCompatibility(compatibility);
630
+ return {
631
+ supported: reasons.length === 0,
632
+ minimumSupportedServerVersion: HonuaClient.minimumSupportedServerVersion,
633
+ compatibility,
634
+ reasons,
635
+ };
636
+ }
637
+ catch (error) {
638
+ return {
639
+ supported: false,
640
+ minimumSupportedServerVersion: HonuaClient.minimumSupportedServerVersion,
641
+ reasons: [describeCompatibilityError(error)],
642
+ };
643
+ }
644
+ }
645
+ /**
646
+ * Returns `true` if the server's `data.compatibility.features` map advertises the
647
+ * given coarse capability. Use this to gate experimental or admin-only workflows.
648
+ *
649
+ * @example
650
+ * ```ts
651
+ * if (await client.supportsFeature("manifestApply")) {
652
+ * // safe to call the manifest apply admin endpoint
653
+ * }
654
+ * ```
655
+ */
656
+ async supportsFeature(feature, options = {}) {
657
+ const compatibility = await this.getCompatibility(options);
658
+ return compatibility.features[feature];
659
+ }
660
+ /**
661
+ * Scan a supported migration source through the admin import scanner.
662
+ *
663
+ * A successful HTTP response means the server returned a deterministic
664
+ * inventory artifact; callers still need to inspect
665
+ * `scanCompleteness.status`, which can be `"failed"` on `200 OK`.
666
+ */
667
+ async scanMigrationSource(request) {
668
+ const { signal, exportJson, ...body } = request;
669
+ const path = `/api/v1/admin/import/scan${exportJson ? "?export=json" : ""}`;
670
+ return this.requestJson("POST", path, {
671
+ headers: { "Content-Type": "application/json" },
672
+ body: JSON.stringify(body),
673
+ }, signal);
674
+ }
675
+ async request(request) {
676
+ const method = request.method ?? "GET";
677
+ const params = new URLSearchParams();
678
+ params.set("f", request.responseFormat ?? "json");
679
+ if (request.query) {
680
+ for (const [key, value] of Object.entries(request.query)) {
681
+ params.set(key, String(value));
682
+ }
683
+ }
684
+ const normalizedPath = normalizePath(request.path);
685
+ const pathWithQuery = mergePathWithQueryParams(normalizedPath, params);
686
+ return this.requestJson(method, pathWithQuery, {
687
+ headers: request.headers,
688
+ body: request.body,
689
+ }, request.signal);
690
+ }
691
+ /**
692
+ * Pipeline-aware JSON request that bypasses the GeoServices `f=json`
693
+ * convention used by {@link request}. Adapters whose protocols do not
694
+ * model `f=` (OData, OGC API, …) call this directly so they keep the
695
+ * shared auth / retry / timeout / interceptor pipeline without sending
696
+ * a query parameter the server would reject as `InvalidQueryOption`.
697
+ *
698
+ * Caller-supplied query parameters belong on `path` itself; `init`
699
+ * carries the body, headers, and abort signal. The default `Accept`
700
+ * header is `application/json`; pass an explicit `Accept` in
701
+ * `init.headers` to override.
702
+ */
703
+ async pipelineRequestJson(method, path, init, signal) {
704
+ return this.requestJson(method, path, init, signal);
705
+ }
706
+ async composeHeaders(...headersList) {
707
+ const authHeaders = await this.resolveAuthHeaders();
708
+ return mergeHeaders(this.defaultHeaders, authHeaders, ...headersList);
709
+ }
710
+ async resolveAuthHeaders() {
711
+ const cached = await this.resolveAuthCredentials({ forceRefresh: false });
712
+ if (!cached)
713
+ return undefined;
714
+ return authHeadersFromCredentials(cached.credentials);
715
+ }
716
+ async resolveAuthCredentials(options) {
717
+ if (!this.authProvider) {
718
+ return undefined;
719
+ }
720
+ const cached = this.authCredentialsCache;
721
+ if (!options.forceRefresh && cached && !isAuthCredentialsExpiring(cached, this.authRefreshSkewMs)) {
722
+ return cached;
723
+ }
724
+ if (this.authRefreshPromise) {
725
+ return this.authRefreshPromise;
726
+ }
727
+ const reason = options.reason ?? resolveAuthRefreshReason(cached);
728
+ this.authRefreshPromise = this.loadAuthCredentials(reason, options.forceRefresh, cached?.credentials);
729
+ try {
730
+ return await this.authRefreshPromise;
731
+ }
732
+ finally {
733
+ this.authRefreshPromise = undefined;
734
+ }
735
+ }
736
+ async loadAuthCredentials(reason, forceRefresh, previousCredentials) {
737
+ const credentials = normalizeAuthCredentials(await this.authProvider?.getCredentials({
738
+ reason,
739
+ forceRefresh,
740
+ ...(previousCredentials ? { previousCredentials } : {}),
741
+ }));
742
+ if (!credentials) {
743
+ this.authCredentialsCache = undefined;
744
+ return undefined;
745
+ }
746
+ const cached = {
747
+ credentials,
748
+ expiresAtMs: normalizeAuthExpiresAtMs(credentials.expiresAt),
749
+ };
750
+ this.authCredentialsCache = cached;
751
+ return cached;
752
+ }
753
+ /**
754
+ * Pipeline-aware request that returns the raw `Response` after the
755
+ * shared auth / retry / timeout / interceptor pipeline finishes
756
+ * successfully. Used by adapters that need to consume non-JSON bodies
757
+ * (OData `$metadata` XML, raw passthrough) without inheriting the
758
+ * `Accept: application/json` default of {@link pipelineRequestJson}.
759
+ *
760
+ * The returned `Response` is unconsumed — the caller picks `.json()`,
761
+ * `.text()`, or `.arrayBuffer()`. Non-2xx responses still throw the
762
+ * normalized `HonuaHttpError` (and trigger retries) so error handling
763
+ * matches every other client method.
764
+ */
765
+ async pipelineFetch(method, path, init, callerSignal, options = {}) {
766
+ const request = {
767
+ url: resolveRequestUrl(this.baseUrl, path),
768
+ path,
769
+ method,
770
+ init: {
771
+ method,
772
+ headers: await this.composeHeaders(init?.headers),
773
+ body: init?.body ?? null,
774
+ ...(init?.signal ? { signal: init.signal } : {}),
775
+ },
776
+ };
777
+ return this.executeRequest(request, {
778
+ callerSignal,
779
+ ...(options.okStatuses ? { okStatuses: options.okStatuses } : {}),
780
+ finalize: async (response, _durationMs, _request, runAfter) => {
781
+ await runAfter();
782
+ return response;
783
+ },
784
+ });
785
+ }
786
+ async requestCachedMetadataJson(cacheKey, path, options = {}) {
787
+ const metadataOptions = normalizeHonuaMetadataRequestOptions(options);
788
+ const keyFingerprint = `metadata:${cacheKey}`;
789
+ const cached = this.metadataCache.get(keyFingerprint);
790
+ const bypass = metadataOptions.cache === "bypass";
791
+ const now = Date.now();
792
+ const freshCachedEntry = cached ? isHonuaCacheEntryFresh(cached.cachedAtMs, now, metadataOptions.ttlMs) : false;
793
+ if (!bypass && !metadataOptions.refresh && cached && freshCachedEntry) {
794
+ return withHonuaCacheState(cached.body, createMetadataCacheState(cached, "hit", {
795
+ now,
796
+ ttlMs: metadataOptions.ttlMs,
797
+ staleIfErrorMs: metadataOptions.staleIfErrorMs,
798
+ }));
799
+ }
800
+ const request = {
801
+ url: resolveRequestUrl(this.baseUrl, path),
802
+ path,
803
+ method: "GET",
804
+ init: {
805
+ method: "GET",
806
+ headers: await this.composeHeaders(honuaMetadataRequestHeaders({
807
+ accept: "application/json",
808
+ refresh: metadataOptions.refresh || Boolean(cached),
809
+ bypass,
810
+ validator: cached?.validator,
811
+ })),
812
+ },
813
+ };
814
+ return this.executeRequest(request, {
815
+ callerSignal: metadataOptions.signal,
816
+ // stale-if-error fallback on a terminal network or HTTP failure.
817
+ onTerminalError: (error) => this.staleMetadataFallback(cached, metadataOptions, error),
818
+ // 304 Not Modified: revalidate the cached entry without re-parsing a body.
819
+ shortCircuit: async (response, _durationMs, _currentRequest, runAfter) => {
820
+ if (response.status !== 304 || !cached || bypass) {
821
+ return undefined;
822
+ }
823
+ await runAfter();
824
+ const updatedEntry = {
825
+ ...cached,
826
+ cachedAtMs: Date.now(),
827
+ ...((honuaCacheValidatorFromHeaders(response.headers) ?? cached.validator)
828
+ ? { validator: honuaCacheValidatorFromHeaders(response.headers) ?? cached.validator }
829
+ : {}),
830
+ };
831
+ this.setMetadataCacheEntry(keyFingerprint, updatedEntry);
832
+ return {
833
+ value: withHonuaCacheState(updatedEntry.body, createMetadataCacheState(updatedEntry, "refreshed", {
834
+ now: Date.now(),
835
+ ttlMs: metadataOptions.ttlMs,
836
+ staleIfErrorMs: metadataOptions.staleIfErrorMs,
837
+ revalidatedAt: new Date().toISOString(),
838
+ })),
839
+ };
840
+ },
841
+ finalize: async (response, durationMs, currentRequest, runAfter) => {
842
+ const body = await parseResponseBody(this.hasAfterInterceptors() ? response.clone() : response);
843
+ // GeoServices reports metadata failures (layer not found, invalid token
844
+ // => code 499, …) as HTTP 200 with a top-level `{error}` envelope.
845
+ // Detect it before caching so a transient auth/permission error is never
846
+ // persisted as "valid" metadata for the cache TTL and surfaced
847
+ // downstream as `undefined` field access instead of a HonuaHttpError.
848
+ const envelopeError = geoServicesEnvelopeError(response.status, body);
849
+ if (envelopeError) {
850
+ const stale = this.staleMetadataFallback(cached, metadataOptions, envelopeError);
851
+ if (stale)
852
+ return stale;
853
+ await this.applyErrorInterceptors({
854
+ request: cloneRequestContext(currentRequest),
855
+ error: envelopeError,
856
+ durationMs,
857
+ });
858
+ throw envelopeError;
859
+ }
860
+ await runAfter();
861
+ const cleanBody = withoutHonuaCacheState(body);
862
+ const validator = honuaCacheValidatorFromHeaders(response.headers);
863
+ const sourceUpdatedAt = response.headers.get("last-modified") ?? undefined;
864
+ const entry = {
865
+ body: cleanBody,
866
+ cachedAtMs: Date.now(),
867
+ keyFingerprint,
868
+ ...(validator ? { validator } : {}),
869
+ ...(sourceUpdatedAt ? { sourceUpdatedAt } : {}),
870
+ };
871
+ const status = bypass ? "bypass" : cached ? "refreshed" : "miss";
872
+ if (!bypass) {
873
+ this.setMetadataCacheEntry(keyFingerprint, entry);
874
+ }
875
+ return withHonuaCacheState(cleanBody, createMetadataCacheState(entry, status, {
876
+ now: Date.now(),
877
+ ttlMs: metadataOptions.ttlMs,
878
+ staleIfErrorMs: metadataOptions.staleIfErrorMs,
879
+ ...(status === "refreshed" ? { revalidatedAt: new Date().toISOString() } : {}),
880
+ }));
881
+ },
882
+ });
883
+ }
884
+ staleMetadataFallback(cached, options, error) {
885
+ if (!cached || options.cache === "bypass" || !options.staleIfError) {
886
+ return undefined;
887
+ }
888
+ const staleIfErrorMs = options.staleIfErrorMs ?? HONUA_DEFAULT_METADATA_STALE_IF_ERROR_MS;
889
+ if (Date.now() - cached.cachedAtMs > staleIfErrorMs) {
890
+ return undefined;
891
+ }
892
+ return withHonuaCacheState(cached.body, createMetadataCacheState(cached, "stale", {
893
+ now: Date.now(),
894
+ ttlMs: options.ttlMs,
895
+ staleIfErrorMs: options.staleIfErrorMs,
896
+ refreshErrorId: metadataRefreshErrorId(error),
897
+ }));
898
+ }
899
+ setMetadataCacheEntry(key, entry) {
900
+ this.metadataCache.set(key, entry);
901
+ while (this.metadataCache.size > DEFAULT_METADATA_CACHE_MAX_ENTRIES) {
902
+ const oldest = [...this.metadataCache.entries()].sort((a, b) => a[1].cachedAtMs - b[1].cachedAtMs)[0];
903
+ if (!oldest)
904
+ return;
905
+ this.metadataCache.delete(oldest[0]);
906
+ }
907
+ }
908
+ async getLayerMetadata(serviceId, layerId, options = {}) {
909
+ return getLayerMetadata(this.protocolTransport, serviceId, layerId, options);
910
+ }
911
+ async getFeatureServiceMetadata(serviceId, options = {}) {
912
+ return getFeatureServiceMetadata(this.protocolTransport, serviceId, options);
913
+ }
914
+ /**
915
+ * Resolve (and memoize) the OGC API Features endpoint layout for the
916
+ * given discovery `mode`. `honua-facade` (default) returns the fixed
917
+ * `/ogc/features/...` fast path with no network access; `ogc-api` and
918
+ * `auto` discover the layout from the server's landing page per OGC API
919
+ * - Common so the same typed surface works against pygeoapi / ldproxy /
920
+ * GeoServer. Discovery is cached per mode for the life of the client
921
+ * (the layout is a function of the fixed `baseUrl`).
922
+ */
923
+ resolveOgcFeaturesLayout(mode = "honua-facade") {
924
+ if (mode === "honua-facade")
925
+ return Promise.resolve(honuaFacadeFeaturesLayout());
926
+ let cached = this.ogcLayoutCache.get(mode);
927
+ if (!cached) {
928
+ cached = resolveOgcEndpointLayout(this.protocolTransport, mode).catch((err) => {
929
+ // Allow a later retry after a transient discovery failure.
930
+ this.ogcLayoutCache.delete(mode);
931
+ throw err;
932
+ });
933
+ this.ogcLayoutCache.set(mode, cached);
934
+ }
935
+ return cached;
936
+ }
937
+ async getOgcFeaturesLanding(request = {}) {
938
+ return getOgcFeaturesLanding(this.protocolTransport, request);
939
+ }
940
+ async getOgcFeaturesConformance(request = {}) {
941
+ return getOgcFeaturesConformance(this.protocolTransport, request);
942
+ }
943
+ async listOgcCollections(request = {}) {
944
+ return listOgcCollections(this.protocolTransport, request);
945
+ }
946
+ async getOgcCollection(request) {
947
+ return getOgcCollection(this.protocolTransport, request);
948
+ }
949
+ async getOgcQueryables(request) {
950
+ return getOgcQueryables(this.protocolTransport, request);
951
+ }
952
+ async listOgcItems(request) {
953
+ return listOgcItems(this.protocolTransport, request);
954
+ }
955
+ async getOgcItem(request) {
956
+ return getOgcItem(this.protocolTransport, request);
957
+ }
958
+ async createOgcItem(request) {
959
+ return createOgcItem(this.protocolTransport, request);
960
+ }
961
+ async replaceOgcItem(request) {
962
+ return replaceOgcItem(this.protocolTransport, request);
963
+ }
964
+ async patchOgcItem(request) {
965
+ return patchOgcItem(this.protocolTransport, request);
966
+ }
967
+ async deleteOgcItem(request) {
968
+ await deleteOgcItem(this.protocolTransport, request);
969
+ }
970
+ // ── OGC API Tiles ───────────────────────────────────────────
971
+ async getOgcTilesLanding(request = {}) {
972
+ return getOgcTilesLanding(this.protocolTransport, request);
973
+ }
974
+ async getOgcTilesConformance(request = {}) {
975
+ return getOgcTilesConformance(this.protocolTransport, request);
976
+ }
977
+ async listOgcTileMatrixSets(request = {}) {
978
+ return listOgcTileMatrixSets(this.protocolTransport, request);
979
+ }
980
+ async getOgcTileMatrixSet(request) {
981
+ return getOgcTileMatrixSet(this.protocolTransport, request);
982
+ }
983
+ async listOgcCollectionTilesets(request) {
984
+ return listOgcCollectionTilesets(this.protocolTransport, request);
985
+ }
986
+ async getOgcCollectionTileset(request) {
987
+ return getOgcCollectionTileset(this.protocolTransport, request);
988
+ }
989
+ async fetchOgcTile(request) {
990
+ return fetchOgcTile(this.protocolTransport, request);
991
+ }
992
+ // ── OGC API Maps ────────────────────────────────────────────
993
+ async getOgcMapsLanding(request = {}) {
994
+ return getOgcMapsLanding(this.protocolTransport, request);
995
+ }
996
+ async getOgcMapsConformance(request = {}) {
997
+ return getOgcMapsConformance(this.protocolTransport, request);
998
+ }
999
+ async getOgcMapImage(request) {
1000
+ return getOgcMapImage(this.protocolTransport, request);
1001
+ }
1002
+ // ── OGC API Records ────────────────────────────────────────
1003
+ async getOgcRecordsLanding(request = {}) {
1004
+ return getOgcRecordsLanding(this.protocolTransport, request);
1005
+ }
1006
+ async getOgcRecordsConformance(request = {}) {
1007
+ return getOgcRecordsConformance(this.protocolTransport, request);
1008
+ }
1009
+ async listOgcRecordCollections(request = {}) {
1010
+ return listOgcRecordCollections(this.protocolTransport, request);
1011
+ }
1012
+ async getOgcRecordCollection(request) {
1013
+ return getOgcRecordCollection(this.protocolTransport, request);
1014
+ }
1015
+ async searchOgcRecords(request) {
1016
+ return searchOgcRecords(this.protocolTransport, request);
1017
+ }
1018
+ async getOgcRecord(request) {
1019
+ return getOgcRecord(this.protocolTransport, request);
1020
+ }
1021
+ async fetchOgcRecordsRaw(request) {
1022
+ return fetchOgcRecordsRaw(this.protocolTransport, request);
1023
+ }
1024
+ async fetchOgcRecordRaw(request) {
1025
+ return fetchOgcRecordRaw(this.protocolTransport, request);
1026
+ }
1027
+ // ── WMS 1.3 ─────────────────────────────────────────────────
1028
+ /**
1029
+ * Fetch and parse a WMS `GetCapabilities` document for the addressed
1030
+ * service. The XML body decodes through `requestText`; the parsed
1031
+ * shape is the typed `WmsCapabilities` envelope (no XML node leaks
1032
+ * through the public surface).
1033
+ */
1034
+ async getWmsCapabilities(request) {
1035
+ return getWmsCapabilities(this.protocolTransport, request);
1036
+ }
1037
+ /** Render a WMS `GetMap`. Returns the raw image bytes. */
1038
+ async getWmsMap(request) {
1039
+ return getWmsMap(this.protocolTransport, request);
1040
+ }
1041
+ /**
1042
+ * Issue a WMS `GetFeatureInfo`. When `INFO_FORMAT=application/json`
1043
+ * the JSON body decodes into the canonical `HonuaTypedFeature[]`
1044
+ * shape; non-JSON formats round-trip on `bytes` so callers retain the
1045
+ * raw payload behind the protocol escape hatch.
1046
+ */
1047
+ async getWmsFeatureInfo(request) {
1048
+ return getWmsFeatureInfo(this.protocolTransport, request);
1049
+ }
1050
+ /**
1051
+ * Fetch a WMS `GetLegendGraphic`. honua-server does not implement
1052
+ * GetLegendGraphic today; callers should branch on
1053
+ * `WmsCapabilities.request.getLegendGraphic` before invoking. When
1054
+ * the wire returns 5xx the underlying `HonuaHttpError` flows through.
1055
+ */
1056
+ async getWmsLegend(request) {
1057
+ return getWmsLegend(this.protocolTransport, request);
1058
+ }
1059
+ // ── WMTS 1.0 ────────────────────────────────────────────────
1060
+ async getWmtsCapabilities(request) {
1061
+ return getWmtsCapabilities(this.protocolTransport, request);
1062
+ }
1063
+ /**
1064
+ * Fetch a single WMTS tile. `mode` selects between KVP
1065
+ * (`?REQUEST=GetTile&...`) and the RESTful path
1066
+ * (`/{layer}/{style}/{tms}/{z}/{y}/{x}.{ext}`). honua-server
1067
+ * advertises both; the SDK defaults to RESTful because the wire path
1068
+ * is a single string substitution per tile and skips
1069
+ * URLSearchParams serialisation on the hot path.
1070
+ */
1071
+ async fetchWmtsTile(request) {
1072
+ return fetchWmtsTile(this.protocolTransport, request);
1073
+ }
1074
+ /**
1075
+ * WMTS GetFeatureInfo. honua-server accepts both KVP and RESTful
1076
+ * routing; mode default mirrors `fetchWmtsTile`.
1077
+ */
1078
+ async getWmtsFeatureInfo(request) {
1079
+ return getWmtsFeatureInfo(this.protocolTransport, request);
1080
+ }
1081
+ // ── OGC API Processes ───────────────────────────────────────
1082
+ async getOgcProcessesLanding(request = {}) {
1083
+ return getOgcProcessesLanding(this.protocolTransport, request);
1084
+ }
1085
+ async getOgcProcessesConformance(request = {}) {
1086
+ return getOgcProcessesConformance(this.protocolTransport, request);
1087
+ }
1088
+ async listOgcProcesses(request = {}) {
1089
+ return listOgcProcesses(this.protocolTransport, request);
1090
+ }
1091
+ async getOgcProcess(request) {
1092
+ return getOgcProcess(this.protocolTransport, request);
1093
+ }
1094
+ async executeOgcProcess(request) {
1095
+ return executeOgcProcess(this.protocolTransport, request);
1096
+ }
1097
+ async getOgcProcessJob(request) {
1098
+ return getOgcProcessJob(this.protocolTransport, request);
1099
+ }
1100
+ async getOgcProcessJobResults(request) {
1101
+ return getOgcProcessJobResults(this.protocolTransport, request);
1102
+ }
1103
+ async cancelOgcProcessJob(request) {
1104
+ return cancelOgcProcessJob(this.protocolTransport, request);
1105
+ }
1106
+ // ── STAC API ────────────────────────────────────────────────
1107
+ async getStacLanding(request = {}) {
1108
+ return getStacLanding(this.protocolTransport, request);
1109
+ }
1110
+ async listStacCollections(request = {}) {
1111
+ return listStacCollections(this.protocolTransport, request);
1112
+ }
1113
+ async getStacCollection(request) {
1114
+ return getStacCollection(this.protocolTransport, request);
1115
+ }
1116
+ async getStacItem(request) {
1117
+ return getStacItem(this.protocolTransport, request);
1118
+ }
1119
+ async searchStac(request = {}) {
1120
+ return searchStac(this.protocolTransport, request);
1121
+ }
1122
+ async getMapServiceMetadata(serviceId, options = {}) {
1123
+ return getMapServiceMetadata(this.protocolTransport, serviceId, options);
1124
+ }
1125
+ async getMapLayerMetadata(serviceId, layerId, options = {}) {
1126
+ return getMapLayerMetadata(this.protocolTransport, serviceId, layerId, options);
1127
+ }
1128
+ /**
1129
+ * Run a GeoServices `FeatureServer/query` request against a Honua-hosted layer.
1130
+ *
1131
+ * This is the canonical low-level read path. It maps directly to the FeatureServer
1132
+ * `query` endpoint and accepts the full ArcGIS query shape (`where`, `outFields`,
1133
+ * `geometry`, `spatialRel`, `orderByFields`, `resultRecordCount`, `outSr`, ...).
1134
+ *
1135
+ * For cross-protocol code (OGC, WFS, OData, STAC), prefer the protocol-neutral
1136
+ * {@link createDataset} contract — it normalizes capability differences and gives
1137
+ * you `Source.query(...)` plus paginated `Source.queryAll(...)` with explicit
1138
+ * `exceededTransferLimit` reporting.
1139
+ *
1140
+ * @example
1141
+ * ```ts
1142
+ * const { features, exceededTransferLimit } = await client.queryFeatures({
1143
+ * serviceId: "parcels",
1144
+ * layerId: 0,
1145
+ * where: "STATUS = 'ACTIVE'",
1146
+ * outFields: ["OBJECTID", "NAME"],
1147
+ * returnGeometry: true,
1148
+ * outSr: 4326,
1149
+ * resultRecordCount: 500,
1150
+ * });
1151
+ *
1152
+ * if (exceededTransferLimit) {
1153
+ * // re-issue with `resultOffset` or use queryFeaturesStream / dataset.source().queryAll()
1154
+ * }
1155
+ * ```
1156
+ */
1157
+ async queryFeatures(request) {
1158
+ if (this.transport === "grpc-web") {
1159
+ const client = await this.ensureConnectClient();
1160
+ const grpcAdapter = await HonuaClient.loadGrpcAdapter();
1161
+ const protoRequest = grpcAdapter.toProtoQueryRequest(request);
1162
+ try {
1163
+ const response = await client.queryFeatures(protoRequest, request.signal ? { signal: request.signal } : undefined);
1164
+ return grpcAdapter.fromProtoQueryResponse(response);
1165
+ }
1166
+ catch (error) {
1167
+ throw grpcAdapter.wrapConnectError(error);
1168
+ }
1169
+ }
1170
+ return queryFeaturesRest(this.protocolTransport, request, this.preferBinary);
1171
+ }
1172
+ async queryMapLayer(request) {
1173
+ return queryMapLayer(this.protocolTransport, request);
1174
+ }
1175
+ async applyEdits(request) {
1176
+ return applyEdits(this.protocolTransport, request);
1177
+ }
1178
+ async queryRelatedRecords(request) {
1179
+ return queryRelatedRecords(this.protocolTransport, request);
1180
+ }
1181
+ async queryMapRelatedRecords(request) {
1182
+ return queryMapRelatedRecords(this.protocolTransport, request);
1183
+ }
1184
+ async exportMap(request) {
1185
+ return exportMap(this.protocolTransport, request);
1186
+ }
1187
+ async getMapLegend(request) {
1188
+ return getMapLegend(this.protocolTransport, request);
1189
+ }
1190
+ async identifyMap(request) {
1191
+ return identifyMap(this.protocolTransport, request);
1192
+ }
1193
+ async findMap(request) {
1194
+ return findMap(this.protocolTransport, request);
1195
+ }
1196
+ async requestJson(method, path, init, callerSignal) {
1197
+ const request = {
1198
+ url: resolveRequestUrl(this.baseUrl, path),
1199
+ path,
1200
+ method,
1201
+ init: {
1202
+ method,
1203
+ headers: await this.composeHeaders({ Accept: "application/json" }, init?.headers),
1204
+ body: init?.body,
1205
+ },
1206
+ };
1207
+ return this.executeRequest(request, {
1208
+ callerSignal,
1209
+ finalize: async (response, durationMs, currentRequest, runAfter) => {
1210
+ // Parse the original body directly when no after-interceptor will read
1211
+ // it; only clone when an interceptor needs an independent copy.
1212
+ const body = await parseResponseBody(this.hasAfterInterceptors() ? response.clone() : response);
1213
+ // GeoServices/Esri services return HTTP 200 with a top-level `{error}`
1214
+ // envelope on failure (bad WHERE, invalid outFields, edit failures, …).
1215
+ // Surface these through the unified error model instead of handing the
1216
+ // failure envelope back as a "successful" response object.
1217
+ const envelopeError = geoServicesEnvelopeError(response.status, body);
1218
+ if (envelopeError) {
1219
+ await this.applyErrorInterceptors({
1220
+ request: cloneRequestContext(currentRequest),
1221
+ error: envelopeError,
1222
+ durationMs,
1223
+ });
1224
+ throw envelopeError;
1225
+ }
1226
+ await runAfter();
1227
+ return body;
1228
+ },
1229
+ });
1230
+ }
1231
+ /**
1232
+ * Request a PBF binary response and decode it. Falls back to JSON on failure.
1233
+ */
1234
+ async requestBinaryWithJsonFallback(method, path, params, callerSignal) {
1235
+ const request = {
1236
+ url: resolveRequestUrl(this.baseUrl, path),
1237
+ path,
1238
+ method,
1239
+ init: {
1240
+ method,
1241
+ headers: await this.composeHeaders({ Accept: "application/x-protobuf, application/json;q=0.9" }),
1242
+ },
1243
+ };
1244
+ return this.executeRequest(request, {
1245
+ callerSignal,
1246
+ finalize: async (response, durationMs, currentRequest, runAfter) => {
1247
+ await runAfter();
1248
+ // If the server returned PBF, decode it; on decode failure (including
1249
+ // Z/M geometry the fast path can't handle) retry as f=json.
1250
+ if (isPbfResponse(response)) {
1251
+ try {
1252
+ const buffer = await response.arrayBuffer();
1253
+ return decodePbfQueryResponse(buffer);
1254
+ }
1255
+ catch {
1256
+ params.set("f", "json");
1257
+ const jsonPath = `${stripQuery(path)}?${params.toString()}`;
1258
+ return this.requestJson("GET", jsonPath, undefined, callerSignal ?? currentRequest.init.signal ?? undefined);
1259
+ }
1260
+ }
1261
+ // Server returned JSON despite the PBF request (e.g. error or
1262
+ // unsupported). GeoServices reports query failures (bad WHERE, invalid
1263
+ // outFields, expired token => code 498/499) as HTTP 200 application/json
1264
+ // even when f=pbf was requested. Detect the `{error}` envelope here so
1265
+ // preferBinary callers throw a normalized HonuaHttpError exactly like
1266
+ // the JSON path instead of receiving the failure envelope as success.
1267
+ const body = await parseResponseBody(response);
1268
+ const envelopeError = geoServicesEnvelopeError(response.status, body);
1269
+ if (envelopeError) {
1270
+ await this.applyErrorInterceptors({
1271
+ request: cloneRequestContext(currentRequest),
1272
+ error: envelopeError,
1273
+ durationMs,
1274
+ });
1275
+ throw envelopeError;
1276
+ }
1277
+ return body;
1278
+ },
1279
+ });
1280
+ }
1281
+ /**
1282
+ * Fetch a text response (e.g. XML / JSON / plain) with an explicit Accept
1283
+ * negotiation. Used by the WFS adapter for `GetCapabilities`,
1284
+ * `Transaction` responses, and ExceptionReport bodies, and by the
1285
+ * WMS / WMTS Capabilities pipelines. Routes through the same
1286
+ * interceptor / retry / abort pipeline as `requestJson` /
1287
+ * `requestBytes`, so adapter callers do not need to bypass `HonuaClient`
1288
+ * to reach `fetch` directly.
1289
+ */
1290
+ async requestText(method, path, options) {
1291
+ const acceptHeader = options?.accept ?? "*/*";
1292
+ const headers = { Accept: acceptHeader };
1293
+ if (options?.contentType)
1294
+ headers["Content-Type"] = options.contentType;
1295
+ const request = {
1296
+ url: resolveRequestUrl(this.baseUrl, path),
1297
+ path,
1298
+ method,
1299
+ init: {
1300
+ method,
1301
+ headers: await this.composeHeaders(headers),
1302
+ ...(options?.body !== undefined ? { body: options.body } : {}),
1303
+ },
1304
+ };
1305
+ return this.executeRequest(request, {
1306
+ callerSignal: options?.signal,
1307
+ errorBody: async (response) => {
1308
+ const text = await response.clone().text();
1309
+ const contentType = response.headers.get("content-type") ?? acceptHeader;
1310
+ return text ? { raw: text, contentType } : {};
1311
+ },
1312
+ finalize: async (response, _durationMs, _request, runAfter) => {
1313
+ await runAfter();
1314
+ const text = await response.text();
1315
+ const contentType = response.headers.get("content-type") ?? acceptHeader;
1316
+ return { text, contentType, status: response.status };
1317
+ },
1318
+ });
1319
+ }
1320
+ /**
1321
+ * Fetch a binary response (raw bytes plus content type). Used by the
1322
+ * OGC API Tiles and OGC API Maps wire methods, both of which negotiate
1323
+ * non-JSON output formats. The interceptor / retry / abort plumbing
1324
+ * mirrors `requestJson`.
1325
+ */
1326
+ async requestBytes(method, path, accept, init, callerSignal) {
1327
+ const acceptHeader = accept ?? "application/octet-stream";
1328
+ const request = {
1329
+ url: resolveRequestUrl(this.baseUrl, path),
1330
+ path,
1331
+ method,
1332
+ init: {
1333
+ method,
1334
+ headers: await this.composeHeaders({ Accept: acceptHeader }, init?.headers),
1335
+ body: init?.body,
1336
+ },
1337
+ };
1338
+ return this.executeRequest(request, {
1339
+ callerSignal,
1340
+ finalize: async (response, _durationMs, _request, runAfter) => {
1341
+ await runAfter();
1342
+ const buffer = await response.arrayBuffer();
1343
+ const bytes = new Uint8Array(buffer);
1344
+ return {
1345
+ bytes,
1346
+ contentType: response.headers.get("content-type") ?? acceptHeader,
1347
+ empty: response.status === 204 || bytes.byteLength === 0,
1348
+ };
1349
+ },
1350
+ });
1351
+ }
1352
+ /**
1353
+ * Single owner of the HTTP attempt loop shared by every typed request
1354
+ * wrapper: before-interceptors, per-attempt timeout, network-error
1355
+ * normalization + retry, replay-safe auth refresh, HTTP-status retry, and the
1356
+ * after/error-interceptor calls. The previous implementation copy-pasted this
1357
+ * loop across six methods (pipelineFetch / requestCachedMetadataJson /
1358
+ * requestJson / requestBinaryWithJsonFallback / requestText / requestBytes),
1359
+ * and the copies had drifted in signal, okStatuses, and 304 handling — the
1360
+ * exact surface where an auth-replay / retry regression can appear in one
1361
+ * transport but not the others.
1362
+ *
1363
+ * Wrappers supply only what differs:
1364
+ * - `finalize` turns a successful `Response` into the wrapper's `T`. It is
1365
+ * handed a `runAfter` thunk so it controls *when* after-interceptors fire
1366
+ * (e.g. before vs. after a GeoServices error-envelope check) and can parse
1367
+ * the original body without a defensive clone (see `hasAfterInterceptors`).
1368
+ * - `shortCircuit` (optional) inspects the response before the ok/!ok split,
1369
+ * e.g. a metadata `304 Not Modified`.
1370
+ * - `okStatuses` (optional) treats specific non-2xx statuses as success.
1371
+ * - `errorBody` (optional) builds the body fed to `toHttpError` on failure.
1372
+ * - `onTerminalError` (optional) yields a fallback value instead of throwing
1373
+ * on a terminal network/HTTP error, e.g. stale-if-error metadata.
1374
+ */
1375
+ async executeRequest(initialRequest, options) {
1376
+ let request = await this.applyBeforeInterceptors(initialRequest);
1377
+ const retrySignal = options.callerSignal ?? request.init.signal ?? undefined;
1378
+ let refreshedAuth = false;
1379
+ for (let attempt = 0;; attempt += 1) {
1380
+ let response;
1381
+ const timeout = createTimeoutSignal(options.callerSignal ?? request.init.signal, this.timeoutMs);
1382
+ const startTime = performance.now();
1383
+ try {
1384
+ response = await this.fetchWithSafeRedirects(request.url, {
1385
+ ...request.init,
1386
+ method: request.method,
1387
+ signal: timeout.signal,
1388
+ });
1389
+ }
1390
+ catch (error) {
1391
+ const durationMs = performance.now() - startTime;
1392
+ const normalizedError = timeout.didTimeout
1393
+ ? new HonuaTimeoutError(this.timeoutMs ?? 0)
1394
+ : normalizeNetworkError(error);
1395
+ if (shouldRetryRequest(this.retryOptions, request.method, attempt, undefined, normalizedError)) {
1396
+ await this.sleepBeforeRetry(attempt, undefined, retrySignal);
1397
+ continue;
1398
+ }
1399
+ const fallback = options.onTerminalError?.(normalizedError);
1400
+ if (fallback !== undefined)
1401
+ return fallback;
1402
+ await this.applyErrorInterceptors({
1403
+ request: cloneRequestContext(request),
1404
+ error: normalizedError,
1405
+ durationMs,
1406
+ });
1407
+ throw normalizedError;
1408
+ }
1409
+ finally {
1410
+ timeout.dispose();
1411
+ }
1412
+ const durationMs = performance.now() - startTime;
1413
+ const currentRequest = request;
1414
+ const runAfter = async () => {
1415
+ try {
1416
+ await this.applyAfterInterceptors(cloneRequestContext(currentRequest), response, durationMs);
1417
+ }
1418
+ catch (error) {
1419
+ await this.applyErrorInterceptors({ request: cloneRequestContext(currentRequest), error, durationMs });
1420
+ throw error;
1421
+ }
1422
+ };
1423
+ if (options.shortCircuit) {
1424
+ const shorted = await options.shortCircuit(response, durationMs, currentRequest, runAfter);
1425
+ if (shorted)
1426
+ return shorted.value;
1427
+ }
1428
+ if (!response.ok && !options.okStatuses?.includes(response.status)) {
1429
+ const body = options.errorBody ? await options.errorBody(response) : await parseResponseBody(response.clone());
1430
+ const httpError = toHttpError(response.status, body);
1431
+ const authRefreshedRequest = refreshedAuth
1432
+ ? undefined
1433
+ : await this.refreshReplaySafeRequestAuth(request, response.status);
1434
+ if (authRefreshedRequest) {
1435
+ request = authRefreshedRequest;
1436
+ refreshedAuth = true;
1437
+ continue;
1438
+ }
1439
+ if (shouldRetryRequest(this.retryOptions, request.method, attempt, response.status, httpError)) {
1440
+ await this.sleepBeforeRetry(attempt, response, retrySignal);
1441
+ continue;
1442
+ }
1443
+ const fallback = options.onTerminalError?.(httpError);
1444
+ if (fallback !== undefined)
1445
+ return fallback;
1446
+ await this.applyErrorInterceptors({ request: cloneRequestContext(request), error: httpError, durationMs });
1447
+ throw httpError;
1448
+ }
1449
+ return options.finalize(response, durationMs, currentRequest, runAfter);
1450
+ }
1451
+ }
1452
+ async applyBeforeInterceptors(request) {
1453
+ let next = cloneRequestContext(request);
1454
+ next = {
1455
+ ...next,
1456
+ url: normalizeInterceptorRequestUrl(this.baseUrl, next.url),
1457
+ };
1458
+ for (const interceptor of this.interceptors) {
1459
+ const mutation = await interceptor.before?.(cloneRequestContext(next));
1460
+ if (!mutation) {
1461
+ continue;
1462
+ }
1463
+ next = applyRequestMutation(next, mutation);
1464
+ next = {
1465
+ ...next,
1466
+ url: normalizeInterceptorRequestUrl(this.baseUrl, next.url),
1467
+ };
1468
+ }
1469
+ return next;
1470
+ }
1471
+ async applyAfterInterceptors(request, response, durationMs) {
1472
+ for (const interceptor of this.interceptors) {
1473
+ // Only clone the response for interceptors that actually inspect it. This
1474
+ // keeps the no-after-interceptor hot path free of `Response.clone()` (so
1475
+ // typed wrappers can parse the original body directly) and avoids cloning
1476
+ // for `before`/`error`-only interceptors.
1477
+ if (!interceptor.after) {
1478
+ continue;
1479
+ }
1480
+ const context = {
1481
+ request: cloneRequestContext(request),
1482
+ response: response.clone(),
1483
+ durationMs,
1484
+ };
1485
+ await interceptor.after(context);
1486
+ }
1487
+ }
1488
+ /** Whether any registered interceptor inspects responses (`after` hook). */
1489
+ hasAfterInterceptors() {
1490
+ return this.interceptors.some((interceptor) => interceptor.after !== undefined);
1491
+ }
1492
+ async applyErrorInterceptors(context) {
1493
+ for (const interceptor of this.interceptors) {
1494
+ try {
1495
+ await interceptor.error?.(context);
1496
+ }
1497
+ catch {
1498
+ // Preserve original request failure; interceptor failures should not mask it.
1499
+ }
1500
+ }
1501
+ }
1502
+ async refreshReplaySafeRequestAuth(request, statusCode) {
1503
+ if ((statusCode !== 401 && statusCode !== 403) ||
1504
+ !this.authProvider ||
1505
+ !DEFAULT_RETRY_METHODS.has(request.method)) {
1506
+ return undefined;
1507
+ }
1508
+ const refreshed = await this.resolveAuthCredentials({ forceRefresh: true, reason: "unauthorized" });
1509
+ if (!refreshed)
1510
+ return undefined;
1511
+ return {
1512
+ ...request,
1513
+ init: {
1514
+ ...request.init,
1515
+ headers: mergeHeaders(request.init.headers, authHeadersFromCredentials(refreshed.credentials)),
1516
+ },
1517
+ };
1518
+ }
1519
+ async sleepBeforeRetry(attempt, response, signal) {
1520
+ await sleep(resolveRetryDelayMs(this.retryOptions, attempt, response), signal);
1521
+ }
1522
+ }
1523
+ /**
1524
+ * Detect a GeoServices/Esri error envelope returned on an HTTP 2xx response.
1525
+ *
1526
+ * GeoServices services (FeatureServer/MapServer/GeocodeServer/…) report
1527
+ * operation failures as HTTP 200 with a body of the shape
1528
+ * `{ error: { code, message, ... } }`. Without this guard such failures are
1529
+ * cast verbatim to the success response type and surface downstream as empty
1530
+ * results or confusing `undefined` access. Returns a normalized
1531
+ * {@link HonuaHttpError} when the envelope is present, otherwise `undefined`.
1532
+ */
1533
+ function geoServicesEnvelopeError(httpStatus, body) {
1534
+ if (!isObject(body) || !isObject(body.error)) {
1535
+ return undefined;
1536
+ }
1537
+ const error = body.error;
1538
+ const hasCode = typeof error.code === "number";
1539
+ const hasMessage = typeof error.message === "string";
1540
+ if (!hasCode && !hasMessage) {
1541
+ return undefined;
1542
+ }
1543
+ const statusCode = hasCode ? error.code : httpStatus;
1544
+ const message = hasMessage ? error.message : "Request failed";
1545
+ return new HonuaHttpError(statusCode, message, body);
1546
+ }
1547
+ async function parseResponseBody(response) {
1548
+ const text = await response.text();
1549
+ if (!text) {
1550
+ return {};
1551
+ }
1552
+ try {
1553
+ return JSON.parse(text);
1554
+ }
1555
+ catch {
1556
+ return { raw: text };
1557
+ }
1558
+ }
1559
+ function isObject(value) {
1560
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1561
+ }
1562
+ function applyRequestMutation(request, mutation) {
1563
+ const nextInit = mutation.init === undefined
1564
+ ? request.init
1565
+ : {
1566
+ ...request.init,
1567
+ ...mutation.init,
1568
+ headers: mergeHeaders(request.init.headers, mutation.init.headers),
1569
+ };
1570
+ return {
1571
+ url: mutation.url ?? request.url,
1572
+ path: request.path,
1573
+ method: mutation.method ?? request.method,
1574
+ init: {
1575
+ ...nextInit,
1576
+ method: mutation.method ?? request.method,
1577
+ },
1578
+ };
1579
+ }
1580
+ function cloneRequestContext(request) {
1581
+ return {
1582
+ ...request,
1583
+ init: {
1584
+ ...request.init,
1585
+ headers: cloneHeadersInit(request.init.headers),
1586
+ },
1587
+ };
1588
+ }
1589
+ function cloneHeadersInit(headers) {
1590
+ return mergeHeaders(headers);
1591
+ }
1592
+ function normalizeAuthProvider(auth) {
1593
+ if (!auth) {
1594
+ return undefined;
1595
+ }
1596
+ if (typeof auth === "function") {
1597
+ return { getCredentials: auth };
1598
+ }
1599
+ return {
1600
+ getCredentials: (context) => auth.getCredentials(context),
1601
+ ...(auth.revokeCredentials ? { revokeCredentials: auth.revokeCredentials.bind(auth) } : {}),
1602
+ };
1603
+ }
1604
+ function normalizeAuthRefreshSkewMs(value) {
1605
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1606
+ return DEFAULT_AUTH_REFRESH_SKEW_MS;
1607
+ }
1608
+ return Math.max(0, Math.trunc(value));
1609
+ }
1610
+ function normalizeAuthCredentials(value) {
1611
+ if (typeof value === "string") {
1612
+ return value.length > 0 ? { bearerToken: value } : undefined;
1613
+ }
1614
+ if (!value) {
1615
+ return undefined;
1616
+ }
1617
+ const credentials = {};
1618
+ if (typeof value.apiKey === "string" && value.apiKey.length > 0) {
1619
+ credentials.apiKey = value.apiKey;
1620
+ }
1621
+ if (typeof value.bearerToken === "string" && value.bearerToken.length > 0) {
1622
+ credentials.bearerToken = value.bearerToken;
1623
+ }
1624
+ if (typeof value.authorization === "string" && value.authorization.length > 0) {
1625
+ credentials.authorization = value.authorization;
1626
+ }
1627
+ if (value.expiresAt !== undefined) {
1628
+ credentials.expiresAt = value.expiresAt;
1629
+ }
1630
+ if (!credentials.apiKey && !credentials.bearerToken && !credentials.authorization) {
1631
+ return undefined;
1632
+ }
1633
+ return credentials;
1634
+ }
1635
+ function normalizeAuthExpiresAtMs(expiresAt) {
1636
+ if (expiresAt === undefined) {
1637
+ return undefined;
1638
+ }
1639
+ if (expiresAt instanceof Date) {
1640
+ return Number.isFinite(expiresAt.getTime()) ? expiresAt.getTime() : undefined;
1641
+ }
1642
+ if (typeof expiresAt === "number") {
1643
+ return Number.isFinite(expiresAt) ? expiresAt : undefined;
1644
+ }
1645
+ const parsed = Date.parse(expiresAt);
1646
+ return Number.isFinite(parsed) ? parsed : undefined;
1647
+ }
1648
+ function isAuthCredentialsExpiring(cached, skewMs) {
1649
+ if (cached.expiresAtMs === undefined) {
1650
+ return false;
1651
+ }
1652
+ return cached.expiresAtMs - Date.now() <= skewMs;
1653
+ }
1654
+ function resolveAuthRefreshReason(cached) {
1655
+ return cached ? "expired" : "initial";
1656
+ }
1657
+ function authHeadersFromCredentials(credentials) {
1658
+ const headers = {};
1659
+ if (credentials.apiKey) {
1660
+ headers["X-API-Key"] = credentials.apiKey;
1661
+ }
1662
+ if (credentials.authorization) {
1663
+ headers.Authorization = credentials.authorization;
1664
+ }
1665
+ else if (credentials.bearerToken) {
1666
+ headers.Authorization = `Bearer ${credentials.bearerToken}`;
1667
+ }
1668
+ return Object.keys(headers).length > 0 ? headers : undefined;
1669
+ }
1670
+ function createMetadataCacheState(entry, status, options) {
1671
+ return createHonuaCacheState({
1672
+ scope: "metadata",
1673
+ status,
1674
+ keyFingerprint: entry.keyFingerprint,
1675
+ ageMs: Math.max(0, options.now - entry.cachedAtMs),
1676
+ ...(options.ttlMs !== undefined ? { ttlMs: options.ttlMs } : {}),
1677
+ ...(options.staleIfErrorMs !== undefined ? { staleIfErrorMs: options.staleIfErrorMs } : {}),
1678
+ ...(options.revalidatedAt ? { revalidatedAt: options.revalidatedAt } : {}),
1679
+ ...(entry.sourceUpdatedAt ? { sourceUpdatedAt: entry.sourceUpdatedAt } : {}),
1680
+ ...(entry.validator ? { validator: entry.validator } : {}),
1681
+ ...(options.refreshErrorId ? { refreshErrorId: options.refreshErrorId } : {}),
1682
+ });
1683
+ }
1684
+ function metadataRefreshErrorId(error) {
1685
+ if (error instanceof HonuaHttpError) {
1686
+ return `http-${error.statusCode}`;
1687
+ }
1688
+ if (error instanceof HonuaTimeoutError) {
1689
+ return "timeout";
1690
+ }
1691
+ if (error instanceof HonuaNetworkError) {
1692
+ return "network";
1693
+ }
1694
+ if (error instanceof Error && error.name) {
1695
+ return error.name;
1696
+ }
1697
+ return "unknown";
1698
+ }
1699
+ function mergePathWithQueryParams(path, additionalParams) {
1700
+ if (additionalParams.size === 0) {
1701
+ return path;
1702
+ }
1703
+ const hashIndex = path.indexOf("#");
1704
+ const hash = hashIndex >= 0 ? path.slice(hashIndex) : "";
1705
+ const withoutHash = hashIndex >= 0 ? path.slice(0, hashIndex) : path;
1706
+ const queryIndex = withoutHash.indexOf("?");
1707
+ const basePath = queryIndex >= 0 ? withoutHash.slice(0, queryIndex) : withoutHash;
1708
+ const existingQuery = queryIndex >= 0 ? withoutHash.slice(queryIndex + 1) : "";
1709
+ const merged = new URLSearchParams(existingQuery);
1710
+ for (const [key, value] of additionalParams.entries()) {
1711
+ merged.set(key, value);
1712
+ }
1713
+ const nextQuery = merged.toString();
1714
+ const withQuery = nextQuery.length > 0 ? `${basePath}?${nextQuery}` : basePath;
1715
+ return `${withQuery}${hash}`;
1716
+ }