@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,1196 @@
1
+ /**
2
+ * Framework-neutral generated-app preview runtime for the operations
3
+ * dashboard proof profile.
4
+ *
5
+ * The runtime composes the existing MapPackage loader, ExplorationContext,
6
+ * and interaction bindings into reusable widget models. Hosts own DOM,
7
+ * framework, and MapLibre construction; this module owns manifest binding,
8
+ * linked state, feature filtering, and structured preview errors.
9
+ *
10
+ * @module
11
+ */
12
+ import { createExplorationContext, isSourceQualifiedSelectionTarget, selectLinkedViewQueryProjection, sourceFeatureSelectionTarget, } from "../exploration/index.js";
13
+ import { bindChartToExploration, bindFilterControlsToExploration, bindTableSelectionToExploration, syncFeatureStateSelection, syncMapLayerFilterToExploration, } from "../interactions/index.js";
14
+ import { loadMapPackage, } from "../runtime/index.js";
15
+ import { HonuaGeneratedAppError, toGeneratedAppDiagnostic } from "./errors.js";
16
+ import { HONUA_GENERATED_APP_DEFAULT_PREVIEW_LIMIT, HONUA_GENERATED_APP_MAX_PREVIEW_LIMIT, assertGeneratedAppManifest, clampGeneratedAppManifest, clampGeneratedAppPreviewLimit, projectAppPackageToGeneratedAppManifest, } from "./projection.js";
17
+ export async function loadGeneratedAppRuntime(manifest, options) {
18
+ assertGeneratedAppManifest(manifest);
19
+ manifest = clampGeneratedAppManifest(manifest);
20
+ assertOperationsDashboardWidgets(manifest);
21
+ const sourceId = manifest.data.sourceId;
22
+ const mapWidget = findWidget(manifest, "map");
23
+ const mapPackage = manifest.mapPackage ?? options.mapPackage;
24
+ assertMapPackageMatchesManifest(manifest, mapPackage);
25
+ let mapRuntime;
26
+ let disposeMap;
27
+ if (mapWidget) {
28
+ if (!mapPackage) {
29
+ throw new HonuaGeneratedAppError("missing-map-package", "generated-app map widget requires a MapPackage", {
30
+ stage: "load",
31
+ detail: { appId: manifest.appId, widgetId: mapWidget.id, path: "GeneratedAppManifest.mapPackage" },
32
+ });
33
+ }
34
+ if (!options.mapFactory) {
35
+ throw new HonuaGeneratedAppError("missing-binding", "generated-app map widget requires options.mapFactory", {
36
+ stage: "load",
37
+ detail: { appId: manifest.appId, widgetId: mapWidget.id, path: "HonuaGeneratedAppLoadOptions.mapFactory" },
38
+ });
39
+ }
40
+ if (!options.mapLoadOptions) {
41
+ throw new HonuaGeneratedAppError("missing-binding", "generated-app map widget requires options.mapLoadOptions", {
42
+ stage: "load",
43
+ detail: { appId: manifest.appId, widgetId: mapWidget.id, path: "HonuaGeneratedAppLoadOptions.mapLoadOptions" },
44
+ });
45
+ }
46
+ try {
47
+ const factoryResult = await options.mapFactory(mapWidget, manifest);
48
+ disposeMap = factoryResult.dispose;
49
+ mapRuntime = await loadMapPackage(mapPackage, factoryResult.map, {
50
+ ...options.mapLoadOptions,
51
+ applyInitialView: options.mapLoadOptions.applyInitialView ?? true,
52
+ });
53
+ }
54
+ catch (cause) {
55
+ if (mapRuntime)
56
+ mapRuntime.dispose();
57
+ disposeMap?.();
58
+ throw new HonuaGeneratedAppError("map-load-failed", "generated-app map widget failed to load", {
59
+ stage: "load",
60
+ detail: { appId: manifest.appId, widgetId: mapWidget.id, widgetKind: "map" },
61
+ cause,
62
+ });
63
+ }
64
+ }
65
+ const sourceIds = unique([sourceId, ...(mapPackage?.sourceBindings.map((binding) => binding.sourceId) ?? [])]);
66
+ const context = createExplorationContext({
67
+ datasetId: manifest.appId,
68
+ sourceIds,
69
+ initialState: manifest.initialState,
70
+ preset: manifest.linkedViewPreset ?? "globalLinked",
71
+ });
72
+ const handles = [];
73
+ const table = {};
74
+ const chart = {};
75
+ const filter = {};
76
+ let mapView;
77
+ for (const widget of manifest.layout.widgets) {
78
+ switch (widget.kind) {
79
+ case "map": {
80
+ mapView = context.connectView({ id: widget.id, role: "map" });
81
+ const layerId = mapLayerIdForWidget(widget, manifest);
82
+ if (mapRuntime && layerId && mapRuntime.map.setFilter) {
83
+ const setFilter = mapRuntime.map.setFilter.bind(mapRuntime.map);
84
+ handles.push(syncMapLayerFilterToExploration({ setFilter }, mapView, {
85
+ layerId,
86
+ sourceId,
87
+ translate: (projection) => compileMapLibreFilters(projection.filters, sourceId),
88
+ }));
89
+ handles.push(syncFeatureStateSelection(mapRuntime.map, mapView, {
90
+ source: sourceId,
91
+ sourceLayer: widget.sourceLayer,
92
+ includeRawIds: false,
93
+ }));
94
+ }
95
+ break;
96
+ }
97
+ case "table":
98
+ case "list": {
99
+ const view = context.connectView({ id: widget.id, role: "grid" });
100
+ table[widget.id] = bindTableSelectionToExploration(view);
101
+ break;
102
+ }
103
+ case "chart": {
104
+ const view = context.connectView({ id: widget.id, role: "chart" });
105
+ const binding = bindChartToExploration(view);
106
+ const groupBy = chartCategoryField(widget);
107
+ if (groupBy) {
108
+ binding.setGrouping([groupBy]);
109
+ binding.setAggregation({ groupBy: [groupBy], metrics: [widget.metric ?? { fn: "count", field: "*" }] });
110
+ }
111
+ chart[widget.id] = binding;
112
+ break;
113
+ }
114
+ case "filter": {
115
+ const view = context.connectView({ id: widget.id, role: "filter" });
116
+ filter[widget.id] = bindFilterControlsToExploration(view);
117
+ break;
118
+ }
119
+ case "count":
120
+ break;
121
+ }
122
+ options.onEvent?.({ type: "widget-bound", appId: manifest.appId, widgetId: widget.id, widgetKind: widget.kind });
123
+ }
124
+ const runtime = new HonuaGeneratedAppRuntime({
125
+ manifest,
126
+ context,
127
+ mapRuntime,
128
+ disposeMap,
129
+ bindings: { mapView, table, chart, filter },
130
+ handles,
131
+ initialFeatures: options.initialFeatures,
132
+ featureLoader: options.featureLoader,
133
+ widgetSource: options.widgetSource,
134
+ onEvent: options.onEvent,
135
+ });
136
+ try {
137
+ await runtime.refresh();
138
+ }
139
+ catch (error) {
140
+ runtime.dispose();
141
+ throw error;
142
+ }
143
+ options.onEvent?.({ type: "loaded", appId: manifest.appId });
144
+ return runtime;
145
+ }
146
+ export async function previewGeneratedApp(input, options) {
147
+ let manifest = input.manifest;
148
+ try {
149
+ if (!manifest && input.appPackage) {
150
+ manifest = projectAppPackageToGeneratedAppManifest(input.appPackage, {
151
+ mapPackage: input.mapPackage ?? options.mapPackage,
152
+ });
153
+ }
154
+ if (!manifest) {
155
+ throw new HonuaGeneratedAppError("missing-manifest", "previewGeneratedApp requires manifest or appPackage", {
156
+ stage: "projection",
157
+ detail: { path: "HonuaGeneratedAppPreviewInput.manifest" },
158
+ });
159
+ }
160
+ const runtime = await loadGeneratedAppRuntime(manifest, {
161
+ ...options,
162
+ mapPackage: input.mapPackage ?? options.mapPackage,
163
+ });
164
+ return {
165
+ status: "ready",
166
+ manifest,
167
+ runtime,
168
+ model: runtime.render(),
169
+ errors: [],
170
+ };
171
+ }
172
+ catch (error) {
173
+ const diagnostic = toGeneratedAppDiagnostic(error);
174
+ if (error instanceof HonuaGeneratedAppError)
175
+ options.onEvent?.({ type: "error", appId: manifest?.appId, error });
176
+ return {
177
+ status: "error",
178
+ ...(manifest ? { manifest } : {}),
179
+ errors: [diagnostic],
180
+ };
181
+ }
182
+ }
183
+ export class HonuaGeneratedAppRuntime {
184
+ manifest;
185
+ context;
186
+ mapRuntime;
187
+ #disposeMap;
188
+ #bindings;
189
+ #handles;
190
+ #initialFeatures;
191
+ #featureLoader;
192
+ #widgetSource;
193
+ #listeners = new Set();
194
+ #records = [];
195
+ #widgetModels;
196
+ #disposed = false;
197
+ constructor(internals) {
198
+ this.manifest = internals.manifest;
199
+ this.context = internals.context;
200
+ this.mapRuntime = internals.mapRuntime;
201
+ this.#disposeMap = internals.disposeMap;
202
+ this.#bindings = internals.bindings;
203
+ this.#handles = internals.handles;
204
+ this.#initialFeatures = internals.initialFeatures;
205
+ this.#featureLoader = internals.featureLoader;
206
+ this.#widgetSource = internals.widgetSource;
207
+ if (internals.onEvent)
208
+ this.#listeners.add(internals.onEvent);
209
+ }
210
+ on(listener) {
211
+ this.#listeners.add(listener);
212
+ return {
213
+ remove: () => {
214
+ this.#listeners.delete(listener);
215
+ },
216
+ };
217
+ }
218
+ async refresh() {
219
+ this.#assertLive("refresh");
220
+ try {
221
+ this.#records = await this.#loadFeatureRecords();
222
+ this.#widgetModels = await this.#loadWidgetSourceModels();
223
+ return this.render();
224
+ }
225
+ catch (cause) {
226
+ const error = new HonuaGeneratedAppError("data-load-failed", "generated-app feature data failed to load", {
227
+ stage: "load",
228
+ detail: { appId: this.manifest.appId, sourceId: this.manifest.data.sourceId },
229
+ cause,
230
+ });
231
+ this.#emit({ type: "error", appId: this.manifest.appId, error });
232
+ throw error;
233
+ }
234
+ }
235
+ render() {
236
+ this.#assertLive("render");
237
+ const sourceId = this.manifest.data.sourceId;
238
+ const projection = selectLinkedViewQueryProjection(this.context.state, { sourceId });
239
+ const filtered = applyProjection(this.#records, projection.filters, projection.selection, sourceId);
240
+ const paged = applySortAndPagination(filtered, this.context.state.sort, this.context.state.page);
241
+ const widgetModels = this.#widgetModels?.projectionKey === stableWidgetProjectionKey(projection) ? this.#widgetModels : undefined;
242
+ const widgets = this.manifest.layout.widgets.map((widget) => this.#renderWidget(widget, paged, filtered, widgetModels));
243
+ const model = {
244
+ status: "ready",
245
+ appId: this.manifest.appId,
246
+ ...(this.manifest.title ? { title: this.manifest.title } : {}),
247
+ sourceId,
248
+ visibleCount: filtered.length,
249
+ totalCount: this.#records.length,
250
+ widgets,
251
+ snapshot: this.context.snapshot(),
252
+ };
253
+ this.#emit({ type: "rendered", appId: this.manifest.appId, visibleCount: filtered.length });
254
+ return model;
255
+ }
256
+ setFilter(widgetId, value) {
257
+ this.#assertLive("setFilter");
258
+ const widget = this.#requireWidget(widgetId, "filter");
259
+ const binding = this.#bindings.filter[widgetId];
260
+ if (!binding) {
261
+ throw missingWidgetBinding(this.manifest.appId, widgetId, "filter");
262
+ }
263
+ if (value === undefined) {
264
+ binding.clearFilter(widget.id);
265
+ }
266
+ else {
267
+ binding.setFilter(widget.id, {
268
+ field: widget.field,
269
+ operator: "=",
270
+ value,
271
+ appliesTo: [widget.sourceId ?? this.manifest.data.sourceId],
272
+ });
273
+ }
274
+ return this.render();
275
+ }
276
+ selectChartBucket(widgetId, value) {
277
+ this.#assertLive("selectChartBucket");
278
+ const widget = this.#requireWidget(widgetId, "chart");
279
+ const binding = this.#bindings.chart[widgetId];
280
+ if (!binding) {
281
+ throw missingWidgetBinding(this.manifest.appId, widgetId, "chart");
282
+ }
283
+ const sourceId = widget.sourceId ?? this.manifest.data.sourceId;
284
+ const groupBy = chartCategoryField(widget);
285
+ if (!groupBy) {
286
+ throw missingWidgetBinding(this.manifest.appId, widgetId, "chart");
287
+ }
288
+ binding.setGrouping([groupBy]);
289
+ binding.setAggregation({ groupBy: [groupBy], metrics: [widget.metric ?? { fn: "count", field: "*" }] });
290
+ for (const [id, clause] of Object.entries(this.context.state.filters)) {
291
+ if (id !== widget.id && clause.field === groupBy) {
292
+ this.context.dispatch({ kind: "clear-filter", id, viewId: widget.id });
293
+ }
294
+ }
295
+ if (value === undefined) {
296
+ this.context.dispatch({ kind: "clear-filter", id: widget.id, viewId: widget.id });
297
+ }
298
+ else {
299
+ binding.selectBucket({
300
+ filters: {
301
+ [widget.id]: {
302
+ field: groupBy,
303
+ operator: "=",
304
+ value,
305
+ appliesTo: [sourceId],
306
+ },
307
+ },
308
+ });
309
+ }
310
+ return this.render();
311
+ }
312
+ selectRecord(widgetId, id, options = {}) {
313
+ this.#assertLive("selectRecord");
314
+ const widget = this.#requireWidget(widgetId, ["table", "list"]);
315
+ const binding = this.#bindings.table[widgetId];
316
+ if (!binding) {
317
+ throw missingWidgetBinding(this.manifest.appId, widgetId, "table");
318
+ }
319
+ binding.select([sourceFeatureSelectionTarget(this.#recordSourceIdForSelection(widget, id), id)], {
320
+ replace: options.replace ?? true,
321
+ });
322
+ return this.render();
323
+ }
324
+ snapshot() {
325
+ this.#assertLive("snapshot");
326
+ return this.context.snapshot();
327
+ }
328
+ restore(snapshot) {
329
+ this.#assertLive("restore");
330
+ this.context.restore(snapshot);
331
+ return this.render();
332
+ }
333
+ dispose() {
334
+ if (this.#disposed)
335
+ return;
336
+ for (const handle of this.#handles)
337
+ handle.remove();
338
+ this.mapRuntime?.dispose();
339
+ this.#disposeMap?.();
340
+ this.context.dispose();
341
+ this.#disposed = true;
342
+ this.#emit({ type: "disposed", appId: this.manifest.appId });
343
+ this.#listeners.clear();
344
+ }
345
+ async #loadFeatureRecords() {
346
+ const sourceId = this.manifest.data.sourceId;
347
+ const projection = selectLinkedViewQueryProjection(this.context.state, { sourceId });
348
+ const raw = this.#initialFeatures ??
349
+ (this.#featureLoader
350
+ ? await this.#featureLoader({ manifest: this.manifest, sourceId, projection, mapRuntime: this.mapRuntime })
351
+ : await loadFeaturesFromMapRuntime(this.manifest, this.mapRuntime, projection));
352
+ return raw.map((feature, index) => normalizeFeatureRecord(feature, sourceId, this.#primaryKey(), index));
353
+ }
354
+ async #loadWidgetSourceModels() {
355
+ if (!this.#widgetSource)
356
+ return undefined;
357
+ const sourceId = this.manifest.data.sourceId;
358
+ const projection = selectLinkedViewQueryProjection(this.context.state, { sourceId });
359
+ const count = {};
360
+ const categories = {};
361
+ const histogram = {};
362
+ const timeSeries = {};
363
+ await runWithConcurrency(this.manifest.layout.widgets.map((widget) => async () => {
364
+ switch (widget.kind) {
365
+ case "count":
366
+ count[widget.id] = await this.#widgetSource.count({ projection });
367
+ break;
368
+ case "chart": {
369
+ const chartKind = generatedChartKind(widget);
370
+ if (chartKind === "histogram") {
371
+ histogram[widget.id] = await this.#widgetSource.histogram({
372
+ projection,
373
+ field: chartMeasureField(widget),
374
+ bins: widget.bins,
375
+ min: widget.min,
376
+ max: widget.max,
377
+ });
378
+ }
379
+ else if (chartKind === "time-series") {
380
+ timeSeries[widget.id] = await this.#widgetSource.timeSeries({
381
+ projection,
382
+ field: chartMeasureField(widget),
383
+ interval: widget.interval,
384
+ metric: widget.metric,
385
+ start: widget.start,
386
+ end: widget.end,
387
+ fillMissing: widget.fillMissing,
388
+ });
389
+ }
390
+ else {
391
+ const groupBy = chartCategoryField(widget);
392
+ if (groupBy) {
393
+ categories[widget.id] = await this.#widgetSource.categories({
394
+ projection,
395
+ field: groupBy,
396
+ metric: widget.metric,
397
+ });
398
+ }
399
+ }
400
+ break;
401
+ }
402
+ case "filter":
403
+ categories[widget.id] = await this.#widgetSource.categories({
404
+ projection,
405
+ field: widget.field,
406
+ limit: clampInteger(Math.max(widget.options?.length ?? 0, 25), 1, HONUA_GENERATED_APP_MAX_PREVIEW_LIMIT),
407
+ });
408
+ break;
409
+ case "map":
410
+ case "table":
411
+ case "list":
412
+ break;
413
+ }
414
+ }), 4);
415
+ return { projectionKey: stableWidgetProjectionKey(projection), count, categories, histogram, timeSeries };
416
+ }
417
+ #renderWidget(widget, pagedRecords, filteredRecords, widgetModels) {
418
+ const sourceId = widget.sourceId ?? this.manifest.data.sourceId;
419
+ switch (widget.kind) {
420
+ case "map":
421
+ return {
422
+ id: widget.id,
423
+ kind: "map",
424
+ ...(widget.title ? { title: widget.title } : {}),
425
+ loaded: Boolean(this.mapRuntime),
426
+ mapPackageId: this.mapRuntime?.mapPackage.mapPackageId ?? this.manifest.mapPackageId,
427
+ layerId: mapLayerIdForWidget(widget, this.manifest),
428
+ legend: widget.showLegend === false ? [] : (this.mapRuntime?.getLegend() ?? []),
429
+ searchFields: widget.showSearch === false ? [] : (this.manifest.bindings?.searchFields ?? []),
430
+ };
431
+ case "table":
432
+ case "list": {
433
+ const fields = widget.fields ?? this.manifest.bindings?.tableFields ?? inferFields(pagedRecords);
434
+ return {
435
+ id: widget.id,
436
+ kind: widget.kind,
437
+ ...(widget.title ? { title: widget.title } : {}),
438
+ sourceId,
439
+ fields,
440
+ rows: pagedRecords.map((record) => this.#rowModel(record, fields, widget)),
441
+ };
442
+ }
443
+ case "count":
444
+ return {
445
+ id: widget.id,
446
+ kind: "count",
447
+ ...(widget.title ? { title: widget.title } : {}),
448
+ label: widget.label ?? widget.title ?? "Records",
449
+ value: widgetModels?.count[widget.id]?.value ?? filteredRecords.length,
450
+ };
451
+ case "chart":
452
+ return chartModel(widget, filteredRecords, sourceId, this.context.state.filters, widgetModels);
453
+ case "filter":
454
+ return {
455
+ id: widget.id,
456
+ kind: "filter",
457
+ ...(widget.title ? { title: widget.title } : {}),
458
+ sourceId,
459
+ field: widget.field,
460
+ options: widgetModels?.categories[widget.id] !== undefined
461
+ ? filterOptionsFromWidgetSource(widgetModels.categories[widget.id], widget, this.context.state.filters)
462
+ : filterOptions(this.#records, this.context.state.filters, widget, sourceId),
463
+ };
464
+ }
465
+ }
466
+ #rowModel(record, fields, widget) {
467
+ const titleField = widget.titleField ?? this.manifest.bindings?.titleField ?? this.#primaryKey();
468
+ const subtitleField = widget.subtitleField ?? this.manifest.bindings?.subtitleField;
469
+ const sourceId = record.sourceId ?? widget.sourceId ?? this.manifest.data.sourceId;
470
+ return {
471
+ id: record.id,
472
+ sourceId,
473
+ title: stringValue(record.attributes[titleField] ?? record.id),
474
+ ...(subtitleField ? { subtitle: stringValue(record.attributes[subtitleField] ?? "") } : {}),
475
+ selected: selectionContains(this.context.state.selection, record, sourceId),
476
+ values: Object.fromEntries(fields.map((field) => [field, record.attributes[field]])),
477
+ };
478
+ }
479
+ #recordSourceIdForSelection(widget, id) {
480
+ const widgetSourceId = widget.sourceId ?? this.manifest.data.sourceId;
481
+ const exactRecord = this.#records.find((record) => record.id === id && (record.sourceId ?? widgetSourceId) === widgetSourceId);
482
+ if (exactRecord)
483
+ return exactRecord.sourceId ?? widgetSourceId;
484
+ const matchingRecords = this.#records.filter((record) => record.id === id);
485
+ if (matchingRecords.length === 1)
486
+ return matchingRecords[0].sourceId ?? widgetSourceId;
487
+ return widgetSourceId;
488
+ }
489
+ #primaryKey() {
490
+ return this.manifest.bindings?.primaryKey ?? "OBJECTID";
491
+ }
492
+ #requireWidget(widgetId, expected) {
493
+ const widget = this.manifest.layout.widgets.find((entry) => entry.id === widgetId);
494
+ const expectedKinds = Array.isArray(expected) ? expected : [expected];
495
+ if (!widget || !expectedKinds.includes(widget.kind)) {
496
+ throw new HonuaGeneratedAppError("missing-widget", `generated-app widget "${widgetId}" is not available`, {
497
+ stage: "interaction",
498
+ detail: { appId: this.manifest.appId, widgetId, expected: expectedKinds, received: widget?.kind },
499
+ });
500
+ }
501
+ return widget;
502
+ }
503
+ #assertLive(operation) {
504
+ if (this.#disposed) {
505
+ throw new HonuaGeneratedAppError("disposed", `generated-app runtime cannot ${operation} after dispose()`, {
506
+ stage: "dispose",
507
+ detail: { appId: this.manifest.appId },
508
+ });
509
+ }
510
+ }
511
+ #emit(event) {
512
+ for (const listener of this.#listeners)
513
+ listener(event);
514
+ }
515
+ }
516
+ async function loadFeaturesFromMapRuntime(manifest, mapRuntime, projection) {
517
+ const source = mapRuntime?.dataset.source(manifest.data.sourceId);
518
+ if (!source) {
519
+ throw new HonuaGeneratedAppError("missing-binding", "generated-app source is not available from the MapPackage", {
520
+ stage: "load",
521
+ detail: {
522
+ appId: manifest.appId,
523
+ sourceId: manifest.data.sourceId,
524
+ path: "HonuaMapRuntime.dataset.source",
525
+ },
526
+ });
527
+ }
528
+ const previewLimit = clampGeneratedAppPreviewLimit(projection.pagination.limit ?? manifest.data.previewLimit ?? HONUA_GENERATED_APP_DEFAULT_PREVIEW_LIMIT);
529
+ const query = {
530
+ returnGeometry: true,
531
+ outFields: generatedAppQueryFields(manifest),
532
+ orderBy: projection.orderBy,
533
+ pagination: { ...projection.pagination, limit: previewLimit ?? HONUA_GENERATED_APP_DEFAULT_PREVIEW_LIMIT },
534
+ };
535
+ const result = await source.query(query);
536
+ return result.features.map((feature) => ({
537
+ attributes: feature.attributes,
538
+ geometry: feature.geometry,
539
+ }));
540
+ }
541
+ function assertOperationsDashboardWidgets(manifest) {
542
+ const supported = new Set(["map", "table", "list", "count", "chart", "filter"]);
543
+ for (const widget of manifest.layout.widgets) {
544
+ if (!supported.has(widget.kind)) {
545
+ throw new HonuaGeneratedAppError("unsupported-widget", `unsupported generated-app widget "${widget.kind}"`, {
546
+ stage: "manifest",
547
+ detail: { appId: manifest.appId, widgetId: widget.id, widgetKind: widget.kind },
548
+ });
549
+ }
550
+ }
551
+ const requiredKinds = ["map", "count", "chart", "filter"];
552
+ for (const kind of requiredKinds) {
553
+ if (!manifest.layout.widgets.some((widget) => widget.kind === kind)) {
554
+ throw new HonuaGeneratedAppError("missing-widget", `operations dashboard manifest is missing ${kind} widget`, {
555
+ stage: "manifest",
556
+ detail: { appId: manifest.appId, expected: kind },
557
+ });
558
+ }
559
+ }
560
+ if (!manifest.layout.widgets.some((widget) => widget.kind === "table" || widget.kind === "list")) {
561
+ throw new HonuaGeneratedAppError("missing-widget", "operations dashboard manifest is missing table/list widget", {
562
+ stage: "manifest",
563
+ detail: { appId: manifest.appId, expected: "table|list" },
564
+ });
565
+ }
566
+ }
567
+ function findWidget(manifest, kind) {
568
+ return manifest.layout.widgets.find((widget) => widget.kind === kind);
569
+ }
570
+ function mapLayerIdForWidget(widget, manifest) {
571
+ return widget.layerId ?? manifest.bindings?.layerId;
572
+ }
573
+ function generatedAppQueryFields(manifest) {
574
+ const fields = [];
575
+ const add = (field) => {
576
+ if (field && !fields.includes(field))
577
+ fields.push(field);
578
+ };
579
+ const addMany = (values) => {
580
+ for (const field of values ?? [])
581
+ add(field);
582
+ };
583
+ add(manifest.bindings?.primaryKey ?? "OBJECTID");
584
+ add(manifest.bindings?.titleField);
585
+ add(manifest.bindings?.subtitleField);
586
+ add(manifest.bindings?.categoryField);
587
+ add(manifest.bindings?.filterField);
588
+ addMany(manifest.bindings?.tableFields);
589
+ addMany(manifest.bindings?.searchFields);
590
+ for (const widget of manifest.layout.widgets) {
591
+ switch (widget.kind) {
592
+ case "table":
593
+ case "list":
594
+ add(widget.primaryKey);
595
+ add(widget.titleField);
596
+ add(widget.subtitleField);
597
+ addMany(widget.fields);
598
+ break;
599
+ case "chart":
600
+ add(widget.groupBy);
601
+ add(widget.field);
602
+ if (widget.metric?.field !== "*")
603
+ add(widget.metric?.field);
604
+ break;
605
+ case "filter":
606
+ add(widget.field);
607
+ break;
608
+ case "map":
609
+ case "count":
610
+ break;
611
+ }
612
+ }
613
+ return fields.length > 0 ? fields : undefined;
614
+ }
615
+ function assertMapPackageMatchesManifest(manifest, mapPackage) {
616
+ if (!manifest.mapPackageId || !mapPackage || manifest.mapPackageId === mapPackage.mapPackageId)
617
+ return;
618
+ throw new HonuaGeneratedAppError("map-package-mismatch", `generated-app MapPackage "${mapPackage.mapPackageId}" does not match manifest mapPackageId "${manifest.mapPackageId}"`, {
619
+ stage: "load",
620
+ detail: {
621
+ appId: manifest.appId,
622
+ path: "GeneratedAppManifest.mapPackageId",
623
+ expected: manifest.mapPackageId,
624
+ received: mapPackage.mapPackageId,
625
+ },
626
+ });
627
+ }
628
+ function missingWidgetBinding(appId, widgetId, widgetKind) {
629
+ return new HonuaGeneratedAppError("missing-binding", `generated-app widget "${widgetId}" is not bound`, {
630
+ stage: "interaction",
631
+ detail: { appId, widgetId, widgetKind },
632
+ });
633
+ }
634
+ function normalizeFeatureRecord(input, sourceId, primaryKey, index) {
635
+ const raw = input;
636
+ const attributes = asRecord(raw.attributes) ?? asRecord(raw.properties) ?? {};
637
+ const candidateId = raw.id ?? attributes[primaryKey] ?? attributes.OBJECTID ?? attributes.objectId ?? attributes.id;
638
+ const id = typeof candidateId === "string" || typeof candidateId === "number" ? candidateId : `${sourceId}:${index}`;
639
+ return {
640
+ id,
641
+ sourceId: typeof raw.sourceId === "string" ? raw.sourceId : sourceId,
642
+ attributes,
643
+ ...(raw.geometry !== undefined ? { geometry: raw.geometry } : {}),
644
+ };
645
+ }
646
+ function asRecord(value) {
647
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
648
+ }
649
+ function applyProjection(records, filters, selection, sourceId) {
650
+ return records.filter((record) => Object.values(filters).every((clause) => matchesClause(record, clause, sourceId)) ||
651
+ selectionContains(selection, record, sourceId));
652
+ }
653
+ function applySortAndPagination(records, sort, page) {
654
+ const sorted = [...records];
655
+ for (const entry of [...sort].reverse()) {
656
+ sorted.sort((a, b) => compareValues(a.attributes[entry.field], b.attributes[entry.field], entry.direction));
657
+ }
658
+ const offset = page.offset ?? 0;
659
+ const limit = page.limit;
660
+ return limit === undefined ? sorted.slice(offset) : sorted.slice(offset, offset + limit);
661
+ }
662
+ function matchesClause(record, clause, fallbackSourceId) {
663
+ const sourceId = record.sourceId ?? fallbackSourceId;
664
+ if (clause.appliesTo && clause.appliesTo.length > 0 && !clause.appliesTo.includes(sourceId))
665
+ return true;
666
+ const value = record.attributes[clause.field];
667
+ switch (clause.operator) {
668
+ case "=":
669
+ return value === clause.value;
670
+ case "!=":
671
+ return value !== clause.value;
672
+ case "in":
673
+ return Array.isArray(clause.value) && clause.value.includes(value);
674
+ case "not-in":
675
+ return Array.isArray(clause.value) && !clause.value.includes(value);
676
+ case "like":
677
+ return typeof value === "string" && typeof clause.value === "string" && value.includes(clause.value);
678
+ case "is-null":
679
+ return value === null || value === undefined;
680
+ case "is-not-null":
681
+ return value !== null && value !== undefined;
682
+ case "<":
683
+ return typeof value === "number" && typeof clause.value === "number" && value < clause.value;
684
+ case "<=":
685
+ return typeof value === "number" && typeof clause.value === "number" && value <= clause.value;
686
+ case ">":
687
+ return typeof value === "number" && typeof clause.value === "number" && value > clause.value;
688
+ case ">=":
689
+ return typeof value === "number" && typeof clause.value === "number" && value >= clause.value;
690
+ case "between":
691
+ return (typeof value === "number" &&
692
+ Array.isArray(clause.value) &&
693
+ typeof clause.value[0] === "number" &&
694
+ typeof clause.value[1] === "number" &&
695
+ value >= clause.value[0] &&
696
+ value <= clause.value[1]);
697
+ }
698
+ }
699
+ function compileMapLibreFilters(filters, sourceId) {
700
+ const compiled = Object.values(filters)
701
+ .filter((clause) => !clause.appliesTo || clause.appliesTo.length === 0 || clause.appliesTo.includes(sourceId))
702
+ .map(clauseToMapLibreFilter)
703
+ .filter((entry) => Array.isArray(entry));
704
+ return compiled.length === 0 ? ["all"] : ["all", ...compiled];
705
+ }
706
+ function clauseToMapLibreFilter(clause) {
707
+ switch (clause.operator) {
708
+ case "=":
709
+ return ["==", clause.field, clause.value];
710
+ case "!=":
711
+ return ["!=", clause.field, clause.value];
712
+ case "in":
713
+ return Array.isArray(clause.value) ? ["in", clause.field, ...clause.value] : undefined;
714
+ case "not-in":
715
+ return Array.isArray(clause.value) ? ["!in", clause.field, ...clause.value] : undefined;
716
+ case "is-null":
717
+ return ["==", clause.field, null];
718
+ case "is-not-null":
719
+ return ["!=", clause.field, null];
720
+ default:
721
+ return undefined;
722
+ }
723
+ }
724
+ function chartBuckets(records, widget, sourceId, filters) {
725
+ const groupBy = chartCategoryField(widget);
726
+ if (!groupBy)
727
+ return [];
728
+ const buckets = new Map();
729
+ for (const record of records) {
730
+ const value = scalarBucketValue(record.attributes[groupBy]);
731
+ if (value === undefined)
732
+ continue;
733
+ const key = String(value);
734
+ const bucket = buckets.get(key) ?? { value, count: 0, targets: [] };
735
+ bucket.count += 1;
736
+ bucket.targets.push(sourceFeatureSelectionTarget(record.sourceId ?? sourceId, record.id));
737
+ buckets.set(key, bucket);
738
+ }
739
+ const active = filters[widget.id]?.value;
740
+ return [...buckets.values()]
741
+ .sort((a, b) => compareValues(a.value, b.value))
742
+ .map((bucket) => ({
743
+ value: bucket.value,
744
+ label: stringValue(bucket.value),
745
+ count: bucket.count,
746
+ selected: active === bucket.value,
747
+ targets: bucket.targets,
748
+ }));
749
+ }
750
+ function filterOptions(records, filters, widget, sourceId) {
751
+ const counts = new Map();
752
+ const active = filters[widget.id]?.value;
753
+ const explicit = widget.options ?? [];
754
+ for (const option of explicit) {
755
+ counts.set(String(option.value), { value: option.value, count: 0 });
756
+ }
757
+ for (const record of records) {
758
+ if (!Object.entries(filters).every(([id, clause]) => id === widget.id || matchesClause(record, clause, sourceId))) {
759
+ continue;
760
+ }
761
+ const value = scalarBucketValue(record.attributes[widget.field]);
762
+ if (value === undefined)
763
+ continue;
764
+ const key = String(value);
765
+ const entry = counts.get(key) ?? { value, count: 0 };
766
+ entry.count += 1;
767
+ counts.set(key, entry);
768
+ }
769
+ return [...counts.values()]
770
+ .sort((a, b) => compareValues(a.value, b.value))
771
+ .map((entry) => {
772
+ const configured = explicit.find((option) => option.value === entry.value);
773
+ return {
774
+ value: entry.value,
775
+ label: configured?.label ?? stringValue(entry.value),
776
+ count: entry.count,
777
+ selected: active === entry.value,
778
+ };
779
+ });
780
+ }
781
+ function chartModel(widget, filteredRecords, sourceId, filters, widgetModels) {
782
+ const chartKind = generatedChartKind(widget);
783
+ const base = {
784
+ id: widget.id,
785
+ kind: "chart",
786
+ chartKind,
787
+ ...(widget.title ? { title: widget.title } : {}),
788
+ sourceId,
789
+ };
790
+ if (chartKind === "histogram") {
791
+ const histogram = widgetModels?.histogram[widget.id] !== undefined
792
+ ? histogramBinsFromWidgetSource(widgetModels.histogram[widget.id])
793
+ : histogramBins(filteredRecords, chartMeasureField(widget), widget.bins, widget.min, widget.max);
794
+ return {
795
+ ...base,
796
+ field: chartMeasureField(widget),
797
+ buckets: [],
798
+ histogramBins: histogram,
799
+ };
800
+ }
801
+ if (chartKind === "time-series") {
802
+ const series = widgetModels?.timeSeries[widget.id] !== undefined
803
+ ? timeSeriesBucketsFromWidgetSource(widgetModels.timeSeries[widget.id])
804
+ : timeSeriesBuckets(filteredRecords, widget);
805
+ return {
806
+ ...base,
807
+ field: chartMeasureField(widget),
808
+ buckets: [],
809
+ timeSeriesBuckets: series.buckets,
810
+ interval: series.interval,
811
+ };
812
+ }
813
+ const groupBy = chartCategoryField(widget);
814
+ return {
815
+ ...base,
816
+ groupBy,
817
+ buckets: widgetModels?.categories[widget.id] !== undefined
818
+ ? chartBucketsFromWidgetSource(widgetModels.categories[widget.id], widget, filters)
819
+ : chartBuckets(filteredRecords, widget, sourceId, filters),
820
+ };
821
+ }
822
+ function chartBucketsFromWidgetSource(result, widget, filters) {
823
+ const active = filters[widget.id]?.value;
824
+ return result.buckets
825
+ .filter((bucket) => scalarBucketValue(bucket.value) !== undefined)
826
+ .map((bucket) => ({
827
+ value: bucket.value,
828
+ label: bucket.label,
829
+ count: bucket.count,
830
+ selected: active === bucket.value,
831
+ targets: [],
832
+ }));
833
+ }
834
+ function histogramBinsFromWidgetSource(result) {
835
+ return result.bins.map((bin) => ({
836
+ id: bin.id,
837
+ min: bin.min,
838
+ max: bin.max,
839
+ label: bin.label,
840
+ count: bin.count,
841
+ percent: bin.percent,
842
+ }));
843
+ }
844
+ function timeSeriesBucketsFromWidgetSource(result) {
845
+ return {
846
+ interval: result.interval,
847
+ buckets: result.buckets.map((bucket) => ({
848
+ id: bucket.id,
849
+ start: bucket.start,
850
+ end: bucket.end,
851
+ label: bucket.label,
852
+ count: bucket.count,
853
+ percent: bucket.percent,
854
+ ...(bucket.metric !== undefined ? { metric: bucket.metric } : {}),
855
+ })),
856
+ };
857
+ }
858
+ function generatedChartKind(widget) {
859
+ return widget.chartKind === "histogram" || widget.chartKind === "time-series" ? widget.chartKind : "categories";
860
+ }
861
+ function chartCategoryField(widget) {
862
+ if (generatedChartKind(widget) !== "categories")
863
+ return undefined;
864
+ return widget.groupBy ?? widget.field;
865
+ }
866
+ function chartMeasureField(widget) {
867
+ return widget.field ?? widget.groupBy ?? widget.metric?.field ?? "OBJECTID";
868
+ }
869
+ function histogramBins(records, field, requestedBins, requestedMin, requestedMax) {
870
+ const values = records.map((record) => numericValue(record.attributes[field])).filter(isNumber);
871
+ const min = requestedMin ?? minNumber(values);
872
+ const max = requestedMax ?? maxNumber(values);
873
+ if (min === undefined || max === undefined)
874
+ return [];
875
+ const count = clampInteger(requestedBins ?? 10, 1, 200);
876
+ const width = max === min ? 1 : (max - min) / count;
877
+ const bins = Array.from({ length: count }, (_, index) => {
878
+ const binMin = min + index * width;
879
+ const binMax = index === count - 1 ? max : min + (index + 1) * width;
880
+ return {
881
+ id: `${index}`,
882
+ min: binMin,
883
+ max: binMax,
884
+ label: `${formatNumber(binMin)} - ${formatNumber(binMax)}`,
885
+ count: 0,
886
+ percent: 0,
887
+ };
888
+ });
889
+ for (const value of values) {
890
+ if (value < min || value > max)
891
+ continue;
892
+ const index = max === min ? 0 : Math.min(count - 1, Math.floor((value - min) / width));
893
+ bins[index] = { ...bins[index], count: bins[index].count + 1 };
894
+ }
895
+ const total = bins.reduce((sum, bin) => sum + bin.count, 0);
896
+ return bins.map((bin) => ({ ...bin, percent: total > 0 ? bin.count / total : 0 }));
897
+ }
898
+ function timeSeriesBuckets(records, widget) {
899
+ const interval = normalizeWidgetInterval(widget.interval);
900
+ const field = chartMeasureField(widget);
901
+ const startLimit = dateValue(widget.start);
902
+ const endLimit = dateValue(widget.end);
903
+ const byStart = new Map();
904
+ for (const record of records) {
905
+ const date = dateValue(record.attributes[field]);
906
+ if (!date)
907
+ continue;
908
+ if (startLimit && date < startLimit)
909
+ continue;
910
+ if (endLimit && date >= endLimit)
911
+ continue;
912
+ const start = truncateWidgetDate(date, interval);
913
+ const key = start.toISOString();
914
+ const entry = byStart.get(key) ?? { start, end: addWidgetInterval(start, interval), count: 0, values: [] };
915
+ entry.count += 1;
916
+ if (widget.metric && widget.metric.fn !== "count") {
917
+ const value = numericValue(record.attributes[widget.metric.field]);
918
+ if (value !== undefined)
919
+ entry.values.push(value);
920
+ }
921
+ byStart.set(key, entry);
922
+ }
923
+ const working = [...byStart.values()].sort((a, b) => a.start.getTime() - b.start.getTime());
924
+ const filled = widget.fillMissing
925
+ ? fillMissingWidgetTimeBuckets(working, interval, widget.start, widget.end)
926
+ : working;
927
+ const total = filled.reduce((sum, bucket) => sum + bucket.count, 0);
928
+ return {
929
+ interval,
930
+ buckets: filled.map((bucket) => ({
931
+ id: bucket.start.toISOString(),
932
+ start: bucket.start.toISOString(),
933
+ end: bucket.end.toISOString(),
934
+ label: formatWidgetTimeLabel(bucket.start, interval),
935
+ count: bucket.count,
936
+ percent: total > 0 ? bucket.count / total : 0,
937
+ ...(widget.metric
938
+ ? {
939
+ metric: widget.metric.fn === "count" ? bucket.count : computeWidgetMetric(bucket.values, widget.metric.fn),
940
+ }
941
+ : {}),
942
+ })),
943
+ };
944
+ }
945
+ function fillMissingWidgetTimeBuckets(buckets, interval, startValue, endValue) {
946
+ if (buckets.length === 0 && (startValue === undefined || endValue === undefined))
947
+ return buckets;
948
+ const first = dateValue(startValue) ?? buckets[0]?.start;
949
+ const lastEnd = dateValue(endValue) ?? buckets.at(-1)?.end;
950
+ if (!first || !lastEnd || first >= lastEnd)
951
+ return buckets;
952
+ const byStart = new Map(buckets.map((bucket) => [bucket.start.toISOString(), bucket]));
953
+ const out = [];
954
+ let cursor = truncateWidgetDate(first, interval);
955
+ while (cursor < lastEnd && out.length < 500) {
956
+ out.push(byStart.get(cursor.toISOString()) ?? {
957
+ start: new Date(cursor.getTime()),
958
+ end: addWidgetInterval(cursor, interval),
959
+ count: 0,
960
+ values: [],
961
+ });
962
+ cursor = addWidgetInterval(cursor, interval);
963
+ }
964
+ return out;
965
+ }
966
+ function filterOptionsFromWidgetSource(result, widget, filters) {
967
+ const active = filters[widget.id]?.value;
968
+ const byValue = new Map(result.buckets.map((bucket) => [String(bucket.value), bucket]));
969
+ const explicit = widget.options ?? [];
970
+ const buckets = explicit.length > 0
971
+ ? explicit.map((option) => ({
972
+ value: option.value,
973
+ label: option.label ?? stringValue(option.value),
974
+ count: byValue.get(String(option.value))?.count ?? 0,
975
+ }))
976
+ : result.buckets
977
+ .filter((bucket) => scalarBucketValue(bucket.value) !== undefined)
978
+ .map((bucket) => ({
979
+ value: bucket.value,
980
+ label: bucket.label,
981
+ count: bucket.count,
982
+ }));
983
+ return buckets.map((bucket) => ({
984
+ value: bucket.value,
985
+ label: bucket.label,
986
+ count: bucket.count,
987
+ selected: active === bucket.value,
988
+ }));
989
+ }
990
+ function selectionContains(selection, record, fallbackSourceId) {
991
+ const sourceId = record.sourceId ?? fallbackSourceId;
992
+ return selection.some((target) => {
993
+ if (isSourceQualifiedSelectionTarget(target))
994
+ return target.sourceId === sourceId && target.id === record.id;
995
+ return target === record.id;
996
+ });
997
+ }
998
+ function inferFields(records) {
999
+ const first = records[0];
1000
+ return first ? Object.keys(first.attributes).slice(0, 6) : [];
1001
+ }
1002
+ function normalizeWidgetInterval(interval) {
1003
+ return {
1004
+ unit: interval?.unit ?? "day",
1005
+ step: clampInteger(interval?.step ?? 1, 1, 10_000),
1006
+ timezone: interval?.timezone ?? "UTC",
1007
+ };
1008
+ }
1009
+ function dateValue(value) {
1010
+ if (value instanceof Date && Number.isFinite(value.getTime()))
1011
+ return new Date(value.getTime());
1012
+ if (typeof value !== "string" && typeof value !== "number")
1013
+ return undefined;
1014
+ const date = new Date(value);
1015
+ return Number.isFinite(date.getTime()) ? date : undefined;
1016
+ }
1017
+ function truncateWidgetDate(date, interval) {
1018
+ const out = new Date(date.getTime());
1019
+ const step = interval.step;
1020
+ switch (interval.unit) {
1021
+ case "minute":
1022
+ out.setUTCSeconds(0, 0);
1023
+ out.setUTCMinutes(Math.floor(out.getUTCMinutes() / step) * step);
1024
+ return out;
1025
+ case "hour":
1026
+ out.setUTCMinutes(0, 0, 0);
1027
+ out.setUTCHours(Math.floor(out.getUTCHours() / step) * step);
1028
+ return out;
1029
+ case "day":
1030
+ return new Date(Date.UTC(out.getUTCFullYear(), out.getUTCMonth(), out.getUTCDate()));
1031
+ case "week": {
1032
+ const day = out.getUTCDay();
1033
+ const mondayOffset = day === 0 ? 6 : day - 1;
1034
+ return new Date(Date.UTC(out.getUTCFullYear(), out.getUTCMonth(), out.getUTCDate() - mondayOffset));
1035
+ }
1036
+ case "month":
1037
+ return new Date(Date.UTC(out.getUTCFullYear(), Math.floor(out.getUTCMonth() / step) * step, 1));
1038
+ case "quarter": {
1039
+ const months = step * 3;
1040
+ return new Date(Date.UTC(out.getUTCFullYear(), Math.floor(out.getUTCMonth() / months) * months, 1));
1041
+ }
1042
+ case "year":
1043
+ return new Date(Date.UTC(Math.floor(out.getUTCFullYear() / step) * step, 0, 1));
1044
+ }
1045
+ }
1046
+ function addWidgetInterval(date, interval) {
1047
+ const out = new Date(date.getTime());
1048
+ switch (interval.unit) {
1049
+ case "minute":
1050
+ out.setUTCMinutes(out.getUTCMinutes() + interval.step);
1051
+ return out;
1052
+ case "hour":
1053
+ out.setUTCHours(out.getUTCHours() + interval.step);
1054
+ return out;
1055
+ case "day":
1056
+ out.setUTCDate(out.getUTCDate() + interval.step);
1057
+ return out;
1058
+ case "week":
1059
+ out.setUTCDate(out.getUTCDate() + interval.step * 7);
1060
+ return out;
1061
+ case "month":
1062
+ out.setUTCMonth(out.getUTCMonth() + interval.step);
1063
+ return out;
1064
+ case "quarter":
1065
+ out.setUTCMonth(out.getUTCMonth() + interval.step * 3);
1066
+ return out;
1067
+ case "year":
1068
+ out.setUTCFullYear(out.getUTCFullYear() + interval.step);
1069
+ return out;
1070
+ }
1071
+ }
1072
+ function formatWidgetTimeLabel(date, interval) {
1073
+ const iso = date.toISOString();
1074
+ if (interval.unit === "year")
1075
+ return iso.slice(0, 4);
1076
+ if (interval.unit === "quarter")
1077
+ return `${iso.slice(0, 4)} Q${Math.floor(date.getUTCMonth() / 3) + 1}`;
1078
+ if (interval.unit === "month")
1079
+ return iso.slice(0, 7);
1080
+ if (interval.unit === "day" || interval.unit === "week")
1081
+ return iso.slice(0, 10);
1082
+ if (interval.unit === "hour")
1083
+ return `${iso.slice(0, 13)}:00Z`;
1084
+ return `${iso.slice(0, 16)}Z`;
1085
+ }
1086
+ function numericValue(value) {
1087
+ if (typeof value === "number" && Number.isFinite(value))
1088
+ return value;
1089
+ if (typeof value === "string" && value.trim() !== "") {
1090
+ const parsed = Number(value);
1091
+ if (Number.isFinite(parsed))
1092
+ return parsed;
1093
+ }
1094
+ return undefined;
1095
+ }
1096
+ function isNumber(value) {
1097
+ return value !== undefined;
1098
+ }
1099
+ function computeWidgetMetric(values, fn) {
1100
+ if (fn === "count")
1101
+ return values.length;
1102
+ if (values.length === 0)
1103
+ return null;
1104
+ switch (fn) {
1105
+ case "sum":
1106
+ return values.reduce((sum, value) => sum + value, 0);
1107
+ case "avg":
1108
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
1109
+ case "min":
1110
+ return minNumber(values) ?? null;
1111
+ case "max":
1112
+ return maxNumber(values) ?? null;
1113
+ case "stddev": {
1114
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
1115
+ const variance = values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length;
1116
+ return Math.sqrt(variance);
1117
+ }
1118
+ case "var": {
1119
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
1120
+ return values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / values.length;
1121
+ }
1122
+ }
1123
+ }
1124
+ function clampInteger(value, min, max) {
1125
+ if (!Number.isFinite(value))
1126
+ return min;
1127
+ return Math.max(min, Math.min(max, Math.trunc(value)));
1128
+ }
1129
+ function minNumber(values) {
1130
+ let min;
1131
+ for (const value of values)
1132
+ min = min === undefined || value < min ? value : min;
1133
+ return min;
1134
+ }
1135
+ function maxNumber(values) {
1136
+ let max;
1137
+ for (const value of values)
1138
+ max = max === undefined || value > max ? value : max;
1139
+ return max;
1140
+ }
1141
+ function formatNumber(value) {
1142
+ return Number.isInteger(value) ? String(value) : value.toFixed(2).replace(/\.?0+$/, "");
1143
+ }
1144
+ function compareValues(a, b, direction = "asc") {
1145
+ const multiplier = direction === "desc" ? -1 : 1;
1146
+ if (typeof a === "number" && typeof b === "number")
1147
+ return (a - b) * multiplier;
1148
+ return stringValue(a).localeCompare(stringValue(b)) * multiplier;
1149
+ }
1150
+ function scalarBucketValue(value) {
1151
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? value : undefined;
1152
+ }
1153
+ function stringValue(value) {
1154
+ return value === undefined || value === null ? "" : String(value);
1155
+ }
1156
+ function stableWidgetProjectionKey(projection) {
1157
+ return stableStringify({
1158
+ filters: projection.filters,
1159
+ spatialFilter: projection.spatialFilter,
1160
+ extent: projection.extent,
1161
+ orderBy: projection.orderBy,
1162
+ pagination: projection.pagination,
1163
+ outFields: projection.outFields,
1164
+ grouping: projection.grouping,
1165
+ aggregation: projection.aggregation,
1166
+ selection: projection.selection,
1167
+ });
1168
+ }
1169
+ function stableStringify(value) {
1170
+ if (value === null || typeof value !== "object")
1171
+ return JSON.stringify(value);
1172
+ if (Array.isArray(value))
1173
+ return `[${value.map(stableStringify).join(",")}]`;
1174
+ const obj = value;
1175
+ return `{${Object.keys(obj)
1176
+ .sort()
1177
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`)
1178
+ .join(",")}}`;
1179
+ }
1180
+ function unique(values) {
1181
+ return [...new Set(values)];
1182
+ }
1183
+ async function runWithConcurrency(tasks, concurrency) {
1184
+ const limit = clampInteger(concurrency, 1, tasks.length || 1);
1185
+ let next = 0;
1186
+ async function worker() {
1187
+ while (next < tasks.length) {
1188
+ const task = tasks[next];
1189
+ next += 1;
1190
+ if (!task)
1191
+ continue;
1192
+ await task();
1193
+ }
1194
+ }
1195
+ await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, () => worker()));
1196
+ }