@honua/react 0.0.20-alpha.0 → 0.1.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/contract/discovery.d.ts +231 -0
  2. package/contract/discovery.d.ts.map +1 -0
  3. package/contract/discovery.js +554 -0
  4. package/contract/edit-sketch.d.ts +8 -0
  5. package/contract/edit-sketch.d.ts.map +1 -1
  6. package/contract/edit-sketch.js +15 -0
  7. package/contract/edit-snapping.d.ts +160 -0
  8. package/contract/edit-snapping.d.ts.map +1 -0
  9. package/contract/edit-snapping.js +675 -0
  10. package/contract/generated/projjson-v0.7-crs-validator.d.ts +35 -0
  11. package/contract/generated/projjson-v0.7-crs-validator.d.ts.map +1 -0
  12. package/contract/generated/projjson-v0.7-crs-validator.js +3941 -0
  13. package/contract/index.d.ts +12 -1
  14. package/contract/index.d.ts.map +1 -1
  15. package/contract/index.js +4 -0
  16. package/contract/pmtiles.d.ts +193 -0
  17. package/contract/pmtiles.d.ts.map +1 -0
  18. package/contract/pmtiles.js +195 -0
  19. package/contract/protocol-module.d.ts +70 -0
  20. package/contract/protocol-module.d.ts.map +1 -0
  21. package/contract/protocol-module.js +1 -0
  22. package/contract/schema-envelope.d.ts +26 -0
  23. package/contract/schema-envelope.d.ts.map +1 -0
  24. package/contract/schema-envelope.js +25 -0
  25. package/contract/schema.d.ts +582 -0
  26. package/contract/schema.d.ts.map +1 -0
  27. package/contract/schema.js +2483 -0
  28. package/contract/source-capability-support.d.ts +6 -0
  29. package/contract/source-capability-support.d.ts.map +1 -0
  30. package/contract/source-capability-support.js +154 -0
  31. package/contract/source.d.ts +57 -15
  32. package/contract/source.d.ts.map +1 -1
  33. package/contract/source.js +368 -65
  34. package/contract/types.d.ts +171 -6
  35. package/contract/types.d.ts.map +1 -1
  36. package/contract/types.js +14 -14
  37. package/core/auth/client-credentials-provider.d.ts +51 -0
  38. package/core/auth/client-credentials-provider.d.ts.map +1 -0
  39. package/core/auth/client-credentials-provider.js +115 -0
  40. package/core/auth/credential-store.d.ts +52 -0
  41. package/core/auth/credential-store.d.ts.map +1 -0
  42. package/core/auth/credential-store.js +82 -0
  43. package/core/auth/index.d.ts +23 -0
  44. package/core/auth/index.d.ts.map +1 -0
  45. package/core/auth/index.js +20 -0
  46. package/core/auth/oauth2-provider.d.ts +114 -0
  47. package/core/auth/oauth2-provider.d.ts.map +1 -0
  48. package/core/auth/oauth2-provider.js +408 -0
  49. package/core/auth/pkce.d.ts +25 -0
  50. package/core/auth/pkce.d.ts.map +1 -0
  51. package/core/auth/pkce.js +46 -0
  52. package/core/auth/static-providers.d.ts +20 -0
  53. package/core/auth/static-providers.d.ts.map +1 -0
  54. package/core/auth/static-providers.js +26 -0
  55. package/core/auth/token-endpoint.d.ts +40 -0
  56. package/core/auth/token-endpoint.d.ts.map +1 -0
  57. package/core/auth/token-endpoint.js +133 -0
  58. package/core/auth/types.d.ts +144 -0
  59. package/core/auth/types.d.ts.map +1 -0
  60. package/core/auth/types.js +8 -0
  61. package/core/bounded-json.d.ts +4 -0
  62. package/core/bounded-json.d.ts.map +1 -0
  63. package/core/bounded-json.js +38 -0
  64. package/core/cache-state.d.ts +9 -0
  65. package/core/cache-state.d.ts.map +1 -1
  66. package/core/cache-state.js +10 -0
  67. package/core/capabilities-xml.d.ts +33 -0
  68. package/core/capabilities-xml.d.ts.map +1 -0
  69. package/core/capabilities-xml.js +331 -0
  70. package/core/client.d.ts +35 -2
  71. package/core/client.d.ts.map +1 -1
  72. package/core/client.js +167 -29
  73. package/core/error-classifications.d.ts +153 -0
  74. package/core/error-classifications.d.ts.map +1 -0
  75. package/core/error-classifications.js +140 -0
  76. package/core/error-code-registry.d.ts +158 -0
  77. package/core/error-code-registry.d.ts.map +1 -0
  78. package/core/error-code-registry.js +143 -0
  79. package/core/error-envelope.d.ts +68 -0
  80. package/core/error-envelope.d.ts.map +1 -0
  81. package/core/error-envelope.js +357 -0
  82. package/core/errors.d.ts +73 -25
  83. package/core/errors.d.ts.map +1 -1
  84. package/core/errors.js +113 -46
  85. package/core/geoparquet-sql.d.ts +190 -0
  86. package/core/geoparquet-sql.d.ts.map +1 -0
  87. package/core/geoparquet-sql.js +368 -0
  88. package/core/odata-key-path.d.ts +12 -0
  89. package/core/odata-key-path.d.ts.map +1 -0
  90. package/core/odata-key-path.js +28 -0
  91. package/core/odata-write-codec.d.ts +66 -0
  92. package/core/odata-write-codec.d.ts.map +1 -0
  93. package/core/odata-write-codec.js +1083 -0
  94. package/core/odata.d.ts +59 -7
  95. package/core/odata.d.ts.map +1 -1
  96. package/core/odata.js +431 -99
  97. package/core/ogc-endpoint-layout.d.ts +70 -0
  98. package/core/ogc-endpoint-layout.d.ts.map +1 -0
  99. package/core/ogc-endpoint-layout.js +173 -0
  100. package/core/ogc-features.d.ts.map +1 -1
  101. package/core/ogc-features.js +35 -17
  102. package/core/ogc-maps.d.ts +7 -0
  103. package/core/ogc-maps.d.ts.map +1 -1
  104. package/core/ogc-maps.js +46 -7
  105. package/core/ogc-processes.d.ts +2 -1
  106. package/core/ogc-processes.d.ts.map +1 -1
  107. package/core/ogc-processes.js +33 -5
  108. package/core/ogc-records.d.ts +9 -0
  109. package/core/ogc-records.d.ts.map +1 -1
  110. package/core/ogc-records.js +78 -29
  111. package/core/ogc-tiles.d.ts +10 -1
  112. package/core/ogc-tiles.d.ts.map +1 -1
  113. package/core/ogc-tiles.js +56 -17
  114. package/core/path-utils.d.ts +9 -0
  115. package/core/path-utils.d.ts.map +1 -1
  116. package/core/path-utils.js +19 -0
  117. package/core/protocol-transport.d.ts +1 -0
  118. package/core/protocol-transport.d.ts.map +1 -1
  119. package/core/request-pipeline.d.ts.map +1 -1
  120. package/core/request-pipeline.js +1 -1
  121. package/core/spatial-filter.d.ts +8 -4
  122. package/core/spatial-filter.d.ts.map +1 -1
  123. package/core/spatial-filter.js +206 -16
  124. package/core/stac-static.d.ts +55 -0
  125. package/core/stac-static.d.ts.map +1 -0
  126. package/core/stac-static.js +386 -0
  127. package/core/stac.d.ts +12 -0
  128. package/core/stac.d.ts.map +1 -1
  129. package/core/stac.js +45 -15
  130. package/core/surfaces.d.ts +13 -0
  131. package/core/surfaces.d.ts.map +1 -1
  132. package/core/surfaces.js +127 -16
  133. package/core/types.d.ts +174 -7
  134. package/core/types.d.ts.map +1 -1
  135. package/core/wfs-capabilities.d.ts +12 -0
  136. package/core/wfs-capabilities.d.ts.map +1 -1
  137. package/core/wfs-capabilities.js +22 -3
  138. package/core/wfs.d.ts +13 -0
  139. package/core/wfs.d.ts.map +1 -1
  140. package/core/wfs.js +35 -5
  141. package/core/wms-capabilities.d.ts +56 -84
  142. package/core/wms-capabilities.d.ts.map +1 -1
  143. package/core/wms-capabilities.js +212 -509
  144. package/core/wmts-capabilities.d.ts +62 -62
  145. package/core/wmts-capabilities.d.ts.map +1 -1
  146. package/core/wmts-capabilities.js +224 -371
  147. package/esri-compat/editor.d.ts +8 -0
  148. package/esri-compat/editor.d.ts.map +1 -1
  149. package/esri-compat/editor.js +13 -0
  150. package/esri-compat/feature-layer.d.ts +2 -0
  151. package/esri-compat/feature-layer.d.ts.map +1 -1
  152. package/esri-compat/feature-layer.js +1 -0
  153. package/esri-compat/identity-manager.d.ts +43 -0
  154. package/esri-compat/identity-manager.d.ts.map +1 -1
  155. package/esri-compat/identity-manager.js +131 -1
  156. package/esri-compat/layer-list.d.ts +11 -0
  157. package/esri-compat/layer-list.d.ts.map +1 -1
  158. package/esri-compat/layer-list.js +49 -0
  159. package/esri-compat/legend.d.ts +10 -0
  160. package/esri-compat/legend.d.ts.map +1 -1
  161. package/esri-compat/legend.js +27 -0
  162. package/esri-compat/oauth-info.d.ts +15 -0
  163. package/esri-compat/oauth-info.d.ts.map +1 -1
  164. package/esri-compat/oauth-info.js +27 -0
  165. package/esri-compat/portal.d.ts +197 -0
  166. package/esri-compat/portal.d.ts.map +1 -0
  167. package/esri-compat/portal.js +251 -0
  168. package/esri-compat/renderer-objects.d.ts +40 -0
  169. package/esri-compat/renderer-objects.d.ts.map +1 -0
  170. package/esri-compat/renderer-objects.js +62 -0
  171. package/esri-compat/sketch.d.ts +43 -0
  172. package/esri-compat/sketch.d.ts.map +1 -1
  173. package/esri-compat/sketch.js +46 -0
  174. package/esri-compat/snapping.d.ts +43 -0
  175. package/esri-compat/snapping.d.ts.map +1 -0
  176. package/esri-compat/snapping.js +45 -0
  177. package/esri-compat/url.d.ts.map +1 -1
  178. package/esri-compat/url.js +1 -1
  179. package/esri-compat/widget-host.d.ts +84 -0
  180. package/esri-compat/widget-host.d.ts.map +1 -0
  181. package/esri-compat/widget-host.js +159 -0
  182. package/filter-registry/index.d.ts +145 -0
  183. package/filter-registry/index.d.ts.map +1 -0
  184. package/filter-registry/index.js +531 -0
  185. package/generated-app/errors.d.ts +18 -2
  186. package/generated-app/errors.d.ts.map +1 -1
  187. package/generated-app/errors.js +44 -11
  188. package/map/automatic-mount-integration.d.ts +134 -0
  189. package/map/automatic-mount-integration.d.ts.map +1 -0
  190. package/map/automatic-mount-integration.js +305 -0
  191. package/map/automatic-source-strategy.d.ts +125 -0
  192. package/map/automatic-source-strategy.d.ts.map +1 -0
  193. package/map/automatic-source-strategy.js +494 -0
  194. package/map/data-to-map-bridge.d.ts +293 -0
  195. package/map/data-to-map-bridge.d.ts.map +1 -0
  196. package/map/data-to-map-bridge.js +817 -0
  197. package/map/geojson-projection.d.ts +33 -0
  198. package/map/geojson-projection.d.ts.map +1 -0
  199. package/map/geojson-projection.js +118 -0
  200. package/map/index.d.ts +14 -0
  201. package/map/index.d.ts.map +1 -1
  202. package/map/index.js +8 -0
  203. package/map/raster-source-spec.d.ts +30 -0
  204. package/map/raster-source-spec.d.ts.map +1 -0
  205. package/map/raster-source-spec.js +190 -0
  206. package/map/raster-source-strategy.d.ts +65 -0
  207. package/map/raster-source-strategy.d.ts.map +1 -0
  208. package/map/raster-source-strategy.js +232 -0
  209. package/map/source-to-maplibre.d.ts +91 -0
  210. package/map/source-to-maplibre.d.ts.map +1 -0
  211. package/map/source-to-maplibre.js +454 -0
  212. package/map/temporal-playback.d.ts +139 -0
  213. package/map/temporal-playback.d.ts.map +1 -0
  214. package/map/temporal-playback.js +247 -0
  215. package/package.json +19 -1
  216. package/query-planner/canonical.d.ts +7 -0
  217. package/query-planner/canonical.d.ts.map +1 -0
  218. package/query-planner/canonical.js +145 -0
  219. package/query-planner/cql2-json.d.ts +17 -0
  220. package/query-planner/cql2-json.d.ts.map +1 -0
  221. package/query-planner/cql2-json.js +646 -0
  222. package/query-planner/diagnostics.d.ts +35 -0
  223. package/query-planner/diagnostics.d.ts.map +1 -0
  224. package/query-planner/diagnostics.js +373 -0
  225. package/query-planner/duckdb.d.ts +79 -0
  226. package/query-planner/duckdb.d.ts.map +1 -0
  227. package/query-planner/duckdb.js +758 -0
  228. package/query-planner/execution-context.d.ts +5 -0
  229. package/query-planner/execution-context.d.ts.map +1 -0
  230. package/query-planner/execution-context.js +50 -0
  231. package/query-planner/executor.d.ts +5 -0
  232. package/query-planner/executor.d.ts.map +1 -0
  233. package/query-planner/executor.js +223 -0
  234. package/query-planner/geoservices.d.ts +91 -0
  235. package/query-planner/geoservices.d.ts.map +1 -0
  236. package/query-planner/geoservices.js +667 -0
  237. package/query-planner/grpc.d.ts +100 -0
  238. package/query-planner/grpc.d.ts.map +1 -0
  239. package/query-planner/grpc.js +736 -0
  240. package/query-planner/index.d.ts +44 -0
  241. package/query-planner/index.d.ts.map +1 -0
  242. package/query-planner/index.js +30 -0
  243. package/query-planner/ir.d.ts +20 -0
  244. package/query-planner/ir.d.ts.map +1 -0
  245. package/query-planner/ir.js +417 -0
  246. package/query-planner/local-aggregate.d.ts +5 -0
  247. package/query-planner/local-aggregate.d.ts.map +1 -0
  248. package/query-planner/local-aggregate.js +126 -0
  249. package/query-planner/odata.d.ts +48 -0
  250. package/query-planner/odata.d.ts.map +1 -0
  251. package/query-planner/odata.js +662 -0
  252. package/query-planner/ogc-compiler.d.ts +55 -0
  253. package/query-planner/ogc-compiler.d.ts.map +1 -0
  254. package/query-planner/ogc-compiler.js +480 -0
  255. package/query-planner/ogc-features.d.ts +53 -0
  256. package/query-planner/ogc-features.d.ts.map +1 -0
  257. package/query-planner/ogc-features.js +617 -0
  258. package/query-planner/planner.d.ts +17 -0
  259. package/query-planner/planner.d.ts.map +1 -0
  260. package/query-planner/planner.js +818 -0
  261. package/query-planner/resource.d.ts +94 -0
  262. package/query-planner/resource.d.ts.map +1 -0
  263. package/query-planner/resource.js +526 -0
  264. package/query-planner/semantic-canonical.d.ts +15 -0
  265. package/query-planner/semantic-canonical.d.ts.map +1 -0
  266. package/query-planner/semantic-canonical.js +62 -0
  267. package/query-planner/semantic-compat.d.ts +10 -0
  268. package/query-planner/semantic-compat.d.ts.map +1 -0
  269. package/query-planner/semantic-compat.js +35 -0
  270. package/query-planner/semantic-compiler.d.ts +64 -0
  271. package/query-planner/semantic-compiler.d.ts.map +1 -0
  272. package/query-planner/semantic-compiler.js +81 -0
  273. package/query-planner/semantic-literals.d.ts +30 -0
  274. package/query-planner/semantic-literals.d.ts.map +1 -0
  275. package/query-planner/semantic-literals.js +133 -0
  276. package/query-planner/semantic-types.d.ts +265 -0
  277. package/query-planner/semantic-types.d.ts.map +1 -0
  278. package/query-planner/semantic-types.js +1 -0
  279. package/query-planner/semantic.d.ts +54 -0
  280. package/query-planner/semantic.d.ts.map +1 -0
  281. package/query-planner/semantic.js +1421 -0
  282. package/query-planner/types.d.ts +560 -0
  283. package/query-planner/types.d.ts.map +1 -0
  284. package/query-planner/types.js +49 -0
  285. package/query-planner/wfs-semantic.d.ts +58 -0
  286. package/query-planner/wfs-semantic.d.ts.map +1 -0
  287. package/query-planner/wfs-semantic.js +547 -0
  288. package/query-planner/wfs.d.ts +6 -0
  289. package/query-planner/wfs.d.ts.map +1 -0
  290. package/query-planner/wfs.js +71 -0
  291. package/react/external-map.d.ts +67 -0
  292. package/react/external-map.d.ts.map +1 -0
  293. package/react/external-map.js +63 -0
  294. package/react/honua-map.d.ts.map +1 -1
  295. package/react/honua-map.js +3 -2
  296. package/react/honua-source-layer.d.ts +110 -0
  297. package/react/honua-source-layer.d.ts.map +1 -0
  298. package/react/honua-source-layer.js +101 -0
  299. package/react/hooks.d.ts +28 -0
  300. package/react/hooks.d.ts.map +1 -1
  301. package/react/hooks.js +26 -4
  302. package/react/index.d.ts +8 -0
  303. package/react/index.d.ts.map +1 -1
  304. package/react/index.js +5 -0
  305. package/react/query-cache.d.ts +26 -4
  306. package/react/query-cache.d.ts.map +1 -1
  307. package/react/query-cache.js +51 -8
  308. package/react/selection.d.ts +177 -0
  309. package/react/selection.d.ts.map +1 -0
  310. package/react/selection.js +0 -0
  311. package/react/use-mounted-source.d.ts +69 -0
  312. package/react/use-mounted-source.d.ts.map +1 -0
  313. package/react/use-mounted-source.js +346 -0
  314. package/runtime/edit-snapping.d.ts +107 -0
  315. package/runtime/edit-snapping.d.ts.map +1 -0
  316. package/runtime/edit-snapping.js +190 -0
  317. package/runtime/errors.d.ts +3 -2
  318. package/runtime/errors.d.ts.map +1 -1
  319. package/runtime/errors.js +19 -2
  320. package/runtime/index.d.ts +8 -2
  321. package/runtime/index.d.ts.map +1 -1
  322. package/runtime/index.js +4 -4
  323. package/runtime/load-package.d.ts.map +1 -1
  324. package/runtime/load-package.js +8 -0
  325. package/runtime/map-package-validation.d.ts +0 -13
  326. package/runtime/map-package-validation.d.ts.map +1 -1
  327. package/runtime/map-package-validation.js +0 -12
  328. package/runtime/map-package.d.ts +1 -1
  329. package/runtime/map-package.d.ts.map +1 -1
  330. package/runtime/maplibre-renderer.d.ts +41 -0
  331. package/runtime/maplibre-renderer.d.ts.map +1 -0
  332. package/runtime/maplibre-renderer.js +322 -0
  333. package/runtime/pmtiles-protocol.d.ts +77 -0
  334. package/runtime/pmtiles-protocol.d.ts.map +1 -0
  335. package/runtime/pmtiles-protocol.js +120 -0
  336. package/runtime/query-tiles.d.ts +2 -1
  337. package/runtime/query-tiles.d.ts.map +1 -1
  338. package/runtime/query-tiles.js +6 -2
  339. package/runtime/source-bridge.d.ts +4 -4
  340. package/runtime/source-bridge.d.ts.map +1 -1
  341. package/runtime/source-bridge.js +36 -56
  342. package/runtime/style-interactions.d.ts +3 -2
  343. package/runtime/style-interactions.d.ts.map +1 -1
  344. package/runtime/style-interactions.js +11 -3
  345. package/runtime/terra-draw-sketch.d.ts +275 -0
  346. package/runtime/terra-draw-sketch.d.ts.map +1 -0
  347. package/runtime/terra-draw-sketch.js +404 -0
  348. package/source-capability-registry.d.ts +1 -0
  349. package/source-capability-registry.js +1 -0
  350. package/source-capability-types.d.ts +186 -0
  351. package/source-capability-types.js +7 -0
  352. package/style/index.d.ts +2 -0
  353. package/style/index.d.ts.map +1 -1
  354. package/style/index.js +2 -0
  355. package/style/renderers.d.ts +326 -0
  356. package/style/renderers.d.ts.map +1 -0
  357. package/style/renderers.js +517 -0
  358. package/webmap/convert-renderer.d.ts +24 -3
  359. package/webmap/convert-renderer.d.ts.map +1 -1
  360. package/webmap/convert-renderer.js +93 -112
  361. package/webmap/index.d.ts +1 -1
  362. package/webmap/index.d.ts.map +1 -1
  363. package/webmap/index.js +1 -1
@@ -64,22 +64,46 @@ export class HonuaQueryCache {
64
64
  error: undefined,
65
65
  isLoading: false,
66
66
  isFetching: false,
67
+ dataUpdatedAt: entry.snapshot.dataUpdatedAt,
67
68
  };
68
69
  }
69
70
  }
70
71
  };
71
72
  }
72
73
  /**
73
- * Kick off a fetch for `key` only when it has never resolved and is not
74
- * already in flight. This is the idempotent entry point hooks call from an
75
- * effect; StrictMode's double-invoke therefore does not double-fetch.
74
+ * Kick off a fetch for `key` when it has never resolved and is not already
75
+ * in flight. This is the idempotent entry point hooks call from an effect;
76
+ * StrictMode's double-invoke therefore does not double-fetch.
77
+ *
78
+ * With `options.staleTimeMs`, a resolved entry whose data is at least that
79
+ * old is additionally revalidated in the background (stale-while-revalidate:
80
+ * the cached data stays served while `isFetching` is true). `0` revalidates
81
+ * on every ensure; omitted keeps the historical never-revalidate behavior.
76
82
  */
77
- ensure(key, fetcher) {
83
+ ensure(key, fetcher, options = {}) {
78
84
  const entry = this.entryFor(key);
79
85
  if (entry.snapshot.status === "idle") {
80
86
  this.run(key, fetcher);
87
+ return;
88
+ }
89
+ if (options.staleTimeMs !== undefined &&
90
+ entry.snapshot.status === "success" &&
91
+ !entry.snapshot.isFetching &&
92
+ Date.now() - (entry.snapshot.dataUpdatedAt ?? 0) >= options.staleTimeMs) {
93
+ this.run(key, fetcher);
81
94
  }
82
95
  }
96
+ /**
97
+ * The promise of the in-flight run for `key`, or `undefined` when no fetch
98
+ * is running. Suspense-mode hooks throw this promise while the first load is
99
+ * pending; it never rejects (errors land on the snapshot instead).
100
+ *
101
+ * @experimental
102
+ */
103
+ getPromise(key) {
104
+ const entry = this.entries.get(key);
105
+ return entry?.snapshot.isFetching ? entry.promise : undefined;
106
+ }
83
107
  /**
84
108
  * Force a (re)fetch for `key`, superseding any in-flight request. The last
85
109
  * resolved `data` is preserved while the refetch runs.
@@ -97,8 +121,9 @@ export class HonuaQueryCache {
97
121
  error: undefined,
98
122
  isLoading: entry.snapshot.data === undefined,
99
123
  isFetching: true,
124
+ dataUpdatedAt: entry.snapshot.dataUpdatedAt,
100
125
  });
101
- fetcher(controller.signal).then((value) => {
126
+ entry.promise = fetcher(controller.signal).then((value) => {
102
127
  if (entry.token !== token)
103
128
  return;
104
129
  entry.controller = undefined;
@@ -108,6 +133,7 @@ export class HonuaQueryCache {
108
133
  error: undefined,
109
134
  isLoading: false,
110
135
  isFetching: false,
136
+ dataUpdatedAt: Date.now(),
111
137
  });
112
138
  }, (error) => {
113
139
  if (entry.token !== token || controller.signal.aborted)
@@ -119,6 +145,7 @@ export class HonuaQueryCache {
119
145
  error,
120
146
  isLoading: false,
121
147
  isFetching: false,
148
+ dataUpdatedAt: entry.snapshot.dataUpdatedAt,
122
149
  });
123
150
  });
124
151
  }
@@ -144,7 +171,7 @@ export class HonuaQueryCache {
144
171
  entryFor(key) {
145
172
  let entry = this.entries.get(key);
146
173
  if (!entry) {
147
- entry = { snapshot: IDLE_SNAPSHOT, listeners: new Set(), controller: undefined, token: 0 };
174
+ entry = { snapshot: IDLE_SNAPSHOT, listeners: new Set(), controller: undefined, token: 0, promise: undefined };
148
175
  this.entries.set(key, entry);
149
176
  }
150
177
  return entry;
@@ -174,8 +201,8 @@ function stableStringify(value) {
174
201
  if (Array.isArray(value)) {
175
202
  return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
176
203
  }
177
- if (value instanceof Set) {
178
- return `[${[...value]
204
+ if (isReadonlySet(value)) {
205
+ return `[${[...value.values()]
179
206
  .map((entry) => stableStringify(entry))
180
207
  .sort()
181
208
  .join(",")}]`;
@@ -186,3 +213,19 @@ function stableStringify(value) {
186
213
  .sort();
187
214
  return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
188
215
  }
216
+ /**
217
+ * Recognize native, cross-realm, and intentionally branded immutable sets.
218
+ * Requiring the complete ReadonlySet surface plus the Set brand avoids
219
+ * consuming strings, maps, generators, or arbitrary domain iterables.
220
+ */
221
+ function isReadonlySet(value) {
222
+ const candidate = value;
223
+ return (candidate[Symbol.toStringTag] === "Set" &&
224
+ typeof candidate.size === "number" &&
225
+ typeof candidate.has === "function" &&
226
+ typeof candidate.entries === "function" &&
227
+ typeof candidate.keys === "function" &&
228
+ typeof candidate.values === "function" &&
229
+ typeof candidate.forEach === "function" &&
230
+ typeof candidate[Symbol.iterator] === "function");
231
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Shared selection / hover state for `@honua/react` (REQ-004 of the react
3
+ * depth pass), built on the interactions layer's source-qualified selection
4
+ * targets and feature-state primitives so map and non-map components observe
5
+ * the same state.
6
+ *
7
+ * - {@link HonuaSelectionProvider} owns a {@link HonuaSelectionStore} (a plain
8
+ * external store read through `useSyncExternalStore`).
9
+ * - {@link useSelection} / {@link useHover} expose the state to any component.
10
+ * - {@link useMapSelectionBinding} / {@link useMapHoverBinding} wire a MapLibre
11
+ * layer set into the store: clicks toggle selection, pointer moves publish
12
+ * hover, and store changes are mirrored onto MapLibre feature-state (via the
13
+ * interactions layer's `setFeatureState`) so paint expressions react to
14
+ * selections made from a sidebar just like map clicks.
15
+ *
16
+ * SSR-safe: no `window` / `document` access at module scope.
17
+ *
18
+ * @module
19
+ */
20
+ import { type ReactNode } from "react";
21
+ import type { SourceQualifiedFeatureSelectionTarget } from "../exploration/types.js";
22
+ import type { DataToMapLibreMap } from "../map/data-to-map-bridge.js";
23
+ /** Immutable snapshot of the shared selection / hover state. @experimental */
24
+ export interface HonuaSelectionSnapshot {
25
+ /** Source-qualified selected features, in selection order. */
26
+ readonly selected: readonly SourceQualifiedFeatureSelectionTarget[];
27
+ /** The feature currently under the pointer, or `null`. */
28
+ readonly hovered: SourceQualifiedFeatureSelectionTarget | null;
29
+ }
30
+ /**
31
+ * Framework-neutral external store behind {@link HonuaSelectionProvider}.
32
+ * Exposed so tests and non-React integrations can drive the same state.
33
+ *
34
+ * @experimental
35
+ */
36
+ export declare class HonuaSelectionStore {
37
+ private snapshot;
38
+ private readonly listeners;
39
+ subscribe: (listener: () => void) => (() => void);
40
+ getSnapshot: () => HonuaSelectionSnapshot;
41
+ isSelected(target: SourceQualifiedFeatureSelectionTarget): boolean;
42
+ /**
43
+ * Select a feature. Non-additive (default) replaces the selection —
44
+ * single-select semantics; `additive` appends (multi-select).
45
+ */
46
+ select(target: SourceQualifiedFeatureSelectionTarget, options?: {
47
+ additive?: boolean;
48
+ }): void;
49
+ deselect(target: SourceQualifiedFeatureSelectionTarget): void;
50
+ /** Toggle a feature's membership (map-click semantics). */
51
+ toggle(target: SourceQualifiedFeatureSelectionTarget, options?: {
52
+ additive?: boolean;
53
+ }): void;
54
+ clear(): void;
55
+ setHovered(target: SourceQualifiedFeatureSelectionTarget | null): void;
56
+ private write;
57
+ }
58
+ /**
59
+ * Context carrying the shared selection store. `null` outside a
60
+ * {@link HonuaSelectionProvider}; the hooks throw a descriptive error then.
61
+ *
62
+ * @experimental
63
+ */
64
+ export declare const HonuaSelectionContext: import("react").Context<HonuaSelectionStore | null>;
65
+ /** Props for {@link HonuaSelectionProvider}. @experimental */
66
+ export interface HonuaSelectionProviderProps {
67
+ /**
68
+ * Optional externally-owned store — share one across providers or pre-seed
69
+ * it in tests. Omit to let the provider own a fresh store.
70
+ */
71
+ store?: HonuaSelectionStore;
72
+ /** Observe every selection change (fires after the state updates). */
73
+ onSelectionChange?: (selected: readonly SourceQualifiedFeatureSelectionTarget[]) => void;
74
+ children?: ReactNode;
75
+ }
76
+ /**
77
+ * Provide shared selection / hover state to the subtree. Map components bind
78
+ * through {@link useMapSelectionBinding} (or `HonuaSourceLayer`'s `selection`
79
+ * prop); sidebars, tables, and charts read/write the same state through
80
+ * {@link useSelection} and {@link useHover}.
81
+ *
82
+ * @experimental
83
+ */
84
+ export declare function HonuaSelectionProvider({ store, onSelectionChange, children }: HonuaSelectionProviderProps): ReactNode;
85
+ /** Result of {@link useSelection}. @experimental */
86
+ export interface UseSelectionResult {
87
+ /** Source-qualified selected features, in selection order. */
88
+ selected: readonly SourceQualifiedFeatureSelectionTarget[];
89
+ isSelected(target: SourceQualifiedFeatureSelectionTarget): boolean;
90
+ /** Select (replace, or append with `{ additive: true }`). */
91
+ select(target: SourceQualifiedFeatureSelectionTarget, options?: {
92
+ additive?: boolean;
93
+ }): void;
94
+ deselect(target: SourceQualifiedFeatureSelectionTarget): void;
95
+ /** Toggle membership — map-click semantics. */
96
+ toggle(target: SourceQualifiedFeatureSelectionTarget, options?: {
97
+ additive?: boolean;
98
+ }): void;
99
+ clear(): void;
100
+ }
101
+ /**
102
+ * Read and mutate the shared selection. Works in any component under a
103
+ * {@link HonuaSelectionProvider} — map-attached or not.
104
+ *
105
+ * @throws outside a `HonuaSelectionProvider`.
106
+ * @experimental
107
+ */
108
+ export declare function useSelection(): UseSelectionResult;
109
+ /** Result of {@link useHover}. @experimental */
110
+ export interface UseHoverResult {
111
+ /** The feature currently under the pointer, or `null`. */
112
+ hovered: SourceQualifiedFeatureSelectionTarget | null;
113
+ isHovered(target: SourceQualifiedFeatureSelectionTarget): boolean;
114
+ setHovered(target: SourceQualifiedFeatureSelectionTarget | null): void;
115
+ clearHovered(): void;
116
+ }
117
+ /**
118
+ * Read and publish the shared hover state.
119
+ *
120
+ * @throws outside a `HonuaSelectionProvider`.
121
+ * @experimental
122
+ */
123
+ export declare function useHover(): UseHoverResult;
124
+ /** Options for {@link useMapSelectionBinding}. @experimental */
125
+ export interface MapSelectionBindingOptions {
126
+ /** MapLibre source id whose features participate. */
127
+ sourceId: string;
128
+ /** Layer ids whose clicks toggle selection. */
129
+ layerIds: readonly string[];
130
+ /** Vector `source-layer` (tile sources). */
131
+ sourceLayer?: string;
132
+ /** Feature-state key mirrored for selected features. @default "selected" */
133
+ stateKey?: string;
134
+ /** Map clicks add to the selection instead of replacing it. @default false */
135
+ multiSelect?: boolean;
136
+ /** Disable the binding without unmounting. @default true */
137
+ enabled?: boolean;
138
+ }
139
+ /**
140
+ * Two-way binding between a mounted MapLibre layer set and the enclosing
141
+ * {@link HonuaSelectionProvider}:
142
+ *
143
+ * - layer clicks toggle the clicked feature in the shared store;
144
+ * - every store change (from the map *or* from non-map components) is mirrored
145
+ * onto MapLibre feature-state under `stateKey`, so paint expressions like
146
+ * `["case", ["boolean", ["feature-state", "selected"], false], …]` respond.
147
+ *
148
+ * Requires a map with `on`/`off` and `setFeatureState` (any MapLibre map).
149
+ * No-ops while the map is `null` or there is no enclosing
150
+ * `HonuaSelectionProvider`. StrictMode-safe: listeners and mirrored
151
+ * feature-state are fully removed on cleanup.
152
+ *
153
+ * @experimental
154
+ */
155
+ export declare function useMapSelectionBinding(map: DataToMapLibreMap | null | undefined, options: MapSelectionBindingOptions): void;
156
+ /** Options for {@link useMapHoverBinding}. @experimental */
157
+ export interface MapHoverBindingOptions {
158
+ /** MapLibre source id whose features participate. */
159
+ sourceId: string;
160
+ /** Layer ids whose pointer moves publish hover. */
161
+ layerIds: readonly string[];
162
+ /** Vector `source-layer` (tile sources). */
163
+ sourceLayer?: string;
164
+ /** Disable the binding without unmounting. @default true */
165
+ enabled?: boolean;
166
+ }
167
+ /**
168
+ * Publish the hovered feature of a MapLibre layer set into the enclosing
169
+ * {@link HonuaSelectionProvider}. Visual hover feature-state stays with the
170
+ * bridge's `hover` option (`createHoverHandler`); this binding only shares the
171
+ * hover *state* with non-map components. No-ops while the map is `null` or
172
+ * there is no enclosing `HonuaSelectionProvider`.
173
+ *
174
+ * @experimental
175
+ */
176
+ export declare function useMapHoverBinding(map: DataToMapLibreMap | null | undefined, options: MapHoverBindingOptions): void;
177
+ //# sourceMappingURL=selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/react/selection.tsx"],"names":[],"mappings":"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"}
Binary file
@@ -0,0 +1,69 @@
1
+ /**
2
+ * {@link useMountedSource} — the React lifecycle wrapper around the
3
+ * data-to-map bridge's `mountSource` (REQ-002 of the react depth pass).
4
+ *
5
+ * One bridge mount per effect run: the mount effect creates a fresh
6
+ * `MountedSource` and its cleanup aborts any in-flight mount and disposes the
7
+ * handle (idempotent), so React 18/19 StrictMode's mount → unmount → mount
8
+ * never leaks MapLibre sources, layers, or listeners and never double-adds.
9
+ *
10
+ * Prop changes are diffed instead of torn down:
11
+ * - `query` → `handle.setFilter(query)` (GeoJSON `setData` / tile URL rewrite);
12
+ * - `renderer` (a first-class renderer object from `@honua/sdk-js/style`) →
13
+ * `handle.setRenderer(renderer)`, which diffs paint/layout in place and
14
+ * recreates only the owned layers on a structural renderer change;
15
+ * - `paint` / `layout` → per-property `map.setPaintProperty` /
16
+ * `map.setLayoutProperty` on the bridge-owned layers (falling back to a full
17
+ * remount when the host map does not expose those methods);
18
+ * - structural options (strategy, ids, custom `layers`, geometry, tiles…) →
19
+ * remount.
20
+ *
21
+ * SSR-safe: no `window` / `document` access at module scope.
22
+ *
23
+ * @module
24
+ */
25
+ import type { Source } from "../contract/types.js";
26
+ import type { DataToMapLibreMap, MountSourceOptions, MountedSource, MountedSourceDiagnostics } from "../map/data-to-map-bridge.js";
27
+ /** Options for {@link useMountedSource}. @experimental */
28
+ export interface UseMountedSourceOptions<T = Record<string, unknown>> extends Omit<MountSourceOptions<T>, "signal"> {
29
+ /** When `false`, nothing is mounted (and any existing mount is disposed). Default `true`. */
30
+ enabled?: boolean;
31
+ /** Called with fresh diagnostics after the mount and after every applied update. */
32
+ onDiagnostics?: (diagnostics: MountedSourceDiagnostics) => void;
33
+ /** Called when mounting or a diff update fails (aborted mounts are silent). */
34
+ onError?: (error: unknown) => void;
35
+ }
36
+ /** Result of {@link useMountedSource}. @experimental */
37
+ export interface UseMountedSourceResult<T = Record<string, unknown>> {
38
+ /** The live bridge handle, or `null` while unmounted / mounting / failed. */
39
+ handle: MountedSource<T> | null;
40
+ /** Diagnostics snapshot from the mount and the latest applied update. */
41
+ diagnostics: MountedSourceDiagnostics | null;
42
+ /** Mount or update failure, `undefined` while healthy. */
43
+ error: unknown;
44
+ /** True while the initial mount (or a structural remount) is in flight. */
45
+ isMounting: boolean;
46
+ /** Re-execute the current filter and diff-update the mounted data in place. */
47
+ refresh: () => void;
48
+ }
49
+ /**
50
+ * Mount a contract `Source` on a MapLibre map through the data-to-map bridge
51
+ * for the lifetime of the component.
52
+ *
53
+ * Pass the map explicitly, or pass `undefined` to resolve it from the nearest
54
+ * {@link HonuaMapProvider} / `HonuaMap` (external `@vis.gl/react-maplibre`
55
+ * interop works the same way — hand over `mapRef.getMap()`).
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * const { diagnostics, error } = useMountedSource(map, source, {
60
+ * query: { where: "STATUS = 'OPEN'" },
61
+ * hover: true,
62
+ * onDiagnostics: (d) => console.log(d.strategy, d.featureCount),
63
+ * });
64
+ * ```
65
+ *
66
+ * @experimental
67
+ */
68
+ export declare function useMountedSource<T = Record<string, unknown>>(map: DataToMapLibreMap | null | undefined, source: Source<T> | null | undefined, options?: UseMountedSourceOptions<T>): UseMountedSourceResult<T>;
69
+ //# sourceMappingURL=use-mounted-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mounted-source.d.ts","sourceRoot":"","sources":["../../../src/react/use-mounted-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAGlB,aAAa,EACb,wBAAwB,EACzB,MAAM,8BAA8B,CAAC;AAOtC,0DAA0D;AAC1D,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IACjH,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oFAAoF;IACpF,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAChE,+EAA+E;IAC/E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED,wDAAwD;AACxD,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,6EAA6E;IAC7E,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAChC,yEAAyE;IACzE,WAAW,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC7C,0DAA0D;IAC1D,KAAK,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,UAAU,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAyJD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,GAAG,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,EACzC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EACpC,OAAO,GAAE,uBAAuB,CAAC,CAAC,CAAM,GACvC,sBAAsB,CAAC,CAAC,CAAC,CAgM3B"}