@honua/react 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 (597) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +9 -0
  3. package/contract/analytics-sources.d.ts +149 -0
  4. package/contract/analytics-sources.d.ts.map +1 -0
  5. package/contract/analytics-sources.js +235 -0
  6. package/contract/edit-session.d.ts +203 -0
  7. package/contract/edit-session.d.ts.map +1 -0
  8. package/contract/edit-session.js +760 -0
  9. package/contract/edit-sketch.d.ts +91 -0
  10. package/contract/edit-sketch.d.ts.map +1 -0
  11. package/contract/edit-sketch.js +281 -0
  12. package/contract/index.d.ts +61 -0
  13. package/contract/index.d.ts.map +1 -0
  14. package/contract/index.js +51 -0
  15. package/contract/jobs.d.ts +149 -0
  16. package/contract/jobs.d.ts.map +1 -0
  17. package/contract/jobs.js +40 -0
  18. package/contract/source.d.ts +423 -0
  19. package/contract/source.d.ts.map +1 -0
  20. package/contract/source.js +3802 -0
  21. package/contract/spatial-aggregation.d.ts +336 -0
  22. package/contract/spatial-aggregation.d.ts.map +1 -0
  23. package/contract/spatial-aggregation.js +298 -0
  24. package/contract/temporal.d.ts +455 -0
  25. package/contract/temporal.d.ts.map +1 -0
  26. package/contract/temporal.js +146 -0
  27. package/contract/tiles.d.ts +370 -0
  28. package/contract/tiles.d.ts.map +1 -0
  29. package/contract/tiles.js +519 -0
  30. package/contract/types.d.ts +665 -0
  31. package/contract/types.d.ts.map +1 -0
  32. package/contract/types.js +175 -0
  33. package/contract/widget-source.d.ts +205 -0
  34. package/contract/widget-source.d.ts.map +1 -0
  35. package/contract/widget-source.js +1473 -0
  36. package/control-plane/client.d.ts +95 -0
  37. package/control-plane/client.d.ts.map +1 -0
  38. package/control-plane/client.js +374 -0
  39. package/control-plane/index.d.ts +18 -0
  40. package/control-plane/index.d.ts.map +1 -0
  41. package/control-plane/index.js +14 -0
  42. package/control-plane/types.d.ts +233 -0
  43. package/control-plane/types.d.ts.map +1 -0
  44. package/control-plane/types.js +7 -0
  45. package/core/batch.d.ts +37 -0
  46. package/core/batch.d.ts.map +1 -0
  47. package/core/batch.js +79 -0
  48. package/core/cache-state.d.ts +79 -0
  49. package/core/cache-state.d.ts.map +1 -0
  50. package/core/cache-state.js +87 -0
  51. package/core/client.d.ts +577 -0
  52. package/core/client.d.ts.map +1 -0
  53. package/core/client.js +1664 -0
  54. package/core/compatibility.d.ts +18 -0
  55. package/core/compatibility.d.ts.map +1 -0
  56. package/core/compatibility.js +245 -0
  57. package/core/errors.d.ts +107 -0
  58. package/core/errors.d.ts.map +1 -0
  59. package/core/errors.js +156 -0
  60. package/core/esri-geojson.d.ts +66 -0
  61. package/core/esri-geojson.d.ts.map +1 -0
  62. package/core/esri-geojson.js +363 -0
  63. package/core/geoservices.d.ts +34 -0
  64. package/core/geoservices.d.ts.map +1 -0
  65. package/core/geoservices.js +434 -0
  66. package/core/grpc-adapter.d.ts +23 -0
  67. package/core/grpc-adapter.d.ts.map +1 -0
  68. package/core/grpc-adapter.js +688 -0
  69. package/core/odata.d.ts +347 -0
  70. package/core/odata.d.ts.map +1 -0
  71. package/core/odata.js +913 -0
  72. package/core/ogc-conformance.d.ts +35 -0
  73. package/core/ogc-conformance.d.ts.map +1 -0
  74. package/core/ogc-conformance.js +134 -0
  75. package/core/ogc-features.d.ts +23 -0
  76. package/core/ogc-features.d.ts.map +1 -0
  77. package/core/ogc-features.js +114 -0
  78. package/core/ogc-maps.d.ts +49 -0
  79. package/core/ogc-maps.d.ts.map +1 -0
  80. package/core/ogc-maps.js +126 -0
  81. package/core/ogc-processes.d.ts +118 -0
  82. package/core/ogc-processes.d.ts.map +1 -0
  83. package/core/ogc-processes.js +423 -0
  84. package/core/ogc-records.d.ts +75 -0
  85. package/core/ogc-records.d.ts.map +1 -0
  86. package/core/ogc-records.js +251 -0
  87. package/core/ogc-tiles.d.ts +125 -0
  88. package/core/ogc-tiles.d.ts.map +1 -0
  89. package/core/ogc-tiles.js +183 -0
  90. package/core/path-utils.d.ts +69 -0
  91. package/core/path-utils.d.ts.map +1 -0
  92. package/core/path-utils.js +123 -0
  93. package/core/pbf-decoder.d.ts +39 -0
  94. package/core/pbf-decoder.d.ts.map +1 -0
  95. package/core/pbf-decoder.js +702 -0
  96. package/core/process-runner.d.ts +104 -0
  97. package/core/process-runner.d.ts.map +1 -0
  98. package/core/process-runner.js +315 -0
  99. package/core/protocol-transport.d.ts +76 -0
  100. package/core/protocol-transport.d.ts.map +1 -0
  101. package/core/protocol-transport.js +15 -0
  102. package/core/query-builder.d.ts +261 -0
  103. package/core/query-builder.d.ts.map +1 -0
  104. package/core/query-builder.js +538 -0
  105. package/core/request-pipeline.d.ts +88 -0
  106. package/core/request-pipeline.d.ts.map +1 -0
  107. package/core/request-pipeline.js +273 -0
  108. package/core/spatial-filter.d.ts +93 -0
  109. package/core/spatial-filter.d.ts.map +1 -0
  110. package/core/spatial-filter.js +153 -0
  111. package/core/stac.d.ts +55 -0
  112. package/core/stac.d.ts.map +1 -0
  113. package/core/stac.js +229 -0
  114. package/core/surfaces.d.ts +527 -0
  115. package/core/surfaces.d.ts.map +1 -0
  116. package/core/surfaces.js +1917 -0
  117. package/core/terrain-elevation.d.ts +114 -0
  118. package/core/terrain-elevation.d.ts.map +1 -0
  119. package/core/terrain-elevation.js +150 -0
  120. package/core/types.d.ts +1355 -0
  121. package/core/types.d.ts.map +1 -0
  122. package/core/types.js +13 -0
  123. package/core/wfs-capabilities.d.ts +143 -0
  124. package/core/wfs-capabilities.d.ts.map +1 -0
  125. package/core/wfs-capabilities.js +478 -0
  126. package/core/wfs-filter.d.ts +118 -0
  127. package/core/wfs-filter.d.ts.map +1 -0
  128. package/core/wfs-filter.js +634 -0
  129. package/core/wfs.d.ts +219 -0
  130. package/core/wfs.d.ts.map +1 -0
  131. package/core/wfs.js +406 -0
  132. package/core/wire-shared.d.ts +32 -0
  133. package/core/wire-shared.d.ts.map +1 -0
  134. package/core/wire-shared.js +76 -0
  135. package/core/wms-axis.d.ts +36 -0
  136. package/core/wms-axis.d.ts.map +1 -0
  137. package/core/wms-axis.js +73 -0
  138. package/core/wms-capabilities.d.ts +110 -0
  139. package/core/wms-capabilities.d.ts.map +1 -0
  140. package/core/wms-capabilities.js +559 -0
  141. package/core/wms-types.d.ts +128 -0
  142. package/core/wms-types.d.ts.map +1 -0
  143. package/core/wms-types.js +32 -0
  144. package/core/wms.d.ts +144 -0
  145. package/core/wms.d.ts.map +1 -0
  146. package/core/wms.js +338 -0
  147. package/core/wmts-capabilities.d.ts +82 -0
  148. package/core/wmts-capabilities.d.ts.map +1 -0
  149. package/core/wmts-capabilities.js +402 -0
  150. package/core/wmts.d.ts +103 -0
  151. package/core/wmts.d.ts.map +1 -0
  152. package/core/wmts.js +332 -0
  153. package/core/xml-text.d.ts +20 -0
  154. package/core/xml-text.d.ts.map +1 -0
  155. package/core/xml-text.js +85 -0
  156. package/esri-compat/basemap-gallery.d.ts +38 -0
  157. package/esri-compat/basemap-gallery.d.ts.map +1 -0
  158. package/esri-compat/basemap-gallery.js +159 -0
  159. package/esri-compat/basemap-layer-list.d.ts +35 -0
  160. package/esri-compat/basemap-layer-list.d.ts.map +1 -0
  161. package/esri-compat/basemap-layer-list.js +139 -0
  162. package/esri-compat/basemap.d.ts +32 -0
  163. package/esri-compat/basemap.d.ts.map +1 -0
  164. package/esri-compat/basemap.js +84 -0
  165. package/esri-compat/bookmarks.d.ts +36 -0
  166. package/esri-compat/bookmarks.d.ts.map +1 -0
  167. package/esri-compat/bookmarks.js +108 -0
  168. package/esri-compat/class-breaks-renderer.d.ts +50 -0
  169. package/esri-compat/class-breaks-renderer.d.ts.map +1 -0
  170. package/esri-compat/class-breaks-renderer.js +164 -0
  171. package/esri-compat/color.d.ts +22 -0
  172. package/esri-compat/color.d.ts.map +1 -0
  173. package/esri-compat/color.js +106 -0
  174. package/esri-compat/controls.d.ts +174 -0
  175. package/esri-compat/controls.d.ts.map +1 -0
  176. package/esri-compat/controls.js +479 -0
  177. package/esri-compat/coordinate-conversion.d.ts +41 -0
  178. package/esri-compat/coordinate-conversion.d.ts.map +1 -0
  179. package/esri-compat/coordinate-conversion.js +125 -0
  180. package/esri-compat/directions.d.ts +45 -0
  181. package/esri-compat/directions.d.ts.map +1 -0
  182. package/esri-compat/directions.js +123 -0
  183. package/esri-compat/editor.d.ts +47 -0
  184. package/esri-compat/editor.d.ts.map +1 -0
  185. package/esri-compat/editor.js +170 -0
  186. package/esri-compat/esri-config.d.ts +16 -0
  187. package/esri-compat/esri-config.d.ts.map +1 -0
  188. package/esri-compat/esri-config.js +23 -0
  189. package/esri-compat/esri-request.d.ts +17 -0
  190. package/esri-compat/esri-request.d.ts.map +1 -0
  191. package/esri-compat/esri-request.js +127 -0
  192. package/esri-compat/event-bus.d.ts +106 -0
  193. package/esri-compat/event-bus.d.ts.map +1 -0
  194. package/esri-compat/event-bus.js +90 -0
  195. package/esri-compat/expand.d.ts +36 -0
  196. package/esri-compat/expand.d.ts.map +1 -0
  197. package/esri-compat/expand.js +97 -0
  198. package/esri-compat/extent.d.ts +43 -0
  199. package/esri-compat/extent.d.ts.map +1 -0
  200. package/esri-compat/extent.js +140 -0
  201. package/esri-compat/feature-filter.d.ts +55 -0
  202. package/esri-compat/feature-filter.d.ts.map +1 -0
  203. package/esri-compat/feature-filter.js +109 -0
  204. package/esri-compat/feature-form.d.ts +64 -0
  205. package/esri-compat/feature-form.d.ts.map +1 -0
  206. package/esri-compat/feature-form.js +137 -0
  207. package/esri-compat/feature-layer.d.ts +173 -0
  208. package/esri-compat/feature-layer.d.ts.map +1 -0
  209. package/esri-compat/feature-layer.js +661 -0
  210. package/esri-compat/feature-set.d.ts +32 -0
  211. package/esri-compat/feature-set.d.ts.map +1 -0
  212. package/esri-compat/feature-set.js +80 -0
  213. package/esri-compat/feature-table.d.ts +141 -0
  214. package/esri-compat/feature-table.d.ts.map +1 -0
  215. package/esri-compat/feature-table.js +500 -0
  216. package/esri-compat/feature-templates.d.ts +41 -0
  217. package/esri-compat/feature-templates.d.ts.map +1 -0
  218. package/esri-compat/feature-templates.js +97 -0
  219. package/esri-compat/feature.d.ts +33 -0
  220. package/esri-compat/feature.d.ts.map +1 -0
  221. package/esri-compat/feature.js +83 -0
  222. package/esri-compat/geojson-layer.d.ts +86 -0
  223. package/esri-compat/geojson-layer.d.ts.map +1 -0
  224. package/esri-compat/geojson-layer.js +191 -0
  225. package/esri-compat/geometry-engine.d.ts +107 -0
  226. package/esri-compat/geometry-engine.d.ts.map +1 -0
  227. package/esri-compat/geometry-engine.js +266 -0
  228. package/esri-compat/graphic.d.ts +46 -0
  229. package/esri-compat/graphic.d.ts.map +1 -0
  230. package/esri-compat/graphic.js +103 -0
  231. package/esri-compat/graphics-layer.d.ts +49 -0
  232. package/esri-compat/graphics-layer.d.ts.map +1 -0
  233. package/esri-compat/graphics-layer.js +185 -0
  234. package/esri-compat/group-layer.d.ts +48 -0
  235. package/esri-compat/group-layer.d.ts.map +1 -0
  236. package/esri-compat/group-layer.js +212 -0
  237. package/esri-compat/identify.d.ts +71 -0
  238. package/esri-compat/identify.d.ts.map +1 -0
  239. package/esri-compat/identify.js +299 -0
  240. package/esri-compat/identity-manager.d.ts +31 -0
  241. package/esri-compat/identity-manager.d.ts.map +1 -0
  242. package/esri-compat/identity-manager.js +115 -0
  243. package/esri-compat/imagery-layer.d.ts +78 -0
  244. package/esri-compat/imagery-layer.d.ts.map +1 -0
  245. package/esri-compat/imagery-layer.js +167 -0
  246. package/esri-compat/label-class.d.ts +31 -0
  247. package/esri-compat/label-class.d.ts.map +1 -0
  248. package/esri-compat/label-class.js +102 -0
  249. package/esri-compat/layer-list.d.ts +77 -0
  250. package/esri-compat/layer-list.d.ts.map +1 -0
  251. package/esri-compat/layer-list.js +342 -0
  252. package/esri-compat/legend.d.ts +53 -0
  253. package/esri-compat/legend.d.ts.map +1 -0
  254. package/esri-compat/legend.js +254 -0
  255. package/esri-compat/map-image-layer.d.ts +162 -0
  256. package/esri-compat/map-image-layer.d.ts.map +1 -0
  257. package/esri-compat/map-image-layer.js +709 -0
  258. package/esri-compat/map-view.d.ts +323 -0
  259. package/esri-compat/map-view.d.ts.map +1 -0
  260. package/esri-compat/map-view.js +1175 -0
  261. package/esri-compat/map.d.ts +47 -0
  262. package/esri-compat/map.d.ts.map +1 -0
  263. package/esri-compat/map.js +209 -0
  264. package/esri-compat/measurement-2d.d.ts +61 -0
  265. package/esri-compat/measurement-2d.d.ts.map +1 -0
  266. package/esri-compat/measurement-2d.js +184 -0
  267. package/esri-compat/measurement.d.ts +45 -0
  268. package/esri-compat/measurement.d.ts.map +1 -0
  269. package/esri-compat/measurement.js +193 -0
  270. package/esri-compat/oauth-info.d.ts +35 -0
  271. package/esri-compat/oauth-info.d.ts.map +1 -0
  272. package/esri-compat/oauth-info.js +115 -0
  273. package/esri-compat/picture-marker-symbol.d.ts +35 -0
  274. package/esri-compat/picture-marker-symbol.d.ts.map +1 -0
  275. package/esri-compat/picture-marker-symbol.js +126 -0
  276. package/esri-compat/point.d.ts +31 -0
  277. package/esri-compat/point.d.ts.map +1 -0
  278. package/esri-compat/point.js +102 -0
  279. package/esri-compat/polygon.d.ts +31 -0
  280. package/esri-compat/polygon.d.ts.map +1 -0
  281. package/esri-compat/polygon.js +107 -0
  282. package/esri-compat/polyline.d.ts +31 -0
  283. package/esri-compat/polyline.d.ts.map +1 -0
  284. package/esri-compat/polyline.js +107 -0
  285. package/esri-compat/popup-template.d.ts +55 -0
  286. package/esri-compat/popup-template.d.ts.map +1 -0
  287. package/esri-compat/popup-template.js +128 -0
  288. package/esri-compat/popup.d.ts +54 -0
  289. package/esri-compat/popup.d.ts.map +1 -0
  290. package/esri-compat/popup.js +312 -0
  291. package/esri-compat/print.d.ts +47 -0
  292. package/esri-compat/print.d.ts.map +1 -0
  293. package/esri-compat/print.js +105 -0
  294. package/esri-compat/query.d.ts +58 -0
  295. package/esri-compat/query.d.ts.map +1 -0
  296. package/esri-compat/query.js +128 -0
  297. package/esri-compat/reactive-utils.d.ts +24 -0
  298. package/esri-compat/reactive-utils.d.ts.map +1 -0
  299. package/esri-compat/reactive-utils.js +193 -0
  300. package/esri-compat/request.d.ts +41 -0
  301. package/esri-compat/request.d.ts.map +1 -0
  302. package/esri-compat/request.js +253 -0
  303. package/esri-compat/route-layer.d.ts +59 -0
  304. package/esri-compat/route-layer.d.ts.map +1 -0
  305. package/esri-compat/route-layer.js +223 -0
  306. package/esri-compat/route-task.d.ts +88 -0
  307. package/esri-compat/route-task.d.ts.map +1 -0
  308. package/esri-compat/route-task.js +225 -0
  309. package/esri-compat/scene-view.d.ts +41 -0
  310. package/esri-compat/scene-view.d.ts.map +1 -0
  311. package/esri-compat/scene-view.js +68 -0
  312. package/esri-compat/search.d.ts +112 -0
  313. package/esri-compat/search.d.ts.map +1 -0
  314. package/esri-compat/search.js +820 -0
  315. package/esri-compat/simple-fill-symbol.d.ts +27 -0
  316. package/esri-compat/simple-fill-symbol.d.ts.map +1 -0
  317. package/esri-compat/simple-fill-symbol.js +85 -0
  318. package/esri-compat/simple-line-symbol.d.ts +27 -0
  319. package/esri-compat/simple-line-symbol.d.ts.map +1 -0
  320. package/esri-compat/simple-line-symbol.js +85 -0
  321. package/esri-compat/simple-marker-symbol.d.ts +29 -0
  322. package/esri-compat/simple-marker-symbol.d.ts.map +1 -0
  323. package/esri-compat/simple-marker-symbol.js +92 -0
  324. package/esri-compat/simple-renderer.d.ts +29 -0
  325. package/esri-compat/simple-renderer.d.ts.map +1 -0
  326. package/esri-compat/simple-renderer.js +92 -0
  327. package/esri-compat/sketch.d.ts +64 -0
  328. package/esri-compat/sketch.d.ts.map +1 -0
  329. package/esri-compat/sketch.js +227 -0
  330. package/esri-compat/spatial-reference.d.ts +31 -0
  331. package/esri-compat/spatial-reference.d.ts.map +1 -0
  332. package/esri-compat/spatial-reference.js +102 -0
  333. package/esri-compat/swipe.d.ts +34 -0
  334. package/esri-compat/swipe.d.ts.map +1 -0
  335. package/esri-compat/swipe.js +93 -0
  336. package/esri-compat/table-list.d.ts +36 -0
  337. package/esri-compat/table-list.d.ts.map +1 -0
  338. package/esri-compat/table-list.js +126 -0
  339. package/esri-compat/text-symbol.d.ts +37 -0
  340. package/esri-compat/text-symbol.d.ts.map +1 -0
  341. package/esri-compat/text-symbol.js +123 -0
  342. package/esri-compat/tile-layer.d.ts +52 -0
  343. package/esri-compat/tile-layer.d.ts.map +1 -0
  344. package/esri-compat/tile-layer.js +168 -0
  345. package/esri-compat/time-slider.d.ts +70 -0
  346. package/esri-compat/time-slider.d.ts.map +1 -0
  347. package/esri-compat/time-slider.js +208 -0
  348. package/esri-compat/track.d.ts +51 -0
  349. package/esri-compat/track.d.ts.map +1 -0
  350. package/esri-compat/track.js +174 -0
  351. package/esri-compat/unique-value-renderer.d.ts +41 -0
  352. package/esri-compat/unique-value-renderer.d.ts.map +1 -0
  353. package/esri-compat/unique-value-renderer.js +127 -0
  354. package/esri-compat/url.d.ts +13 -0
  355. package/esri-compat/url.d.ts.map +1 -0
  356. package/esri-compat/url.js +68 -0
  357. package/esri-compat/vector-tile-layer.d.ts +47 -0
  358. package/esri-compat/vector-tile-layer.d.ts.map +1 -0
  359. package/esri-compat/vector-tile-layer.js +130 -0
  360. package/esri-compat/web-map.d.ts +14 -0
  361. package/esri-compat/web-map.d.ts.map +1 -0
  362. package/esri-compat/web-map.js +24 -0
  363. package/esri-compat/wfs-layer.d.ts +64 -0
  364. package/esri-compat/wfs-layer.d.ts.map +1 -0
  365. package/esri-compat/wfs-layer.js +145 -0
  366. package/esri-compat/wms-layer.d.ts +76 -0
  367. package/esri-compat/wms-layer.d.ts.map +1 -0
  368. package/esri-compat/wms-layer.js +157 -0
  369. package/exploration/context.d.ts +25 -0
  370. package/exploration/context.d.ts.map +1 -0
  371. package/exploration/context.js +396 -0
  372. package/exploration/index.d.ts +27 -0
  373. package/exploration/index.d.ts.map +1 -0
  374. package/exploration/index.js +24 -0
  375. package/exploration/presets.d.ts +27 -0
  376. package/exploration/presets.d.ts.map +1 -0
  377. package/exploration/presets.js +114 -0
  378. package/exploration/reducer.d.ts +23 -0
  379. package/exploration/reducer.d.ts.map +1 -0
  380. package/exploration/reducer.js +332 -0
  381. package/exploration/selection.d.ts +25 -0
  382. package/exploration/selection.d.ts.map +1 -0
  383. package/exploration/selection.js +34 -0
  384. package/exploration/selectors.d.ts +56 -0
  385. package/exploration/selectors.d.ts.map +1 -0
  386. package/exploration/selectors.js +110 -0
  387. package/exploration/types.d.ts +294 -0
  388. package/exploration/types.d.ts.map +1 -0
  389. package/exploration/types.js +33 -0
  390. package/expr/expression.d.ts +457 -0
  391. package/expr/expression.d.ts.map +1 -0
  392. package/expr/expression.js +663 -0
  393. package/expr/index.d.ts +32 -0
  394. package/expr/index.d.ts.map +1 -0
  395. package/expr/index.js +30 -0
  396. package/gen/honua/v1/feature_service_pb.d.ts +918 -0
  397. package/gen/honua/v1/feature_service_pb.d.ts.map +1 -0
  398. package/gen/honua/v1/feature_service_pb.js +375 -0
  399. package/generated-app/errors.d.ts +41 -0
  400. package/generated-app/errors.d.ts.map +1 -0
  401. package/generated-app/errors.js +41 -0
  402. package/generated-app/index.d.ts +17 -0
  403. package/generated-app/index.d.ts.map +1 -0
  404. package/generated-app/index.js +12 -0
  405. package/generated-app/manifest.d.ts +183 -0
  406. package/generated-app/manifest.d.ts.map +1 -0
  407. package/generated-app/manifest.js +14 -0
  408. package/generated-app/projection.d.ts +44 -0
  409. package/generated-app/projection.d.ts.map +1 -0
  410. package/generated-app/projection.js +234 -0
  411. package/generated-app/runtime.d.ts +215 -0
  412. package/generated-app/runtime.d.ts.map +1 -0
  413. package/generated-app/runtime.js +1196 -0
  414. package/interactions/detail-model.d.ts +54 -0
  415. package/interactions/detail-model.d.ts.map +1 -0
  416. package/interactions/detail-model.js +105 -0
  417. package/interactions/exploration-bindings.d.ts +120 -0
  418. package/interactions/exploration-bindings.d.ts.map +1 -0
  419. package/interactions/exploration-bindings.js +218 -0
  420. package/interactions/feature-state.d.ts +144 -0
  421. package/interactions/feature-state.d.ts.map +1 -0
  422. package/interactions/feature-state.js +169 -0
  423. package/interactions/hit-test.d.ts +112 -0
  424. package/interactions/hit-test.d.ts.map +1 -0
  425. package/interactions/hit-test.js +291 -0
  426. package/interactions/index.d.ts +31 -0
  427. package/interactions/index.d.ts.map +1 -0
  428. package/interactions/index.js +24 -0
  429. package/interactions/share-state.d.ts +36 -0
  430. package/interactions/share-state.d.ts.map +1 -0
  431. package/interactions/share-state.js +123 -0
  432. package/map/feature-service-adapter.d.ts +138 -0
  433. package/map/feature-service-adapter.d.ts.map +1 -0
  434. package/map/feature-service-adapter.js +279 -0
  435. package/map/honua-map.d.ts +203 -0
  436. package/map/honua-map.d.ts.map +1 -0
  437. package/map/honua-map.js +347 -0
  438. package/map/index.d.ts +27 -0
  439. package/map/index.d.ts.map +1 -0
  440. package/map/index.js +22 -0
  441. package/map/maplibre-target.d.ts +103 -0
  442. package/map/maplibre-target.d.ts.map +1 -0
  443. package/map/maplibre-target.js +164 -0
  444. package/map/webmap-maplibre.d.ts +60 -0
  445. package/map/webmap-maplibre.d.ts.map +1 -0
  446. package/map/webmap-maplibre.js +212 -0
  447. package/package.json +37 -0
  448. package/react/context.d.ts +32 -0
  449. package/react/context.d.ts.map +1 -0
  450. package/react/context.js +19 -0
  451. package/react/honua-layer.d.ts +35 -0
  452. package/react/honua-layer.d.ts.map +1 -0
  453. package/react/honua-layer.js +47 -0
  454. package/react/honua-map.d.ts +83 -0
  455. package/react/honua-map.d.ts.map +1 -0
  456. package/react/honua-map.js +109 -0
  457. package/react/honua-popup.d.ts +26 -0
  458. package/react/honua-popup.d.ts.map +1 -0
  459. package/react/honua-popup.js +34 -0
  460. package/react/hooks.d.ts +127 -0
  461. package/react/hooks.d.ts.map +1 -0
  462. package/react/hooks.js +206 -0
  463. package/react/index.d.ts +42 -0
  464. package/react/index.d.ts.map +1 -0
  465. package/react/index.js +34 -0
  466. package/react/provider.d.ts +36 -0
  467. package/react/provider.d.ts.map +1 -0
  468. package/react/provider.js +35 -0
  469. package/react/query-cache.d.ts +76 -0
  470. package/react/query-cache.d.ts.map +1 -0
  471. package/react/query-cache.js +188 -0
  472. package/runtime/diff.d.ts +31 -0
  473. package/runtime/diff.d.ts.map +1 -0
  474. package/runtime/diff.js +143 -0
  475. package/runtime/errors.d.ts +40 -0
  476. package/runtime/errors.d.ts.map +1 -0
  477. package/runtime/errors.js +35 -0
  478. package/runtime/index.d.ts +59 -0
  479. package/runtime/index.d.ts.map +1 -0
  480. package/runtime/index.js +43 -0
  481. package/runtime/legend.d.ts +23 -0
  482. package/runtime/legend.d.ts.map +1 -0
  483. package/runtime/legend.js +38 -0
  484. package/runtime/load-package.d.ts +125 -0
  485. package/runtime/load-package.d.ts.map +1 -0
  486. package/runtime/load-package.js +264 -0
  487. package/runtime/map-package-fetch.d.ts +107 -0
  488. package/runtime/map-package-fetch.d.ts.map +1 -0
  489. package/runtime/map-package-fetch.js +336 -0
  490. package/runtime/map-package-realtime.d.ts +169 -0
  491. package/runtime/map-package-realtime.d.ts.map +1 -0
  492. package/runtime/map-package-realtime.js +350 -0
  493. package/runtime/map-package-validation.d.ts +43 -0
  494. package/runtime/map-package-validation.d.ts.map +1 -0
  495. package/runtime/map-package-validation.js +269 -0
  496. package/runtime/map-package-watch.d.ts +78 -0
  497. package/runtime/map-package-watch.d.ts.map +1 -0
  498. package/runtime/map-package-watch.js +695 -0
  499. package/runtime/map-package.d.ts +167 -0
  500. package/runtime/map-package.d.ts.map +1 -0
  501. package/runtime/map-package.js +15 -0
  502. package/runtime/ogc-styles.d.ts +110 -0
  503. package/runtime/ogc-styles.d.ts.map +1 -0
  504. package/runtime/ogc-styles.js +195 -0
  505. package/runtime/popups.d.ts +62 -0
  506. package/runtime/popups.d.ts.map +1 -0
  507. package/runtime/popups.js +95 -0
  508. package/runtime/query-tiles.d.ts +217 -0
  509. package/runtime/query-tiles.d.ts.map +1 -0
  510. package/runtime/query-tiles.js +801 -0
  511. package/runtime/runtime.d.ts +243 -0
  512. package/runtime/runtime.d.ts.map +1 -0
  513. package/runtime/runtime.js +1147 -0
  514. package/runtime/source-bridge.d.ts +99 -0
  515. package/runtime/source-bridge.d.ts.map +1 -0
  516. package/runtime/source-bridge.js +401 -0
  517. package/runtime/style-compose.d.ts +46 -0
  518. package/runtime/style-compose.d.ts.map +1 -0
  519. package/runtime/style-compose.js +144 -0
  520. package/runtime/style-interactions.d.ts +141 -0
  521. package/runtime/style-interactions.d.ts.map +1 -0
  522. package/runtime/style-interactions.js +574 -0
  523. package/runtime/style-spec-validation.d.ts +23 -0
  524. package/runtime/style-spec-validation.d.ts.map +1 -0
  525. package/runtime/style-spec-validation.js +357 -0
  526. package/studio/capability-manifest.d.ts +285 -0
  527. package/studio/capability-manifest.d.ts.map +1 -0
  528. package/studio/capability-manifest.js +59 -0
  529. package/studio/chart-spec.d.ts +85 -0
  530. package/studio/chart-spec.d.ts.map +1 -0
  531. package/studio/chart-spec.js +106 -0
  532. package/studio/index.d.ts +34 -0
  533. package/studio/index.d.ts.map +1 -0
  534. package/studio/index.js +27 -0
  535. package/studio/provenance.d.ts +131 -0
  536. package/studio/provenance.d.ts.map +1 -0
  537. package/studio/provenance.js +39 -0
  538. package/studio/publish.d.ts +64 -0
  539. package/studio/publish.d.ts.map +1 -0
  540. package/studio/publish.js +13 -0
  541. package/studio/types.d.ts +278 -0
  542. package/studio/types.d.ts.map +1 -0
  543. package/studio/types.js +71 -0
  544. package/studio/validate.d.ts +45 -0
  545. package/studio/validate.d.ts.map +1 -0
  546. package/studio/validate.js +255 -0
  547. package/studio/validation.d.ts +112 -0
  548. package/studio/validation.d.ts.map +1 -0
  549. package/studio/validation.js +42 -0
  550. package/style/factory.d.ts +30 -0
  551. package/style/factory.d.ts.map +1 -0
  552. package/style/factory.js +61 -0
  553. package/style/index.d.ts +25 -0
  554. package/style/index.d.ts.map +1 -0
  555. package/style/index.js +24 -0
  556. package/style/specification.d.ts +203 -0
  557. package/style/specification.d.ts.map +1 -0
  558. package/style/specification.js +178 -0
  559. package/style/wms-wmts-resolvers.d.ts +38 -0
  560. package/style/wms-wmts-resolvers.d.ts.map +1 -0
  561. package/style/wms-wmts-resolvers.js +92 -0
  562. package/webmap/contract.d.ts +28 -0
  563. package/webmap/contract.d.ts.map +1 -0
  564. package/webmap/contract.js +130 -0
  565. package/webmap/convert-basemap.d.ts +17 -0
  566. package/webmap/convert-basemap.d.ts.map +1 -0
  567. package/webmap/convert-basemap.js +78 -0
  568. package/webmap/convert-extent.d.ts +17 -0
  569. package/webmap/convert-extent.d.ts.map +1 -0
  570. package/webmap/convert-extent.js +114 -0
  571. package/webmap/convert-label.d.ts +13 -0
  572. package/webmap/convert-label.d.ts.map +1 -0
  573. package/webmap/convert-label.js +125 -0
  574. package/webmap/convert-layer.d.ts +22 -0
  575. package/webmap/convert-layer.d.ts.map +1 -0
  576. package/webmap/convert-layer.js +181 -0
  577. package/webmap/convert-popup.d.ts +34 -0
  578. package/webmap/convert-popup.d.ts.map +1 -0
  579. package/webmap/convert-popup.js +68 -0
  580. package/webmap/convert-renderer.d.ts +17 -0
  581. package/webmap/convert-renderer.d.ts.map +1 -0
  582. package/webmap/convert-renderer.js +161 -0
  583. package/webmap/convert-symbol.d.ts +17 -0
  584. package/webmap/convert-symbol.d.ts.map +1 -0
  585. package/webmap/convert-symbol.js +122 -0
  586. package/webmap/index.d.ts +44 -0
  587. package/webmap/index.d.ts.map +1 -0
  588. package/webmap/index.js +33 -0
  589. package/webmap/parse.d.ts +25 -0
  590. package/webmap/parse.d.ts.map +1 -0
  591. package/webmap/parse.js +83 -0
  592. package/webmap/types.d.ts +264 -0
  593. package/webmap/types.d.ts.map +1 -0
  594. package/webmap/types.js +13 -0
  595. package/webmap/warnings.d.ts +30 -0
  596. package/webmap/warnings.d.ts.map +1 -0
  597. package/webmap/warnings.js +37 -0
@@ -0,0 +1,1473 @@
1
+ /**
2
+ * CARTO-style widget data models over the canonical `Source` contract.
3
+ *
4
+ * The facade keeps dashboard widgets out of protocol-specific request
5
+ * shapes. It prefers server aggregation when the source advertises it, uses
6
+ * OData `$apply` only when metadata advertises Apply support, and stamps
7
+ * structured degradation reasons whenever it must materialize records on the
8
+ * client.
9
+ *
10
+ * @module
11
+ */
12
+ import { rewriteWhereToOdataFilter } from "../core/odata.js";
13
+ import { buildAnalyticsSourceCacheKey, normalizeAnalyticsSourceDescriptor } from "./analytics-sources.js";
14
+ export const WIDGET_SOURCE_SCHEMA_VERSION = "honua.widget-source.v1";
15
+ const DEFAULT_MAX_CLIENT_ROWS = 10_000;
16
+ const DEFAULT_CATEGORY_LIMIT = 25;
17
+ const DEFAULT_TOP_VALUES_LIMIT = 10;
18
+ const DEFAULT_HISTOGRAM_BINS = 10;
19
+ const MAX_HISTOGRAM_BINS = 200;
20
+ const DEFAULT_TIME_SERIES_INTERVAL = { unit: "day", step: 1, timezone: "UTC" };
21
+ const MAX_TIME_SERIES_BUCKETS = 500;
22
+ export function createWidgetSource(source, options = {}) {
23
+ return {
24
+ source,
25
+ count: (request = {}) => count(source, options, request),
26
+ formula: (request) => formula(source, options, request),
27
+ categories: (request) => categories(source, options, request, "categories"),
28
+ histogram: (request) => histogram(source, options, request),
29
+ timeSeries: (request) => timeSeries(source, options, request),
30
+ range: (request) => range(source, options, request),
31
+ topValues: (request) => topValues(source, options, request),
32
+ };
33
+ }
34
+ export const widgetSource = createWidgetSource;
35
+ async function count(source, options, request) {
36
+ throwIfAborted(request.signal);
37
+ const field = request.field ?? "*";
38
+ const alias = "widget_count";
39
+ const resolved = resolveWidgetQuery(source, request);
40
+ const odata = await tryOdataApply(source, request.signal);
41
+ let odataFallbackDegraded = [...(odata.degraded ?? [])];
42
+ if (odata.supported) {
43
+ const attempt = await tryRunOdataApply(source, odata.adapter, `aggregate($count as ${alias})`, resolved, request.signal);
44
+ if (attempt.rows) {
45
+ const value = numeric(attempt.rows[0]?.[alias]) ?? 0;
46
+ return {
47
+ ...baseResponse(source, "count", "server", request, resolved, options, [
48
+ ...(odata.degraded ?? []),
49
+ ...(attempt.degraded ?? []),
50
+ ]),
51
+ value,
52
+ label: "Count",
53
+ };
54
+ }
55
+ odataFallbackDegraded = [...odataFallbackDegraded, ...(attempt.degraded ?? [])];
56
+ }
57
+ if (source.capabilities.has("queryAggregate")) {
58
+ const result = await source.queryAggregate({
59
+ ...resolved.query,
60
+ aggregation: { metrics: [{ fn: "count", field, alias }] },
61
+ signal: request.signal ?? resolved.query.signal,
62
+ });
63
+ const value = numeric(result.aggregateRows?.[0]?.[alias]) ?? 0;
64
+ return {
65
+ ...baseResponse(source, "count", "server", request, resolved, options, result.degraded),
66
+ value,
67
+ label: "Count",
68
+ };
69
+ }
70
+ const materialized = await materialize(source, options, request, resolved, [field === "*" ? undefined : field], odataFallbackDegraded);
71
+ const value = materialized.result.totalCount ?? materialized.features.length;
72
+ return {
73
+ ...baseResponse(source, "count", "client", request, resolved, options, materialized.degraded),
74
+ value,
75
+ label: "Count",
76
+ };
77
+ }
78
+ async function formula(source, options, request) {
79
+ throwIfAborted(request.signal);
80
+ const alias = metricAlias(request.metric);
81
+ const resolved = resolveWidgetQuery(source, request);
82
+ const odata = await tryOdataApply(source, request.signal);
83
+ let odataFallbackDegraded = [...(odata.degraded ?? [])];
84
+ if (odata.supported && odataMetricSupported(request.metric.fn)) {
85
+ const attempt = await tryRunOdataApply(source, odata.adapter, `aggregate(${odataAggregateExpression(request.metric, alias)})`, resolved, request.signal);
86
+ if (attempt.rows) {
87
+ return {
88
+ ...baseResponse(source, "formula", "server", request, resolved, options, [
89
+ ...(odata.degraded ?? []),
90
+ ...(attempt.degraded ?? []),
91
+ ]),
92
+ value: nullableNumeric(attempt.rows[0]?.[alias]),
93
+ metric: request.metric,
94
+ label: alias,
95
+ };
96
+ }
97
+ odataFallbackDegraded = [...odataFallbackDegraded, ...(attempt.degraded ?? [])];
98
+ }
99
+ if (source.capabilities.has("queryAggregate")) {
100
+ const result = await source.queryAggregate({
101
+ ...resolved.query,
102
+ aggregation: { metrics: [{ ...request.metric, alias }] },
103
+ signal: request.signal ?? resolved.query.signal,
104
+ });
105
+ return {
106
+ ...baseResponse(source, "formula", "server", request, resolved, options, result.degraded),
107
+ value: nullableNumeric(result.aggregateRows?.[0]?.[alias]),
108
+ metric: request.metric,
109
+ label: alias,
110
+ };
111
+ }
112
+ const materialized = await materialize(source, options, request, resolved, [request.metric.field], odataFallbackDegraded);
113
+ return {
114
+ ...baseResponse(source, "formula", "client", request, resolved, options, materialized.degraded),
115
+ value: computeMetric(materialized.features, request.metric),
116
+ metric: request.metric,
117
+ label: alias,
118
+ };
119
+ }
120
+ async function categories(source, options, request, kind) {
121
+ throwIfAborted(request.signal);
122
+ const limit = boundedLimit(request.limit, DEFAULT_CATEGORY_LIMIT);
123
+ const resolved = resolveWidgetQuery(source, request);
124
+ const metric = request.metric;
125
+ const metricField = metric?.field && metric.field !== "*" ? metric.field : undefined;
126
+ const countAlias = "count";
127
+ const metricValueAlias = metric ? metricAlias(metric, "metric") : undefined;
128
+ const odata = await tryOdataApply(source, request.signal);
129
+ let odataFallbackDegraded = [...(odata.degraded ?? [])];
130
+ if (odata.supported && (!metric || odataMetricSupported(metric.fn))) {
131
+ const aggregateParts = [`$count as ${countAlias}`];
132
+ if (metric && metricValueAlias)
133
+ aggregateParts.push(odataAggregateExpression(metric, metricValueAlias));
134
+ const attempt = await tryRunOdataApply(source, odata.adapter, `groupby((${request.field}),aggregate(${aggregateParts.join(",")}))`, resolved, request.signal);
135
+ if (attempt.rows) {
136
+ return {
137
+ ...baseResponse(source, kind, "server", request, resolved, options, [
138
+ ...(odata.degraded ?? []),
139
+ ...(attempt.degraded ?? []),
140
+ ]),
141
+ field: request.field,
142
+ buckets: categoryBucketsFromRows(attempt.rows, request.field, countAlias, metricValueAlias, request.orderBy, limit),
143
+ };
144
+ }
145
+ odataFallbackDegraded = [...odataFallbackDegraded, ...(attempt.degraded ?? [])];
146
+ }
147
+ if (source.capabilities.has("queryAggregate")) {
148
+ const metrics = [{ fn: "count", field: "*", alias: countAlias }];
149
+ if (metric && metricValueAlias)
150
+ metrics.push({ ...metric, alias: metricValueAlias });
151
+ const result = await source.queryAggregate({
152
+ ...resolved.query,
153
+ aggregation: { groupBy: [request.field], metrics },
154
+ signal: request.signal ?? resolved.query.signal,
155
+ });
156
+ return {
157
+ ...baseResponse(source, kind, "server", request, resolved, options, result.degraded),
158
+ field: request.field,
159
+ buckets: categoryBucketsFromRows(result.aggregateRows ?? [], request.field, countAlias, metricValueAlias, request.orderBy, limit),
160
+ };
161
+ }
162
+ const materialized = await materialize(source, options, request, resolved, [request.field, metricField], odataFallbackDegraded);
163
+ return {
164
+ ...baseResponse(source, kind, "client", request, resolved, options, materialized.degraded),
165
+ field: request.field,
166
+ buckets: categoryBucketsFromFeatures(materialized.features, request.field, metric, request.orderBy, limit),
167
+ };
168
+ }
169
+ async function topValues(source, options, request) {
170
+ const result = await categories(source, options, {
171
+ ...request,
172
+ limit: request.limit ?? DEFAULT_TOP_VALUES_LIMIT,
173
+ orderBy: request.metric ? "metric-desc" : "count-desc",
174
+ }, "categories");
175
+ return {
176
+ ...result,
177
+ kind: "top-values",
178
+ values: result.buckets,
179
+ };
180
+ }
181
+ async function histogram(source, options, request) {
182
+ throwIfAborted(request.signal);
183
+ const resolved = resolveWidgetQuery(source, request, histogramRangeWhere(request.field, request.min, request.max));
184
+ const histogramSpec = aggregationHistogramSpec(request);
185
+ const countAlias = "count";
186
+ const bucketAlias = histogramSpec.aliases?.bucket ?? "bucket";
187
+ const odata = await tryOdataApply(source, request.signal);
188
+ let fallbackDegraded = [...(odata.degraded ?? [])];
189
+ if (odata.supported) {
190
+ const range = await resolveHistogramRangeFromOdata(source, odata.adapter, request, resolved, request.signal);
191
+ if (range.value) {
192
+ const attempt = await tryRunOdataApply(source, odata.adapter, odataHistogramTransformation(request.field, range.value.min, range.value.max, histogramSpec.bins, bucketAlias), resolved, request.signal);
193
+ if (attempt.rows) {
194
+ const bins = histogramBinsFromRows(attempt.rows, {
195
+ min: range.value.min,
196
+ max: range.value.max,
197
+ bins: histogramSpec.bins,
198
+ bucketAlias,
199
+ countAlias,
200
+ minAlias: histogramSpec.aliases?.min,
201
+ maxAlias: histogramSpec.aliases?.max,
202
+ labelAlias: histogramSpec.aliases?.label,
203
+ });
204
+ return {
205
+ ...baseResponse(source, "histogram", "server", request, resolved, options, [
206
+ ...(odata.degraded ?? []),
207
+ ...(range.degraded ?? []),
208
+ ...(attempt.degraded ?? []),
209
+ ]),
210
+ field: request.field,
211
+ min: bins.min,
212
+ max: bins.max,
213
+ bins: bins.bins,
214
+ };
215
+ }
216
+ fallbackDegraded = [...fallbackDegraded, ...(range.degraded ?? []), ...(attempt.degraded ?? [])];
217
+ }
218
+ else {
219
+ fallbackDegraded = [...fallbackDegraded, ...(range.degraded ?? [])];
220
+ }
221
+ }
222
+ const canonical = await tryCanonicalHistogramPushdown(source, request, resolved, histogramSpec, countAlias, bucketAlias);
223
+ if (canonical.rows) {
224
+ const bins = histogramBinsFromRows(canonical.rows, {
225
+ min: request.min ?? canonical.min,
226
+ max: request.max ?? canonical.max,
227
+ bins: histogramSpec.bins,
228
+ bucketAlias,
229
+ countAlias,
230
+ minAlias: histogramSpec.aliases?.min,
231
+ maxAlias: histogramSpec.aliases?.max,
232
+ labelAlias: histogramSpec.aliases?.label,
233
+ });
234
+ return {
235
+ ...baseResponse(source, "histogram", "server", request, resolved, options, canonical.degraded),
236
+ field: request.field,
237
+ min: bins.min,
238
+ max: bins.max,
239
+ bins: bins.bins,
240
+ };
241
+ }
242
+ fallbackDegraded = [...fallbackDegraded, ...(canonical.degraded ?? [])];
243
+ const protocol = await tryProtocolHistogramPushdown(source, request, resolved, histogramSpec, countAlias, bucketAlias);
244
+ if (protocol.rows) {
245
+ const bins = histogramBinsFromRows(protocol.rows, {
246
+ min: request.min ?? protocol.min,
247
+ max: request.max ?? protocol.max,
248
+ bins: histogramSpec.bins,
249
+ bucketAlias,
250
+ countAlias,
251
+ minAlias: histogramSpec.aliases?.min,
252
+ maxAlias: histogramSpec.aliases?.max,
253
+ labelAlias: histogramSpec.aliases?.label,
254
+ });
255
+ return {
256
+ ...baseResponse(source, "histogram", "server", request, resolved, options, protocol.degraded),
257
+ field: request.field,
258
+ min: bins.min,
259
+ max: bins.max,
260
+ bins: bins.bins,
261
+ };
262
+ }
263
+ fallbackDegraded = [...fallbackDegraded, ...(protocol.degraded ?? [])];
264
+ const materialized = await materialize(source, options, request, resolved, [request.field], [
265
+ {
266
+ capability: "queryAggregate",
267
+ reason: "No compatible histogram bucketization pushdown was advertised; values were materialized client-side.",
268
+ protocol: source.descriptor.protocol,
269
+ sourceId: source.descriptor.id,
270
+ },
271
+ ...fallbackDegraded,
272
+ ]);
273
+ const bins = histogramBins(materialized.features, request);
274
+ return {
275
+ ...baseResponse(source, "histogram", "client", request, resolved, options, materialized.degraded),
276
+ field: request.field,
277
+ min: bins.min,
278
+ max: bins.max,
279
+ bins: bins.bins,
280
+ };
281
+ }
282
+ async function timeSeries(source, options, request) {
283
+ throwIfAborted(request.signal);
284
+ const interval = normalizeTimeSeriesInterval(request.interval);
285
+ const rangeWhere = timeSeriesRangeWhere(request.field, request.start, request.end);
286
+ const resolved = resolveWidgetQuery(source, request, rangeWhere);
287
+ const countAlias = "count";
288
+ const metric = request.metric;
289
+ const metricAliasValue = metric ? metricAlias(metric, "metric") : undefined;
290
+ const timeSeriesSpec = aggregationTimeSeriesSpec(request, interval);
291
+ const startAlias = timeSeriesSpec.aliases?.start ?? "intervalStart";
292
+ const endAlias = timeSeriesSpec.aliases?.end ?? "intervalEnd";
293
+ const odata = await tryOdataApply(source, request.signal);
294
+ let fallbackDegraded = [...(odata.degraded ?? [])];
295
+ if (odata.supported && (!metric || odataMetricSupported(metric.fn))) {
296
+ const aggregateParts = [`$count as ${countAlias}`];
297
+ if (metric && metricAliasValue)
298
+ aggregateParts.push(odataAggregateExpression(metric, metricAliasValue));
299
+ const attempt = await tryRunOdataApply(source, odata.adapter, `${odataTimeBucketTransformation(request.field, interval, startAlias)}/groupby((${startAlias}),aggregate(${aggregateParts.join(",")}))`, resolved, request.signal);
300
+ if (attempt.rows) {
301
+ const buckets = timeSeriesBucketsFromRows(attempt.rows, {
302
+ interval,
303
+ startAlias,
304
+ endAlias,
305
+ labelAlias: timeSeriesSpec.aliases?.label,
306
+ countAlias,
307
+ metricAlias: metricAliasValue,
308
+ fillMissing: request.fillMissing,
309
+ start: request.start,
310
+ end: request.end,
311
+ });
312
+ return {
313
+ ...baseResponse(source, "time-series", "server", request, resolved, options, [
314
+ ...(odata.degraded ?? []),
315
+ ...(attempt.degraded ?? []),
316
+ ]),
317
+ field: request.field,
318
+ interval,
319
+ buckets: buckets.buckets,
320
+ totalCount: buckets.totalCount,
321
+ ...(metric ? { metric } : {}),
322
+ };
323
+ }
324
+ fallbackDegraded = [...fallbackDegraded, ...(attempt.degraded ?? [])];
325
+ }
326
+ const canonical = await tryCanonicalTimeSeriesPushdown(source, request, resolved, timeSeriesSpec, countAlias, metricAliasValue);
327
+ if (canonical.rows) {
328
+ const buckets = timeSeriesBucketsFromRows(canonical.rows, {
329
+ interval,
330
+ startAlias,
331
+ endAlias,
332
+ labelAlias: timeSeriesSpec.aliases?.label,
333
+ countAlias,
334
+ metricAlias: metricAliasValue,
335
+ fillMissing: request.fillMissing,
336
+ start: request.start,
337
+ end: request.end,
338
+ });
339
+ return {
340
+ ...baseResponse(source, "time-series", "server", request, resolved, options, canonical.degraded),
341
+ field: request.field,
342
+ interval,
343
+ buckets: buckets.buckets,
344
+ totalCount: buckets.totalCount,
345
+ ...(metric ? { metric } : {}),
346
+ };
347
+ }
348
+ fallbackDegraded = [...fallbackDegraded, ...(canonical.degraded ?? [])];
349
+ const protocol = await tryProtocolTimeSeriesPushdown(source, request, resolved, timeSeriesSpec, countAlias, metricAliasValue);
350
+ if (protocol.rows) {
351
+ const buckets = timeSeriesBucketsFromRows(protocol.rows, {
352
+ interval,
353
+ startAlias,
354
+ endAlias,
355
+ labelAlias: timeSeriesSpec.aliases?.label,
356
+ countAlias,
357
+ metricAlias: metricAliasValue,
358
+ fillMissing: request.fillMissing,
359
+ start: request.start,
360
+ end: request.end,
361
+ });
362
+ return {
363
+ ...baseResponse(source, "time-series", "server", request, resolved, options, protocol.degraded),
364
+ field: request.field,
365
+ interval,
366
+ buckets: buckets.buckets,
367
+ totalCount: buckets.totalCount,
368
+ ...(metric ? { metric } : {}),
369
+ };
370
+ }
371
+ fallbackDegraded = [...fallbackDegraded, ...(protocol.degraded ?? [])];
372
+ const metricField = metric?.field && metric.field !== "*" ? metric.field : undefined;
373
+ const materialized = await materialize(source, options, request, resolved, [request.field, metricField], [
374
+ {
375
+ capability: "queryAggregate",
376
+ reason: "No compatible time-series interval pushdown was advertised; records were materialized client-side.",
377
+ protocol: source.descriptor.protocol,
378
+ sourceId: source.descriptor.id,
379
+ },
380
+ ...fallbackDegraded,
381
+ ]);
382
+ const buckets = timeSeriesBucketsFromFeatures(materialized.features, request, interval);
383
+ return {
384
+ ...baseResponse(source, "time-series", "client", request, resolved, options, materialized.degraded),
385
+ field: request.field,
386
+ interval,
387
+ buckets: buckets.buckets,
388
+ totalCount: buckets.totalCount,
389
+ ...(metric ? { metric } : {}),
390
+ };
391
+ }
392
+ async function range(source, options, request) {
393
+ throwIfAborted(request.signal);
394
+ const resolved = resolveWidgetQuery(source, request);
395
+ const minAlias = `min_${request.field}`;
396
+ const maxAlias = `max_${request.field}`;
397
+ const countAlias = "count";
398
+ const odata = await tryOdataApply(source, request.signal);
399
+ let odataFallbackDegraded = [...(odata.degraded ?? [])];
400
+ if (odata.supported) {
401
+ const attempt = await tryRunOdataApply(source, odata.adapter, `aggregate(${request.field} with min as ${minAlias},${request.field} with max as ${maxAlias},$count as ${countAlias})`, resolved, request.signal);
402
+ if (attempt.rows) {
403
+ const row = attempt.rows[0] ?? {};
404
+ return {
405
+ ...baseResponse(source, "range", "server", request, resolved, options, [
406
+ ...(odata.degraded ?? []),
407
+ ...(attempt.degraded ?? []),
408
+ ]),
409
+ field: request.field,
410
+ min: nullableNumeric(row[minAlias]),
411
+ max: nullableNumeric(row[maxAlias]),
412
+ count: numeric(row[countAlias]) ?? 0,
413
+ };
414
+ }
415
+ odataFallbackDegraded = [...odataFallbackDegraded, ...(attempt.degraded ?? [])];
416
+ }
417
+ if (source.capabilities.has("queryAggregate")) {
418
+ const result = await source.queryAggregate({
419
+ ...resolved.query,
420
+ aggregation: {
421
+ metrics: [
422
+ { fn: "min", field: request.field, alias: minAlias },
423
+ { fn: "max", field: request.field, alias: maxAlias },
424
+ { fn: "count", field: request.field, alias: countAlias },
425
+ ],
426
+ },
427
+ signal: request.signal ?? resolved.query.signal,
428
+ });
429
+ const row = result.aggregateRows?.[0] ?? {};
430
+ return {
431
+ ...baseResponse(source, "range", "server", request, resolved, options, result.degraded),
432
+ field: request.field,
433
+ min: nullableNumeric(row[minAlias]),
434
+ max: nullableNumeric(row[maxAlias]),
435
+ count: numeric(row[countAlias]) ?? 0,
436
+ };
437
+ }
438
+ const materialized = await materialize(source, options, request, resolved, [request.field], odataFallbackDegraded);
439
+ const values = numericValues(materialized.features, request.field);
440
+ return {
441
+ ...baseResponse(source, "range", "client", request, resolved, options, materialized.degraded),
442
+ field: request.field,
443
+ min: values.length > 0 ? Math.min(...values) : null,
444
+ max: values.length > 0 ? Math.max(...values) : null,
445
+ count: values.length,
446
+ };
447
+ }
448
+ function resolveWidgetQuery(source, request, extraWhere) {
449
+ const projection = request.projection;
450
+ const query = request.query ?? {};
451
+ const projectionWhere = compileProjectionWhere(projection?.filters, source.descriptor.id);
452
+ const where = combineWhere(combineWhere(query.where, projectionWhere), extraWhere);
453
+ const spatialFilter = query.spatialFilter ?? projection?.spatialFilter ?? spatialFilterFromExtent(projection?.extent);
454
+ const out = {
455
+ ...query,
456
+ ...(where ? { where } : {}),
457
+ ...(spatialFilter ? { spatialFilter } : {}),
458
+ ...((query.orderBy ?? projection?.orderBy) ? { orderBy: query.orderBy ?? projection?.orderBy } : {}),
459
+ ...((query.outFields ?? projection?.outFields) ? { outFields: query.outFields ?? projection?.outFields } : {}),
460
+ returnGeometry: false,
461
+ ...((request.signal ?? query.signal) ? { signal: request.signal ?? query.signal } : {}),
462
+ };
463
+ return { query: out, ...(where ? { where } : {}) };
464
+ }
465
+ function baseResponse(source, kind, execution, request, resolved, options, degraded) {
466
+ const cache = cacheMetadata(source, kind, request, resolved, options);
467
+ const normalizedDegraded = degraded && degraded.length > 0 ? dedupeDegraded(degraded) : undefined;
468
+ return {
469
+ schemaVersion: WIDGET_SOURCE_SCHEMA_VERSION,
470
+ kind,
471
+ sourceId: source.descriptor.id,
472
+ protocol: source.descriptor.protocol,
473
+ execution,
474
+ serverPushdown: execution === "server",
475
+ cache,
476
+ ...(normalizedDegraded ? { degraded: normalizedDegraded } : {}),
477
+ };
478
+ }
479
+ async function materialize(source, options, request, resolved, fields, extraDegraded = []) {
480
+ throwIfAborted(request.signal);
481
+ const maxRows = maxClientRows(options, request);
482
+ const result = await source.queryAll({
483
+ ...resolved.query,
484
+ outFields: mergeOutFields(resolved.query.outFields, fields),
485
+ pagination: { limit: maxRows + 1 },
486
+ returnGeometry: false,
487
+ signal: request.signal ?? resolved.query.signal,
488
+ });
489
+ throwIfAborted(request.signal);
490
+ const features = result.features.slice(0, maxRows);
491
+ const degraded = [
492
+ {
493
+ capability: "queryAggregate",
494
+ reason: "Widget source evaluated this model client-side because no compatible server aggregate pushdown is available.",
495
+ protocol: source.descriptor.protocol,
496
+ sourceId: source.descriptor.id,
497
+ },
498
+ ...extraDegraded,
499
+ ...(result.degraded ?? []),
500
+ ];
501
+ if (result.exceededTransferLimit || result.features.length > maxRows) {
502
+ degraded.push({
503
+ capability: "queryAggregate",
504
+ reason: `Widget source client-side scan was bounded at ${maxRows} rows; results may be partial.`,
505
+ protocol: source.descriptor.protocol,
506
+ sourceId: source.descriptor.id,
507
+ });
508
+ }
509
+ return { result, features, degraded: dedupeDegraded(degraded) };
510
+ }
511
+ async function tryOdataApply(source, signal) {
512
+ const adapter = source.protocol("odata");
513
+ if (!adapter?.apply || !adapter.metadata)
514
+ return { supported: false };
515
+ throwIfAborted(signal);
516
+ try {
517
+ const metadata = await adapter.metadata(signal ? { signal } : undefined);
518
+ throwIfAborted(signal);
519
+ if (metadata.capabilities?.[adapter.entitySetName]?.apply === true) {
520
+ return { supported: true, adapter };
521
+ }
522
+ return {
523
+ supported: false,
524
+ degraded: [
525
+ {
526
+ capability: "queryAggregate",
527
+ reason: "OData metadata does not advertise ApplySupported; widget source did not use $apply pushdown.",
528
+ protocol: source.descriptor.protocol,
529
+ sourceId: source.descriptor.id,
530
+ },
531
+ ],
532
+ };
533
+ }
534
+ catch (error) {
535
+ throwIfAborted(signal);
536
+ return {
537
+ supported: false,
538
+ degraded: [
539
+ {
540
+ capability: "queryAggregate",
541
+ reason: `OData Apply capability negotiation failed: ${error instanceof Error ? error.message : String(error)}`,
542
+ protocol: source.descriptor.protocol,
543
+ sourceId: source.descriptor.id,
544
+ },
545
+ ],
546
+ };
547
+ }
548
+ }
549
+ async function tryRunOdataApply(source, adapter, transformation, resolved, signal) {
550
+ if (resolved.query.spatialFilter) {
551
+ return {
552
+ degraded: [
553
+ {
554
+ capability: "queryAggregate",
555
+ reason: "OData $apply pushdown cannot combine with spatialFilter yet; widget source used client fallback.",
556
+ protocol: source.descriptor.protocol,
557
+ sourceId: source.descriptor.id,
558
+ },
559
+ ],
560
+ };
561
+ }
562
+ try {
563
+ const filter = resolved.where ? rewriteWhereToOdataFilter(resolved.where) : undefined;
564
+ const result = await adapter.apply(transformation, {
565
+ ...(filter ? { filter } : {}),
566
+ ...(signal ? { signal } : {}),
567
+ });
568
+ return { rows: result.rows };
569
+ }
570
+ catch (error) {
571
+ throwIfAborted(signal);
572
+ return {
573
+ degraded: [
574
+ {
575
+ capability: "queryAggregate",
576
+ reason: `OData $apply pushdown failed: ${error instanceof Error ? error.message : String(error)}`,
577
+ protocol: source.descriptor.protocol,
578
+ sourceId: source.descriptor.id,
579
+ },
580
+ ],
581
+ };
582
+ }
583
+ }
584
+ async function resolveHistogramRangeFromOdata(source, adapter, request, resolved, signal) {
585
+ if (request.min !== undefined && request.max !== undefined) {
586
+ return { value: { min: request.min, max: request.max } };
587
+ }
588
+ const minAlias = "histogram_min";
589
+ const maxAlias = "histogram_max";
590
+ const attempt = await tryRunOdataApply(source, adapter, `aggregate(${request.field} with min as ${minAlias},${request.field} with max as ${maxAlias})`, resolved, signal);
591
+ if (!attempt.rows)
592
+ return { degraded: attempt.degraded };
593
+ const row = attempt.rows[0] ?? {};
594
+ const min = request.min ?? numeric(row[minAlias]);
595
+ const max = request.max ?? numeric(row[maxAlias]);
596
+ if (min === undefined || max === undefined) {
597
+ return {
598
+ degraded: [
599
+ ...(attempt.degraded ?? []),
600
+ degradedReason(source, "OData $apply histogram pushdown could not determine numeric bucket boundaries; widget source used client fallback."),
601
+ ],
602
+ };
603
+ }
604
+ return { value: { min, max }, degraded: attempt.degraded };
605
+ }
606
+ async function tryCanonicalHistogramPushdown(source, request, resolved, histogramSpec, countAlias, bucketAlias) {
607
+ if (!source.capabilities.has("queryAggregate"))
608
+ return {};
609
+ if (!histogramCapabilityCompatible(source.descriptor.analytics?.histogram, request.field, histogramSpec.bins)) {
610
+ return {};
611
+ }
612
+ const minAlias = histogramSpec.aliases?.min ?? "bucketMin";
613
+ const maxAlias = histogramSpec.aliases?.max ?? "bucketMax";
614
+ try {
615
+ const result = await source.queryAggregate({
616
+ ...resolved.query,
617
+ aggregation: {
618
+ metrics: [
619
+ { fn: "count", field: "*", alias: countAlias },
620
+ { fn: "min", field: request.field, alias: minAlias },
621
+ { fn: "max", field: request.field, alias: maxAlias },
622
+ ],
623
+ histogram: { ...histogramSpec, aliases: { ...histogramSpec.aliases, bucket: bucketAlias } },
624
+ },
625
+ signal: request.signal ?? resolved.query.signal,
626
+ });
627
+ const rows = result.aggregateRows ?? [];
628
+ return {
629
+ rows,
630
+ min: rowsMin(rows, minAlias),
631
+ max: rowsMax(rows, maxAlias),
632
+ degraded: result.degraded,
633
+ };
634
+ }
635
+ catch (error) {
636
+ throwIfAborted(request.signal);
637
+ return {
638
+ degraded: [
639
+ degradedReason(source, `Canonical histogram queryAggregate pushdown failed: ${error instanceof Error ? error.message : String(error)}`),
640
+ ],
641
+ };
642
+ }
643
+ }
644
+ async function tryCanonicalTimeSeriesPushdown(source, request, resolved, timeSeriesSpec, countAlias, metricAliasValue) {
645
+ if (!source.capabilities.has("queryAggregate"))
646
+ return {};
647
+ if (!timeSeriesCapabilityCompatible(source.descriptor.analytics?.timeSeries, request.field, timeSeriesSpec.interval.unit)) {
648
+ return {};
649
+ }
650
+ const metrics = [{ fn: "count", field: "*", alias: countAlias }];
651
+ if (request.metric && metricAliasValue)
652
+ metrics.push({ ...request.metric, alias: metricAliasValue });
653
+ try {
654
+ const result = await source.queryAggregate({
655
+ ...resolved.query,
656
+ aggregation: {
657
+ metrics,
658
+ timeSeries: timeSeriesSpec,
659
+ },
660
+ signal: request.signal ?? resolved.query.signal,
661
+ });
662
+ return { rows: result.aggregateRows ?? [], degraded: result.degraded };
663
+ }
664
+ catch (error) {
665
+ throwIfAborted(request.signal);
666
+ return {
667
+ degraded: [
668
+ degradedReason(source, `Canonical time-series queryAggregate pushdown failed: ${error instanceof Error ? error.message : String(error)}`),
669
+ ],
670
+ };
671
+ }
672
+ }
673
+ async function tryProtocolHistogramPushdown(source, request, resolved, histogramSpec, countAlias, bucketAlias) {
674
+ const adapter = widgetAnalyticsAdapter(source);
675
+ if (!adapter?.histogram)
676
+ return {};
677
+ const metadata = await widgetAnalyticsMetadata(source, adapter, request.signal);
678
+ if (metadata.degraded)
679
+ return { degraded: metadata.degraded };
680
+ if (!histogramCapabilityCompatible(metadata.analytics?.histogram, request.field, histogramSpec.bins))
681
+ return {};
682
+ const minAlias = histogramSpec.aliases?.min ?? "bucketMin";
683
+ const maxAlias = histogramSpec.aliases?.max ?? "bucketMax";
684
+ try {
685
+ const result = await adapter.histogram({
686
+ ...resolved.query,
687
+ aggregation: {
688
+ metrics: [
689
+ { fn: "count", field: "*", alias: countAlias },
690
+ { fn: "min", field: request.field, alias: minAlias },
691
+ { fn: "max", field: request.field, alias: maxAlias },
692
+ ],
693
+ histogram: { ...histogramSpec, aliases: { ...histogramSpec.aliases, bucket: bucketAlias } },
694
+ },
695
+ signal: request.signal ?? resolved.query.signal,
696
+ });
697
+ return {
698
+ rows: result.rows,
699
+ min: rowsMin(result.rows, minAlias),
700
+ max: rowsMax(result.rows, maxAlias),
701
+ degraded: result.degraded,
702
+ };
703
+ }
704
+ catch (error) {
705
+ throwIfAborted(request.signal);
706
+ return {
707
+ degraded: [
708
+ degradedReason(source, `Protocol histogram pushdown failed: ${error instanceof Error ? error.message : String(error)}`),
709
+ ],
710
+ };
711
+ }
712
+ }
713
+ async function tryProtocolTimeSeriesPushdown(source, request, resolved, timeSeriesSpec, countAlias, metricAliasValue) {
714
+ const adapter = widgetAnalyticsAdapter(source);
715
+ if (!adapter?.timeSeries)
716
+ return {};
717
+ const metadata = await widgetAnalyticsMetadata(source, adapter, request.signal);
718
+ if (metadata.degraded)
719
+ return { degraded: metadata.degraded };
720
+ if (!timeSeriesCapabilityCompatible(metadata.analytics?.timeSeries, request.field, timeSeriesSpec.interval.unit)) {
721
+ return {};
722
+ }
723
+ const metrics = [{ fn: "count", field: "*", alias: countAlias }];
724
+ if (request.metric && metricAliasValue)
725
+ metrics.push({ ...request.metric, alias: metricAliasValue });
726
+ try {
727
+ const result = await adapter.timeSeries({
728
+ ...resolved.query,
729
+ aggregation: { metrics, timeSeries: timeSeriesSpec },
730
+ signal: request.signal ?? resolved.query.signal,
731
+ });
732
+ return { rows: result.rows, degraded: result.degraded };
733
+ }
734
+ catch (error) {
735
+ throwIfAborted(request.signal);
736
+ return {
737
+ degraded: [
738
+ degradedReason(source, `Protocol time-series pushdown failed: ${error instanceof Error ? error.message : String(error)}`),
739
+ ],
740
+ };
741
+ }
742
+ }
743
+ function aggregationHistogramSpec(request) {
744
+ return {
745
+ field: request.field,
746
+ bins: clampInteger(request.bins ?? DEFAULT_HISTOGRAM_BINS, 1, MAX_HISTOGRAM_BINS),
747
+ ...(request.min !== undefined ? { min: request.min } : {}),
748
+ ...(request.max !== undefined ? { max: request.max } : {}),
749
+ boundary: "inclusive-exclusive",
750
+ aliases: {
751
+ bucket: "bucket",
752
+ min: "bucketMin",
753
+ max: "bucketMax",
754
+ label: "label",
755
+ },
756
+ };
757
+ }
758
+ function aggregationTimeSeriesSpec(request, interval) {
759
+ return {
760
+ field: request.field,
761
+ interval,
762
+ ...(request.start !== undefined ? { start: serializeTimeValue(request.start) } : {}),
763
+ ...(request.end !== undefined ? { end: serializeTimeValue(request.end) } : {}),
764
+ aliases: {
765
+ start: "intervalStart",
766
+ end: "intervalEnd",
767
+ label: "label",
768
+ },
769
+ };
770
+ }
771
+ function odataHistogramTransformation(field, min, max, bins, bucketAlias) {
772
+ const width = max === min ? 1 : (max - min) / bins;
773
+ return `compute(floor((${field} sub ${formatOdataNumber(min)}) div ${formatOdataNumber(width)}) as ${bucketAlias})/groupby((${bucketAlias}),aggregate($count as count))`;
774
+ }
775
+ function odataTimeBucketTransformation(field, interval, alias) {
776
+ return `compute(honua.timeBucket(${field},'${interval.unit}',${interval.step},'${interval.timezone.replace(/'/g, "''")}') as ${alias})`;
777
+ }
778
+ function formatOdataNumber(value) {
779
+ return Number.isFinite(value) ? String(value) : "0";
780
+ }
781
+ function widgetAnalyticsAdapter(source) {
782
+ const protocol = source.protocol;
783
+ const candidate = protocol(source.descriptor.protocol);
784
+ if (!candidate || typeof candidate !== "object")
785
+ return undefined;
786
+ const adapter = candidate;
787
+ if (typeof adapter.histogram !== "function" && typeof adapter.timeSeries !== "function")
788
+ return undefined;
789
+ return adapter;
790
+ }
791
+ async function widgetAnalyticsMetadata(source, adapter, signal) {
792
+ if (!adapter.metadata) {
793
+ return {
794
+ degraded: [
795
+ degradedReason(source, "Protocol widget analytics adapter did not expose capability metadata; widget source used client fallback."),
796
+ ],
797
+ };
798
+ }
799
+ try {
800
+ const metadata = await adapter.metadata(signal ? { signal } : undefined);
801
+ const capabilities = metadata.capabilities;
802
+ const analytics = capabilities?.widgets ?? {
803
+ histogram: capabilities?.histogram,
804
+ timeSeries: capabilities?.timeSeries,
805
+ freshness: capabilities?.freshness,
806
+ };
807
+ return { analytics };
808
+ }
809
+ catch (error) {
810
+ throwIfAborted(signal);
811
+ return {
812
+ degraded: [
813
+ degradedReason(source, `Protocol widget analytics capability negotiation failed: ${error instanceof Error ? error.message : String(error)}`),
814
+ ],
815
+ };
816
+ }
817
+ }
818
+ function histogramCapabilityCompatible(capability, field, bins) {
819
+ if (capability === true)
820
+ return true;
821
+ if (capability === undefined || capability === false)
822
+ return false;
823
+ if (capability.fields && !capability.fields.includes(field))
824
+ return false;
825
+ return capability.maxBins === undefined || bins <= capability.maxBins;
826
+ }
827
+ function timeSeriesCapabilityCompatible(capability, field, interval) {
828
+ if (capability === true)
829
+ return true;
830
+ if (capability === undefined || capability === false)
831
+ return false;
832
+ if (capability.fields && !capability.fields.includes(field))
833
+ return false;
834
+ return !capability.intervals || capability.intervals.includes(interval);
835
+ }
836
+ function degradedReason(source, reason) {
837
+ return {
838
+ capability: "queryAggregate",
839
+ reason,
840
+ protocol: source.descriptor.protocol,
841
+ sourceId: source.descriptor.id,
842
+ };
843
+ }
844
+ function compileProjectionWhere(filters, sourceId) {
845
+ const parts = [];
846
+ for (const clause of Object.values(filters ?? {})) {
847
+ if (clause.appliesTo && clause.appliesTo.length > 0 && !clause.appliesTo.includes(sourceId))
848
+ continue;
849
+ const compiled = compileClause(clause);
850
+ if (compiled)
851
+ parts.push(compiled);
852
+ }
853
+ return parts.length > 0 ? parts.map((part) => `(${part})`).join(" AND ") : undefined;
854
+ }
855
+ function compileClause(clause) {
856
+ const field = clause.field;
857
+ switch (clause.operator) {
858
+ case "=":
859
+ return `${field} = ${literal(clause.value)}`;
860
+ case "!=":
861
+ return `${field} <> ${literal(clause.value)}`;
862
+ case "<":
863
+ case "<=":
864
+ case ">":
865
+ case ">=":
866
+ return `${field} ${clause.operator} ${literal(clause.value)}`;
867
+ case "in":
868
+ case "not-in": {
869
+ if (!Array.isArray(clause.value) || clause.value.length === 0)
870
+ return undefined;
871
+ const values = clause.value.map(literal).join(", ");
872
+ return `${field} ${clause.operator === "not-in" ? "NOT " : ""}IN (${values})`;
873
+ }
874
+ case "between": {
875
+ if (!Array.isArray(clause.value) || clause.value.length < 2)
876
+ return undefined;
877
+ return `${field} BETWEEN ${literal(clause.value[0])} AND ${literal(clause.value[1])}`;
878
+ }
879
+ case "like":
880
+ return `${field} LIKE ${literal(clause.value)}`;
881
+ case "is-null":
882
+ return `${field} IS NULL`;
883
+ case "is-not-null":
884
+ return `${field} IS NOT NULL`;
885
+ }
886
+ }
887
+ function combineWhere(left, right) {
888
+ if (left && right)
889
+ return `(${left}) AND (${right})`;
890
+ return left || right || undefined;
891
+ }
892
+ function spatialFilterFromExtent(extent) {
893
+ if (!extent)
894
+ return undefined;
895
+ return {
896
+ geometryType: "esriGeometryEnvelope",
897
+ geometry: {
898
+ xmin: extent.xmin,
899
+ ymin: extent.ymin,
900
+ xmax: extent.xmax,
901
+ ymax: extent.ymax,
902
+ ...(extent.spatialReference ? { spatialReference: extent.spatialReference } : {}),
903
+ },
904
+ spatialRel: "esriSpatialRelIntersects",
905
+ };
906
+ }
907
+ function literal(value) {
908
+ if (value === null || value === undefined)
909
+ return "NULL";
910
+ if (typeof value === "number")
911
+ return Number.isFinite(value) ? String(value) : "NULL";
912
+ if (typeof value === "boolean")
913
+ return value ? "TRUE" : "FALSE";
914
+ return `'${String(value).replace(/'/g, "''")}'`;
915
+ }
916
+ function categoryBucketsFromRows(rows, field, countAlias, metricAliasValue, orderBy, limit) {
917
+ const total = rows.reduce((sum, row) => sum + (numeric(row[countAlias]) ?? 0), 0);
918
+ return sortBuckets(rows.map((row) => {
919
+ const count = numeric(row[countAlias]) ?? 0;
920
+ const value = normalizeBucketValue(row[field]);
921
+ return {
922
+ value,
923
+ label: label(value),
924
+ count,
925
+ percent: total > 0 ? count / total : 0,
926
+ ...(metricAliasValue ? { metric: nullableNumeric(row[metricAliasValue]) } : {}),
927
+ };
928
+ }), orderBy ?? "count-desc").slice(0, limit);
929
+ }
930
+ function categoryBucketsFromFeatures(features, field, metric, orderBy, limit) {
931
+ const buckets = new Map();
932
+ for (const feature of features) {
933
+ const value = normalizeBucketValue(readField(feature.attributes, field));
934
+ const key = String(value);
935
+ const entry = buckets.get(key) ?? { value, count: 0, values: [] };
936
+ entry.count += 1;
937
+ const metricValue = metric ? numeric(readField(feature.attributes, metric.field)) : undefined;
938
+ if (metricValue !== undefined)
939
+ entry.values.push(metricValue);
940
+ buckets.set(key, entry);
941
+ }
942
+ const total = features.length;
943
+ return sortBuckets([...buckets.values()].map((entry) => ({
944
+ value: entry.value,
945
+ label: label(entry.value),
946
+ count: entry.count,
947
+ percent: total > 0 ? entry.count / total : 0,
948
+ ...(metric ? { metric: computeNumbersMetric(entry.values, metric.fn) } : {}),
949
+ })), orderBy ?? (metric ? "metric-desc" : "count-desc")).slice(0, limit);
950
+ }
951
+ function histogramBinsFromRows(rows, options) {
952
+ const min = options.min ?? (options.minAlias ? rowsMin(rows, options.minAlias) : undefined);
953
+ const max = options.max ?? (options.maxAlias ? rowsMax(rows, options.maxAlias) : undefined);
954
+ if (min === undefined || max === undefined)
955
+ return { min: null, max: null, bins: [] };
956
+ const count = clampInteger(options.bins, 1, MAX_HISTOGRAM_BINS);
957
+ const bins = emptyHistogramBins(min, max, count);
958
+ const width = max === min ? 1 : (max - min) / count;
959
+ for (const row of rows) {
960
+ const rowCount = numeric(row[options.countAlias]) ?? 0;
961
+ let index = numeric(row[options.bucketAlias]);
962
+ if (index === undefined && options.minAlias) {
963
+ const rowMin = numeric(row[options.minAlias]);
964
+ if (rowMin !== undefined)
965
+ index = max === min ? 0 : Math.floor((rowMin - min) / width);
966
+ }
967
+ if (index === undefined)
968
+ continue;
969
+ const bucketIndex = Math.max(0, Math.min(count - 1, Math.trunc(index)));
970
+ const bin = bins[bucketIndex];
971
+ const rowMin = options.minAlias ? numeric(row[options.minAlias]) : undefined;
972
+ const rowMax = options.maxAlias ? numeric(row[options.maxAlias]) : undefined;
973
+ const rowLabel = options.labelAlias ? row[options.labelAlias] : undefined;
974
+ bins[bucketIndex] = {
975
+ ...bin,
976
+ ...(rowMin !== undefined ? { min: rowMin } : {}),
977
+ ...(rowMax !== undefined ? { max: rowMax } : {}),
978
+ ...(typeof rowLabel === "string" && rowLabel !== "" ? { label: rowLabel } : {}),
979
+ count: bin.count + rowCount,
980
+ };
981
+ }
982
+ const total = bins.reduce((sum, bin) => sum + bin.count, 0);
983
+ return {
984
+ min,
985
+ max,
986
+ bins: bins.map((bin) => ({ ...bin, percent: total > 0 ? bin.count / total : 0 })),
987
+ };
988
+ }
989
+ function emptyHistogramBins(min, max, count) {
990
+ const width = max === min ? 1 : (max - min) / count;
991
+ return Array.from({ length: count }, (_, index) => {
992
+ const binMin = min + index * width;
993
+ const binMax = index === count - 1 ? max : min + (index + 1) * width;
994
+ return {
995
+ id: `${index}`,
996
+ min: binMin,
997
+ max: binMax,
998
+ label: `${formatNumber(binMin)} - ${formatNumber(binMax)}`,
999
+ count: 0,
1000
+ percent: 0,
1001
+ };
1002
+ });
1003
+ }
1004
+ function histogramBins(features, request) {
1005
+ const values = numericValues(features, request.field);
1006
+ const min = request.min ?? (values.length > 0 ? Math.min(...values) : undefined);
1007
+ const max = request.max ?? (values.length > 0 ? Math.max(...values) : undefined);
1008
+ if (min === undefined || max === undefined)
1009
+ return { min: null, max: null, bins: [] };
1010
+ const count = clampInteger(request.bins ?? DEFAULT_HISTOGRAM_BINS, 1, MAX_HISTOGRAM_BINS);
1011
+ const width = max === min ? 1 : (max - min) / count;
1012
+ const bins = emptyHistogramBins(min, max, count);
1013
+ for (const value of values) {
1014
+ if (value < min || value > max)
1015
+ continue;
1016
+ const index = max === min ? 0 : Math.min(count - 1, Math.floor((value - min) / width));
1017
+ bins[index] = { ...bins[index], count: bins[index].count + 1 };
1018
+ }
1019
+ const total = bins.reduce((sum, bin) => sum + bin.count, 0);
1020
+ return {
1021
+ min,
1022
+ max,
1023
+ bins: bins.map((bin) => ({ ...bin, percent: total > 0 ? bin.count / total : 0 })),
1024
+ };
1025
+ }
1026
+ function timeSeriesBucketsFromRows(rows, options) {
1027
+ const buckets = [];
1028
+ for (const row of rows) {
1029
+ const start = dateFromValue(row[options.startAlias]);
1030
+ if (!start)
1031
+ continue;
1032
+ const end = dateFromValue(row[options.endAlias]) ?? addInterval(start, options.interval);
1033
+ const count = numeric(row[options.countAlias]) ?? 0;
1034
+ const labelValue = options.labelAlias ? row[options.labelAlias] : undefined;
1035
+ buckets.push({
1036
+ start,
1037
+ end,
1038
+ label: typeof labelValue === "string" && labelValue !== "" ? labelValue : formatTimeLabel(start, options.interval),
1039
+ count,
1040
+ ...(options.metricAlias ? { metric: nullableNumeric(row[options.metricAlias]) } : {}),
1041
+ });
1042
+ }
1043
+ buckets.sort((a, b) => a.start.getTime() - b.start.getTime());
1044
+ return finalizeTimeSeriesBuckets(options.fillMissing ? fillMissingTimeBuckets(buckets, options.interval, options.start, options.end) : buckets);
1045
+ }
1046
+ function timeSeriesBucketsFromFeatures(features, request, interval) {
1047
+ const startLimit = dateFromValue(request.start);
1048
+ const endLimit = dateFromValue(request.end);
1049
+ const byStart = new Map();
1050
+ for (const feature of features) {
1051
+ const date = dateFromValue(readField(feature.attributes, request.field));
1052
+ if (!date)
1053
+ continue;
1054
+ if (startLimit && date < startLimit)
1055
+ continue;
1056
+ if (endLimit && date >= endLimit)
1057
+ continue;
1058
+ const start = truncateDate(date, interval);
1059
+ const end = addInterval(start, interval);
1060
+ const key = start.toISOString();
1061
+ const existing = byStart.get(key) ?? {
1062
+ start,
1063
+ end,
1064
+ label: formatTimeLabel(start, interval),
1065
+ count: 0,
1066
+ metric: undefined,
1067
+ values: [],
1068
+ };
1069
+ existing.count += 1;
1070
+ if (request.metric && request.metric.fn !== "count") {
1071
+ const value = numeric(readField(feature.attributes, request.metric.field));
1072
+ if (value !== undefined)
1073
+ existing.values.push(value);
1074
+ }
1075
+ byStart.set(key, existing);
1076
+ }
1077
+ const buckets = [...byStart.values()]
1078
+ .map((bucket) => ({
1079
+ start: bucket.start,
1080
+ end: bucket.end,
1081
+ label: bucket.label,
1082
+ count: bucket.count,
1083
+ metric: request.metric
1084
+ ? request.metric.fn === "count"
1085
+ ? bucket.count
1086
+ : computeNumbersMetric(bucket.values, request.metric.fn)
1087
+ : undefined,
1088
+ }))
1089
+ .sort((a, b) => a.start.getTime() - b.start.getTime());
1090
+ return finalizeTimeSeriesBuckets(request.fillMissing ? fillMissingTimeBuckets(buckets, interval, request.start, request.end) : buckets);
1091
+ }
1092
+ function finalizeTimeSeriesBuckets(buckets) {
1093
+ const totalCount = buckets.reduce((sum, bucket) => sum + bucket.count, 0);
1094
+ return {
1095
+ totalCount,
1096
+ buckets: buckets.map((bucket) => ({
1097
+ id: bucket.start.toISOString(),
1098
+ start: bucket.start.toISOString(),
1099
+ end: bucket.end.toISOString(),
1100
+ label: bucket.label,
1101
+ count: bucket.count,
1102
+ percent: totalCount > 0 ? bucket.count / totalCount : 0,
1103
+ ...(bucket.metric !== undefined ? { metric: bucket.metric } : {}),
1104
+ })),
1105
+ };
1106
+ }
1107
+ function fillMissingTimeBuckets(buckets, interval, startValue, endValue) {
1108
+ if (buckets.length === 0 && (startValue === undefined || endValue === undefined))
1109
+ return buckets;
1110
+ const byStart = new Map(buckets.map((bucket) => [bucket.start.toISOString(), bucket]));
1111
+ const first = dateFromValue(startValue) ?? buckets[0]?.start;
1112
+ const lastEnd = dateFromValue(endValue) ?? buckets.at(-1)?.end;
1113
+ if (!first || !lastEnd || first >= lastEnd)
1114
+ return buckets;
1115
+ const out = [];
1116
+ let cursor = truncateDate(first, interval);
1117
+ while (cursor < lastEnd && out.length < MAX_TIME_SERIES_BUCKETS) {
1118
+ const key = cursor.toISOString();
1119
+ const existing = byStart.get(key);
1120
+ if (existing) {
1121
+ out.push(existing);
1122
+ }
1123
+ else {
1124
+ out.push({
1125
+ start: new Date(cursor.getTime()),
1126
+ end: addInterval(cursor, interval),
1127
+ label: formatTimeLabel(cursor, interval),
1128
+ count: 0,
1129
+ metric: null,
1130
+ });
1131
+ }
1132
+ cursor = addInterval(cursor, interval);
1133
+ }
1134
+ return out;
1135
+ }
1136
+ function computeMetric(features, metric) {
1137
+ if (metric.fn === "count")
1138
+ return features.length;
1139
+ return computeNumbersMetric(numericValues(features, metric.field), metric.fn);
1140
+ }
1141
+ function computeNumbersMetric(values, fn) {
1142
+ if (fn === "count")
1143
+ return values.length;
1144
+ if (values.length === 0)
1145
+ return null;
1146
+ switch (fn) {
1147
+ case "sum":
1148
+ return values.reduce((sum, value) => sum + value, 0);
1149
+ case "avg":
1150
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
1151
+ case "min":
1152
+ return Math.min(...values);
1153
+ case "max":
1154
+ return Math.max(...values);
1155
+ case "stddev": {
1156
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
1157
+ const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length;
1158
+ return Math.sqrt(variance);
1159
+ }
1160
+ case "var": {
1161
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
1162
+ return values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length;
1163
+ }
1164
+ }
1165
+ }
1166
+ function numericValues(features, field) {
1167
+ const values = [];
1168
+ for (const feature of features) {
1169
+ const value = numeric(readField(feature.attributes, field));
1170
+ if (value !== undefined)
1171
+ values.push(value);
1172
+ }
1173
+ return values;
1174
+ }
1175
+ function rowsMin(rows, field) {
1176
+ const values = rows.map((row) => numeric(row[field])).filter((value) => value !== undefined);
1177
+ return values.length > 0 ? Math.min(...values) : undefined;
1178
+ }
1179
+ function rowsMax(rows, field) {
1180
+ const values = rows.map((row) => numeric(row[field])).filter((value) => value !== undefined);
1181
+ return values.length > 0 ? Math.max(...values) : undefined;
1182
+ }
1183
+ function normalizeTimeSeriesInterval(interval) {
1184
+ if (!interval)
1185
+ return DEFAULT_TIME_SERIES_INTERVAL;
1186
+ if (typeof interval === "string")
1187
+ return { unit: interval, step: 1, timezone: "UTC" };
1188
+ return {
1189
+ unit: interval.unit,
1190
+ step: clampInteger(interval.step ?? 1, 1, 10_000),
1191
+ timezone: interval.timezone ?? "UTC",
1192
+ };
1193
+ }
1194
+ function histogramRangeWhere(field, min, max) {
1195
+ const parts = [];
1196
+ if (min !== undefined)
1197
+ parts.push(`${field} >= ${literal(min)}`);
1198
+ if (max !== undefined)
1199
+ parts.push(`${field} <= ${literal(max)}`);
1200
+ return parts.length > 0 ? parts.join(" AND ") : undefined;
1201
+ }
1202
+ function timeSeriesRangeWhere(field, start, end) {
1203
+ const parts = [];
1204
+ if (start !== undefined)
1205
+ parts.push(`${field} >= ${literal(serializeTimeValue(start))}`);
1206
+ if (end !== undefined)
1207
+ parts.push(`${field} < ${literal(serializeTimeValue(end))}`);
1208
+ return parts.length > 0 ? parts.join(" AND ") : undefined;
1209
+ }
1210
+ function serializeTimeValue(value) {
1211
+ return value instanceof Date ? value.toISOString() : value;
1212
+ }
1213
+ function dateFromValue(value) {
1214
+ if (value instanceof Date && Number.isFinite(value.getTime()))
1215
+ return new Date(value.getTime());
1216
+ if (typeof value !== "string" && typeof value !== "number")
1217
+ return undefined;
1218
+ const date = new Date(value);
1219
+ return Number.isFinite(date.getTime()) ? date : undefined;
1220
+ }
1221
+ function truncateDate(date, interval) {
1222
+ const out = new Date(date.getTime());
1223
+ const step = interval.step;
1224
+ switch (interval.unit) {
1225
+ case "minute":
1226
+ out.setUTCSeconds(0, 0);
1227
+ out.setUTCMinutes(Math.floor(out.getUTCMinutes() / step) * step);
1228
+ return out;
1229
+ case "hour":
1230
+ out.setUTCMinutes(0, 0, 0);
1231
+ out.setUTCHours(Math.floor(out.getUTCHours() / step) * step);
1232
+ return out;
1233
+ case "day":
1234
+ return new Date(Math.floor(Date.UTC(out.getUTCFullYear(), out.getUTCMonth(), out.getUTCDate()) / dayMs(step)) * dayMs(step));
1235
+ case "week": {
1236
+ const day = out.getUTCDay();
1237
+ const mondayOffset = day === 0 ? 6 : day - 1;
1238
+ const monday = Date.UTC(out.getUTCFullYear(), out.getUTCMonth(), out.getUTCDate() - mondayOffset);
1239
+ return new Date(Math.floor(monday / dayMs(step * 7)) * dayMs(step * 7));
1240
+ }
1241
+ case "month":
1242
+ return new Date(Date.UTC(out.getUTCFullYear(), Math.floor(out.getUTCMonth() / step) * step, 1));
1243
+ case "quarter": {
1244
+ const months = step * 3;
1245
+ return new Date(Date.UTC(out.getUTCFullYear(), Math.floor(out.getUTCMonth() / months) * months, 1));
1246
+ }
1247
+ case "year":
1248
+ return new Date(Date.UTC(Math.floor(out.getUTCFullYear() / step) * step, 0, 1));
1249
+ }
1250
+ }
1251
+ function addInterval(date, interval) {
1252
+ const out = new Date(date.getTime());
1253
+ switch (interval.unit) {
1254
+ case "minute":
1255
+ out.setUTCMinutes(out.getUTCMinutes() + interval.step);
1256
+ return out;
1257
+ case "hour":
1258
+ out.setUTCHours(out.getUTCHours() + interval.step);
1259
+ return out;
1260
+ case "day":
1261
+ out.setUTCDate(out.getUTCDate() + interval.step);
1262
+ return out;
1263
+ case "week":
1264
+ out.setUTCDate(out.getUTCDate() + interval.step * 7);
1265
+ return out;
1266
+ case "month":
1267
+ out.setUTCMonth(out.getUTCMonth() + interval.step);
1268
+ return out;
1269
+ case "quarter":
1270
+ out.setUTCMonth(out.getUTCMonth() + interval.step * 3);
1271
+ return out;
1272
+ case "year":
1273
+ out.setUTCFullYear(out.getUTCFullYear() + interval.step);
1274
+ return out;
1275
+ }
1276
+ }
1277
+ function dayMs(days) {
1278
+ return days * 24 * 60 * 60 * 1000;
1279
+ }
1280
+ function formatTimeLabel(date, interval) {
1281
+ const iso = date.toISOString();
1282
+ if (interval.unit === "year")
1283
+ return iso.slice(0, 4);
1284
+ if (interval.unit === "quarter")
1285
+ return `${iso.slice(0, 4)} Q${Math.floor(date.getUTCMonth() / 3) + 1}`;
1286
+ if (interval.unit === "month")
1287
+ return iso.slice(0, 7);
1288
+ if (interval.unit === "day" || interval.unit === "week")
1289
+ return iso.slice(0, 10);
1290
+ if (interval.unit === "hour")
1291
+ return `${iso.slice(0, 13)}:00Z`;
1292
+ return `${iso.slice(0, 16)}Z`;
1293
+ }
1294
+ function sortBuckets(buckets, orderBy) {
1295
+ return [...buckets].sort((a, b) => {
1296
+ switch (orderBy) {
1297
+ case "count-asc":
1298
+ return a.count - b.count || compareBucketValue(a.value, b.value);
1299
+ case "value-asc":
1300
+ return compareBucketValue(a.value, b.value);
1301
+ case "value-desc":
1302
+ return compareBucketValue(b.value, a.value);
1303
+ case "metric-asc":
1304
+ return compareNullableNumber(a.metric, b.metric) || compareBucketValue(a.value, b.value);
1305
+ case "metric-desc":
1306
+ return compareNullableNumber(b.metric, a.metric) || compareBucketValue(a.value, b.value);
1307
+ case "count-desc":
1308
+ return b.count - a.count || compareBucketValue(a.value, b.value);
1309
+ }
1310
+ });
1311
+ }
1312
+ function compareBucketValue(a, b) {
1313
+ if (typeof a === "number" && typeof b === "number")
1314
+ return a - b;
1315
+ return label(a).localeCompare(label(b));
1316
+ }
1317
+ function compareNullableNumber(a, b) {
1318
+ const left = a ?? Number.NEGATIVE_INFINITY;
1319
+ const right = b ?? Number.NEGATIVE_INFINITY;
1320
+ return left - right;
1321
+ }
1322
+ function readField(attributes, field) {
1323
+ if (!attributes || typeof attributes !== "object")
1324
+ return undefined;
1325
+ return attributes[field];
1326
+ }
1327
+ function normalizeBucketValue(value) {
1328
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) {
1329
+ return value;
1330
+ }
1331
+ if (value === undefined)
1332
+ return null;
1333
+ return String(value);
1334
+ }
1335
+ function label(value) {
1336
+ return value === null ? "Null" : String(value);
1337
+ }
1338
+ function numeric(value) {
1339
+ if (typeof value === "number" && Number.isFinite(value))
1340
+ return value;
1341
+ if (typeof value === "string" && value.trim() !== "") {
1342
+ const parsed = Number(value);
1343
+ if (Number.isFinite(parsed))
1344
+ return parsed;
1345
+ }
1346
+ return undefined;
1347
+ }
1348
+ function nullableNumeric(value) {
1349
+ return numeric(value) ?? null;
1350
+ }
1351
+ function metricAlias(metric, prefix = "widget") {
1352
+ const field = metric.field === "*" ? "all" : metric.field.replace(/\W+/g, "_");
1353
+ return metric.alias ?? `${prefix}_${metric.fn}_${field}`;
1354
+ }
1355
+ function odataAggregateExpression(metric, alias) {
1356
+ if (metric.fn === "count")
1357
+ return `$count as ${alias}`;
1358
+ return `${metric.field} with ${odataMetricName(metric.fn)} as ${alias}`;
1359
+ }
1360
+ function odataMetricSupported(fn) {
1361
+ return fn === "count" || fn === "sum" || fn === "avg" || fn === "min" || fn === "max";
1362
+ }
1363
+ function odataMetricName(fn) {
1364
+ return fn === "avg" ? "average" : fn;
1365
+ }
1366
+ function mergeOutFields(existing, fields) {
1367
+ const out = new Set(existing ?? []);
1368
+ for (const field of fields) {
1369
+ if (field && field !== "*")
1370
+ out.add(field);
1371
+ }
1372
+ return out.size > 0 ? [...out] : existing;
1373
+ }
1374
+ function boundedLimit(value, fallback) {
1375
+ return clampInteger(value ?? fallback, 1, 500);
1376
+ }
1377
+ function maxClientRows(options, request) {
1378
+ return clampInteger(request.maxClientRows ?? options.maxClientRows ?? DEFAULT_MAX_CLIENT_ROWS, 1, 100_000);
1379
+ }
1380
+ function clampInteger(value, min, max) {
1381
+ if (!Number.isFinite(value))
1382
+ return min;
1383
+ return Math.max(min, Math.min(max, Math.trunc(value)));
1384
+ }
1385
+ function cacheMetadata(source, kind, request, resolved, options) {
1386
+ const hints = { ...(options.cache ?? {}), ...(request.cache ?? {}) };
1387
+ const analyticsSource = request.analyticsSource ?? options.analyticsSource;
1388
+ const ttlMs = hints.ttlMs ?? options.ttlMs;
1389
+ const freshness = hints.freshness ?? options.freshness ?? source.descriptor.analytics?.freshness;
1390
+ const normalizedAnalyticsSource = analyticsSource ? normalizeAnalyticsSourceDescriptor(analyticsSource) : undefined;
1391
+ const keyParts = [
1392
+ WIDGET_SOURCE_SCHEMA_VERSION,
1393
+ source.descriptor.id,
1394
+ source.descriptor.protocol,
1395
+ kind,
1396
+ ...(normalizedAnalyticsSource
1397
+ ? [
1398
+ buildAnalyticsSourceCacheKey(normalizedAnalyticsSource, {
1399
+ operation: "widget",
1400
+ cache: {
1401
+ ...(normalizedAnalyticsSource.cache?.key ?? {}),
1402
+ filters: resolved.query.where,
1403
+ projection: sanitizeQuery(resolved.query),
1404
+ widgetProjection: sanitizeRequest(request),
1405
+ },
1406
+ }),
1407
+ ]
1408
+ : []),
1409
+ stableStringify({
1410
+ query: sanitizeQuery(resolved.query),
1411
+ request: sanitizeRequest(request),
1412
+ }),
1413
+ ...(hints.keyParts ?? []),
1414
+ ];
1415
+ return {
1416
+ metadataCacheable: hints.metadataCacheable ?? true,
1417
+ resultCacheable: hints.resultCacheable ?? (!options.realtime || freshness !== undefined),
1418
+ cacheKey: keyParts.join(":"),
1419
+ keyParts,
1420
+ ...(ttlMs !== undefined ? { ttlMs } : {}),
1421
+ ...(freshness ? { freshness } : {}),
1422
+ status: "computed",
1423
+ };
1424
+ }
1425
+ function sanitizeQuery(query) {
1426
+ const { signal: _signal, ...rest } = query;
1427
+ void _signal;
1428
+ return rest;
1429
+ }
1430
+ function sanitizeRequest(request) {
1431
+ const { signal: _signal, query: _query, projection: _projection, analyticsSource: _analyticsSource, ...rest } = request;
1432
+ void _signal;
1433
+ void _query;
1434
+ void _projection;
1435
+ void _analyticsSource;
1436
+ return rest;
1437
+ }
1438
+ function stableStringify(value) {
1439
+ if (value === null || typeof value !== "object")
1440
+ return JSON.stringify(value);
1441
+ if (value instanceof Date)
1442
+ return JSON.stringify(value.toISOString());
1443
+ if (Array.isArray(value))
1444
+ return `[${value.map(stableStringify).join(",")}]`;
1445
+ const obj = value;
1446
+ return `{${Object.keys(obj)
1447
+ .sort()
1448
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`)
1449
+ .join(",")}}`;
1450
+ }
1451
+ function dedupeDegraded(reasons) {
1452
+ const out = [];
1453
+ const seen = new Set();
1454
+ for (const reason of reasons) {
1455
+ const key = `${reason.capability}:${reason.protocol ?? ""}:${reason.sourceId ?? ""}:${reason.reason}`;
1456
+ if (seen.has(key))
1457
+ continue;
1458
+ seen.add(key);
1459
+ out.push(reason);
1460
+ }
1461
+ return out;
1462
+ }
1463
+ function throwIfAborted(signal) {
1464
+ if (!signal?.aborted)
1465
+ return;
1466
+ const reason = signal.reason;
1467
+ if (reason instanceof Error)
1468
+ throw reason;
1469
+ throw new DOMException("The operation was aborted.", "AbortError");
1470
+ }
1471
+ function formatNumber(value) {
1472
+ return Number.isInteger(value) ? String(value) : Number(value.toFixed(6)).toString();
1473
+ }