@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
@@ -86,6 +86,33 @@ export class OAuthInfoCompat {
86
86
  this.notifyWatchers("preserveUrlHash", this.preserveUrlHash);
87
87
  }
88
88
  }
89
+ /**
90
+ * Derive an {@link OAuth2Config} from this Esri-style OAuth info so it can back
91
+ * a real `oauth2(...)` provider from `@honua/sdk-js/auth`. Endpoints default to
92
+ * the ArcGIS Portal shape (`<portalUrl>/sharing/rest/oauth2/authorize` and
93
+ * `/token`); pass explicit endpoints or a `redirectUri` via `overrides`.
94
+ */
95
+ toOAuth2Config(overrides = {}) {
96
+ const clientId = overrides.clientId ?? this.appId;
97
+ if (!clientId) {
98
+ throw new Error("OAuthInfoCompat.toOAuth2Config requires an appId (or an explicit clientId override).");
99
+ }
100
+ const redirectUri = overrides.redirectUri;
101
+ if (!redirectUri) {
102
+ throw new Error("OAuthInfoCompat.toOAuth2Config requires a redirectUri override.");
103
+ }
104
+ const portalBase = this.portalUrl.replace(/\/+$/, "");
105
+ const { redirectUri: _redirectUri, clientId: _clientId, ...rest } = overrides;
106
+ return {
107
+ authorizationEndpoint: `${portalBase}/sharing/rest/oauth2/authorize`,
108
+ tokenEndpoint: `${portalBase}/sharing/rest/oauth2/token`,
109
+ clientId,
110
+ redirectUri,
111
+ mode: this.popup ? "popup" : "redirect",
112
+ ...(this.expiration !== undefined ? { extraAuthorizationParams: { expiration: String(this.expiration) } } : {}),
113
+ ...rest,
114
+ };
115
+ }
89
116
  clone() {
90
117
  return new OAuthInfoCompat(this.toJSON());
91
118
  }
@@ -0,0 +1,197 @@
1
+ import { HonuaClient } from "../core/client.js";
2
+ import { FeatureLayerCompat } from "./feature-layer.js";
3
+ /**
4
+ * A single item as returned by the Honua Portal facade
5
+ * (`/sharing/rest/search` and `/sharing/rest/content/items/{id}`). Mirrors the
6
+ * ArcGIS Portal item shape so a repointed app reads the same fields.
7
+ */
8
+ export interface PortalItem {
9
+ id: string;
10
+ owner: string;
11
+ created: number;
12
+ modified: number;
13
+ type: string;
14
+ typeKeywords: string[];
15
+ title: string;
16
+ snippet: string | null;
17
+ description: string | null;
18
+ tags: string[];
19
+ /** Absolute service URL, e.g. `.../rest/services/{name}/FeatureServer`. */
20
+ url: string | null;
21
+ access: "public" | "org" | "private" | string;
22
+ extent: number[][] | null;
23
+ spatialReference: string | null;
24
+ culture: string | null;
25
+ numComments: number;
26
+ numViews: number;
27
+ [key: string]: unknown;
28
+ }
29
+ /** Parsed `/sharing/rest/search` response. */
30
+ export interface PortalSearchResult {
31
+ query: string;
32
+ total: number;
33
+ /** 1-based index of the first result in this page. */
34
+ start: number;
35
+ num: number;
36
+ /** Index of the next page's first result, or `-1` on the last page. */
37
+ nextStart: number;
38
+ results: PortalItem[];
39
+ }
40
+ /** `/sharing/rest/info` response (subset the client relies on). */
41
+ export interface PortalInfo {
42
+ authInfo?: {
43
+ isTokenBasedSecurity?: boolean;
44
+ tokenServicesUrl?: string;
45
+ };
46
+ [key: string]: unknown;
47
+ }
48
+ /** `/sharing/rest/portals/self` response (subset the client relies on). */
49
+ export interface PortalSelf {
50
+ id?: string;
51
+ isPortal?: boolean;
52
+ name?: string;
53
+ portalName?: string;
54
+ user?: {
55
+ username: string;
56
+ fullName?: string;
57
+ role?: string;
58
+ } | null;
59
+ [key: string]: unknown;
60
+ }
61
+ /** Options accepted by {@link PortalCompat}. */
62
+ export interface PortalCompatOptions {
63
+ /**
64
+ * Portal base URL. Accepts either a portal root (`https://portal.example`) or
65
+ * a `/sharing/rest` base; both normalize to the `.../sharing/rest` endpoint
66
+ * base. Defaults to {@link esriConfig.portalUrl}.
67
+ */
68
+ portalUrl?: string;
69
+ /** Pre-obtained token to attach to authenticated calls. */
70
+ token?: string;
71
+ /** Static API key (falls back to {@link esriConfig.apiKey}). */
72
+ apiKey?: string;
73
+ /** Override the global `fetch` implementation (useful in tests). */
74
+ fetchFn?: typeof fetch;
75
+ }
76
+ /** Options for {@link PortalCompat.generateToken}. */
77
+ export interface PortalGenerateTokenOptions {
78
+ username: string;
79
+ password: string;
80
+ /** Referer registered with the token. Defaults to the portal origin. */
81
+ referer?: string;
82
+ /** Esri `client` param (`"referer"` | `"requestip"` | `"ip"`). Defaults to `"referer"`. */
83
+ client?: string;
84
+ /** Token lifetime in minutes. */
85
+ expirationMinutes?: number;
86
+ }
87
+ /** Result of {@link PortalCompat.generateToken}. */
88
+ export interface PortalTokenCredential {
89
+ token: string;
90
+ /** Absolute expiry as a unix-millisecond timestamp. */
91
+ expiresAtMs: number;
92
+ ssl: boolean;
93
+ }
94
+ /** Options for {@link PortalCompat.search}. */
95
+ export interface PortalSearchOptions {
96
+ q?: string;
97
+ start?: number;
98
+ num?: number;
99
+ token?: string;
100
+ }
101
+ /** Options for {@link PortalCompat.getItem}. */
102
+ export interface PortalGetItemOptions {
103
+ token?: string;
104
+ }
105
+ /** Options for {@link PortalCompat.openFeatureLayer}. */
106
+ export interface PortalOpenOptions {
107
+ /** Layer id to open for Feature Service items. Defaults to the service's first advertised layer. */
108
+ layerId?: number;
109
+ }
110
+ interface PortalOpenResultBase {
111
+ /** Resolved portal item. */
112
+ item: PortalItem;
113
+ /** Service base (`.../rest/services`-prefixed origin/prefix) without the service segment. */
114
+ baseUrl: string;
115
+ /** Service (folder/name) id parsed from the item URL. */
116
+ serviceId: string;
117
+ /** Authenticated client bound to `baseUrl`, carrying the portal credential. */
118
+ client: HonuaClient;
119
+ }
120
+ /** Feature Service open result: includes a ready-to-use {@link FeatureLayerCompat}. */
121
+ export interface PortalFeatureServiceOpenResult extends PortalOpenResultBase {
122
+ type: "feature-service";
123
+ layerId: number;
124
+ layer: FeatureLayerCompat;
125
+ }
126
+ /** Map/Image Service open result: the resolved, authenticated service handle. */
127
+ export interface PortalServiceOpenResult extends PortalOpenResultBase {
128
+ type: "map-service" | "image-service";
129
+ }
130
+ export type PortalOpenResult = PortalFeatureServiceOpenResult | PortalServiceOpenResult;
131
+ /** Error thrown when the Portal facade returns an Esri error envelope. */
132
+ export declare class PortalError extends Error {
133
+ readonly code: number | string | undefined;
134
+ readonly details: unknown;
135
+ constructor(message: string, code?: number | string, details?: unknown);
136
+ }
137
+ /**
138
+ * Client for a Honua `/sharing/rest` Portal facade. Lets a repointed ArcGIS app
139
+ * authenticate, search for items, and open an item that resolves to a
140
+ * `/rest/services` URL — carrying the portal token through to the opened layer
141
+ * so the whole flow authenticates end to end.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * import { PortalCompat } from "@honua/sdk-js/esri-compat";
146
+ *
147
+ * const portal = new PortalCompat({ portalUrl: "https://honua.example" });
148
+ * await portal.generateToken({ username: "u", password: "p" });
149
+ * const { results } = await portal.search({ q: "roads" });
150
+ * const opened = await portal.openFeatureLayer(results[0]);
151
+ * if (opened.type === "feature-service") {
152
+ * await opened.layer.queryFeatures({ where: "1=1" });
153
+ * }
154
+ * ```
155
+ */
156
+ export declare class PortalCompat {
157
+ /** Normalized `.../sharing/rest` base for this portal. */
158
+ readonly sharingRestBase: string;
159
+ private token;
160
+ private tokenExpiresAtMs;
161
+ private readonly apiKey;
162
+ private readonly fetchFn;
163
+ constructor(options?: PortalCompatOptions);
164
+ /** The currently held portal token, if any. */
165
+ getToken(): string | undefined;
166
+ /**
167
+ * Exchange username/password for a portal token via
168
+ * `POST /sharing/rest/generateToken`. Stores the token on this instance and
169
+ * returns the credential (`expires` ms → `expiresAtMs`).
170
+ */
171
+ generateToken(options: PortalGenerateTokenOptions): Promise<PortalTokenCredential>;
172
+ /** `GET /sharing/rest/info`. */
173
+ getInfo(): Promise<PortalInfo>;
174
+ /** `GET /sharing/rest/portals/self` (attaches the token when present). */
175
+ getPortalSelf(): Promise<PortalSelf>;
176
+ /** `GET /sharing/rest/search`. */
177
+ search(options?: PortalSearchOptions): Promise<PortalSearchResult>;
178
+ /** `GET /sharing/rest/content/items/{id}`. */
179
+ getItem(itemId: string, options?: PortalGetItemOptions): Promise<PortalItem>;
180
+ /**
181
+ * Resolve an item (fetching it when given an id), parse its service `url`, and
182
+ * return an authenticated handle. Feature Service items yield a
183
+ * {@link FeatureLayerCompat} bound to a client carrying the portal token;
184
+ * Map/Image Service items yield the resolved `{ baseUrl, serviceId, client }`.
185
+ */
186
+ openFeatureLayer(itemOrId: string | PortalItem, options?: PortalOpenOptions): Promise<PortalOpenResult>;
187
+ /**
188
+ * Register the currently held token with the shared {@link identityManager}
189
+ * under this portal's `/sharing/rest` server, so subsequent esri-compat calls
190
+ * resolve the same credential.
191
+ */
192
+ registerWithIdentityManager(): void;
193
+ private buildAuthenticatedClient;
194
+ private getJson;
195
+ }
196
+ export {};
197
+ //# sourceMappingURL=portal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/esri-compat/portal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,251 @@
1
+ import { HonuaClient } from "../core/client.js";
2
+ import { esriConfig } from "./esri-config.js";
3
+ import { FeatureLayerCompat } from "./feature-layer.js";
4
+ import { identityManager } from "./identity-manager.js";
5
+ import { createArcGisTokenInterceptor } from "./request.js";
6
+ import { parseFeatureLayerUrl, parseImageServiceUrl, parseMapServiceUrl } from "./url.js";
7
+ /** Error thrown when the Portal facade returns an Esri error envelope. */
8
+ export class PortalError extends Error {
9
+ code;
10
+ details;
11
+ constructor(message, code, details) {
12
+ super(message);
13
+ this.name = "PortalError";
14
+ this.code = code;
15
+ this.details = details;
16
+ }
17
+ }
18
+ /**
19
+ * Client for a Honua `/sharing/rest` Portal facade. Lets a repointed ArcGIS app
20
+ * authenticate, search for items, and open an item that resolves to a
21
+ * `/rest/services` URL — carrying the portal token through to the opened layer
22
+ * so the whole flow authenticates end to end.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { PortalCompat } from "@honua/sdk-js/esri-compat";
27
+ *
28
+ * const portal = new PortalCompat({ portalUrl: "https://honua.example" });
29
+ * await portal.generateToken({ username: "u", password: "p" });
30
+ * const { results } = await portal.search({ q: "roads" });
31
+ * const opened = await portal.openFeatureLayer(results[0]);
32
+ * if (opened.type === "feature-service") {
33
+ * await opened.layer.queryFeatures({ where: "1=1" });
34
+ * }
35
+ * ```
36
+ */
37
+ export class PortalCompat {
38
+ /** Normalized `.../sharing/rest` base for this portal. */
39
+ sharingRestBase;
40
+ token;
41
+ tokenExpiresAtMs;
42
+ apiKey;
43
+ fetchFn;
44
+ constructor(options = {}) {
45
+ this.sharingRestBase = normalizeSharingRestBase(options.portalUrl ?? esriConfig.portalUrl);
46
+ this.token = options.token;
47
+ this.tokenExpiresAtMs = undefined;
48
+ this.apiKey = options.apiKey ?? esriConfig.apiKey;
49
+ // Bind so passing a bare `window.fetch`/`globalThis.fetch` cannot throw an
50
+ // "Illegal invocation" when called as `this.fetchFn(...)`.
51
+ this.fetchFn = (options.fetchFn ?? fetch).bind(globalThis);
52
+ }
53
+ /** The currently held portal token, if any. */
54
+ getToken() {
55
+ return this.token;
56
+ }
57
+ /**
58
+ * Exchange username/password for a portal token via
59
+ * `POST /sharing/rest/generateToken`. Stores the token on this instance and
60
+ * returns the credential (`expires` ms → `expiresAtMs`).
61
+ */
62
+ async generateToken(options) {
63
+ const referer = options.referer ?? defaultReferer(this.sharingRestBase);
64
+ const body = new URLSearchParams();
65
+ body.set("username", options.username);
66
+ body.set("password", options.password);
67
+ body.set("client", options.client ?? "referer");
68
+ if (referer) {
69
+ body.set("referer", referer);
70
+ }
71
+ if (typeof options.expirationMinutes === "number" && Number.isFinite(options.expirationMinutes)) {
72
+ body.set("expiration", String(options.expirationMinutes));
73
+ }
74
+ body.set("f", "json");
75
+ const response = await this.fetchFn(`${this.sharingRestBase}/generateToken`, {
76
+ method: "POST",
77
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
78
+ body: body.toString(),
79
+ });
80
+ const json = (await response.json());
81
+ throwIfEsriError(json, "Portal generateToken failed.");
82
+ if (typeof json.token !== "string" || json.token.length === 0) {
83
+ throw new PortalError("Portal generateToken response did not include a token.");
84
+ }
85
+ const expiresAtMs = typeof json.expires === "number" && Number.isFinite(json.expires) ? json.expires : 0;
86
+ this.token = json.token;
87
+ this.tokenExpiresAtMs = expiresAtMs || undefined;
88
+ return { token: json.token, expiresAtMs, ssl: json.ssl ?? true };
89
+ }
90
+ /** `GET /sharing/rest/info`. */
91
+ async getInfo() {
92
+ return this.getJson("/info", {}, undefined);
93
+ }
94
+ /** `GET /sharing/rest/portals/self` (attaches the token when present). */
95
+ async getPortalSelf() {
96
+ return this.getJson("/portals/self", {}, this.token);
97
+ }
98
+ /** `GET /sharing/rest/search`. */
99
+ async search(options = {}) {
100
+ const params = {
101
+ q: options.q,
102
+ start: options.start,
103
+ num: options.num,
104
+ };
105
+ const raw = await this.getJson("/search", params, options.token ?? this.token);
106
+ return {
107
+ query: raw.query ?? options.q ?? "",
108
+ total: raw.total ?? 0,
109
+ start: raw.start ?? options.start ?? 1,
110
+ num: raw.num ?? options.num ?? 0,
111
+ nextStart: raw.nextStart ?? -1,
112
+ results: Array.isArray(raw.results) ? raw.results : [],
113
+ };
114
+ }
115
+ /** `GET /sharing/rest/content/items/{id}`. */
116
+ async getItem(itemId, options = {}) {
117
+ return this.getJson(`/content/items/${encodeURIComponent(itemId)}`, {}, options.token ?? this.token);
118
+ }
119
+ /**
120
+ * Resolve an item (fetching it when given an id), parse its service `url`, and
121
+ * return an authenticated handle. Feature Service items yield a
122
+ * {@link FeatureLayerCompat} bound to a client carrying the portal token;
123
+ * Map/Image Service items yield the resolved `{ baseUrl, serviceId, client }`.
124
+ */
125
+ async openFeatureLayer(itemOrId, options = {}) {
126
+ const item = typeof itemOrId === "string" ? await this.getItem(itemOrId) : itemOrId;
127
+ if (!item.url) {
128
+ throw new PortalError(`Portal item ${item.id} has no service URL to open.`);
129
+ }
130
+ const serviceUrl = trimTrailingSlashes(item.url);
131
+ if (isFeatureService(item.type, serviceUrl)) {
132
+ const hasLayerId = /\/FeatureServer\/\d+$/i.test(serviceUrl);
133
+ const service = parseFeatureLayerUrl(hasLayerId ? serviceUrl : `${serviceUrl}/0`);
134
+ const client = this.buildAuthenticatedClient(service.baseUrl);
135
+ let layerId = service.layerId;
136
+ if (!hasLayerId) {
137
+ if (options.layerId !== undefined) {
138
+ layerId = options.layerId;
139
+ }
140
+ else {
141
+ const metadata = await client.getFeatureServiceMetadata(service.serviceId);
142
+ const firstLayerId = metadata.layers?.[0]?.id;
143
+ if (typeof firstLayerId !== "number" || !Number.isSafeInteger(firstLayerId)) {
144
+ throw new PortalError(`Portal Feature Service item ${item.id} does not advertise a layer to open.`);
145
+ }
146
+ layerId = firstLayerId;
147
+ }
148
+ }
149
+ const layerUrl = hasLayerId ? serviceUrl : `${serviceUrl}/${layerId}`;
150
+ const parsed = parseFeatureLayerUrl(layerUrl);
151
+ const layer = new FeatureLayerCompat({ url: layerUrl, client, title: item.title, id: item.id });
152
+ return {
153
+ type: "feature-service",
154
+ item,
155
+ baseUrl: parsed.baseUrl,
156
+ serviceId: parsed.serviceId,
157
+ layerId: parsed.layerId,
158
+ client,
159
+ layer,
160
+ };
161
+ }
162
+ if (isImageService(item.type, serviceUrl)) {
163
+ const parsed = parseImageServiceUrl(serviceUrl);
164
+ const client = this.buildAuthenticatedClient(parsed.baseUrl);
165
+ return { type: "image-service", item, baseUrl: parsed.baseUrl, serviceId: parsed.serviceId, client };
166
+ }
167
+ const parsed = parseMapServiceUrl(serviceUrl);
168
+ const client = this.buildAuthenticatedClient(parsed.baseUrl);
169
+ return { type: "map-service", item, baseUrl: parsed.baseUrl, serviceId: parsed.serviceId, client };
170
+ }
171
+ /**
172
+ * Register the currently held token with the shared {@link identityManager}
173
+ * under this portal's `/sharing/rest` server, so subsequent esri-compat calls
174
+ * resolve the same credential.
175
+ */
176
+ registerWithIdentityManager() {
177
+ if (!this.token) {
178
+ throw new PortalError("PortalCompat has no token to register; call generateToken first.");
179
+ }
180
+ identityManager.registerToken({
181
+ server: this.sharingRestBase,
182
+ token: this.token,
183
+ ...(this.tokenExpiresAtMs !== undefined ? { expires: this.tokenExpiresAtMs } : {}),
184
+ });
185
+ }
186
+ buildAuthenticatedClient(baseUrl) {
187
+ const interceptors = [];
188
+ if (this.token) {
189
+ interceptors.push(createArcGisTokenInterceptor({ getToken: () => this.token }));
190
+ }
191
+ return new HonuaClient({
192
+ baseUrl,
193
+ fetchFn: this.fetchFn,
194
+ ...(this.apiKey ? { apiKey: this.apiKey } : {}),
195
+ ...(interceptors.length > 0 ? { interceptors } : {}),
196
+ });
197
+ }
198
+ async getJson(path, params, token) {
199
+ const query = new URLSearchParams();
200
+ query.set("f", "json");
201
+ for (const [key, value] of Object.entries(params)) {
202
+ if (value !== undefined && value !== null && value !== "") {
203
+ query.set(key, String(value));
204
+ }
205
+ }
206
+ if (token) {
207
+ query.set("token", token);
208
+ }
209
+ const response = await this.fetchFn(`${this.sharingRestBase}${path}?${query.toString()}`);
210
+ const json = (await response.json());
211
+ throwIfEsriError(json, `Portal request to ${path} failed.`);
212
+ return json;
213
+ }
214
+ }
215
+ function normalizeSharingRestBase(portalUrl) {
216
+ const trimmed = trimTrailingSlashes(portalUrl);
217
+ if (/\/sharing\/rest$/i.test(trimmed)) {
218
+ return trimmed;
219
+ }
220
+ return `${trimmed}/sharing/rest`;
221
+ }
222
+ function trimTrailingSlashes(value) {
223
+ let end = value.length;
224
+ while (end > 0 && value.charCodeAt(end - 1) === 47) {
225
+ end--;
226
+ }
227
+ return value.slice(0, end);
228
+ }
229
+ function defaultReferer(sharingRestBase) {
230
+ if (globalThis.location?.origin) {
231
+ return globalThis.location.origin;
232
+ }
233
+ try {
234
+ return new URL(sharingRestBase).origin;
235
+ }
236
+ catch {
237
+ return undefined;
238
+ }
239
+ }
240
+ function isFeatureService(type, serviceUrl) {
241
+ return /feature\s*service/i.test(type) || /\/FeatureServer(\/\d+)?$/i.test(serviceUrl);
242
+ }
243
+ function isImageService(type, serviceUrl) {
244
+ return /image\s*service/i.test(type) || /\/ImageServer(\/\d+)?$/i.test(serviceUrl);
245
+ }
246
+ function throwIfEsriError(json, fallbackMessage) {
247
+ if (json && typeof json === "object" && json.error) {
248
+ const { code, message, details } = json.error;
249
+ throw new PortalError(message ?? fallbackMessage, code, details);
250
+ }
251
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Bridges the esri-compat renderer shims to the first-class renderer objects
3
+ * in `@honua/sdk-js/style` (issue #497 REQ-002). The compat classes stay
4
+ * pure state holders; these helpers project their state through the same
5
+ * WebMap symbol/renderer conversion path the WebMap converter uses, so the
6
+ * SDK has exactly one class-breaks/unique-value implementation.
7
+ *
8
+ * Kept out of the compat classes themselves so consumers who never emit
9
+ * renderer objects do not pay for the conversion pipeline.
10
+ *
11
+ * @module
12
+ */
13
+ import type { ClassBreaksRenderer, UniqueValueRenderer } from "../style/renderers.js";
14
+ import type { WarningCollector } from "../webmap/warnings.js";
15
+ import type { ClassBreaksRendererCompat } from "./class-breaks-renderer.js";
16
+ import type { UniqueValueRendererCompat } from "./unique-value-renderer.js";
17
+ /** Result of projecting a compat renderer to a renderer object. @experimental */
18
+ export interface CompatRendererProjection<R> {
19
+ /** The emitted renderer object, or `undefined` when nothing was convertible. */
20
+ readonly renderer: R | undefined;
21
+ /** Symbol/renderer conversion warnings collected during projection. */
22
+ readonly warnings: WarningCollector["warnings"];
23
+ }
24
+ /**
25
+ * Emit a first-class {@link ClassBreaksRenderer} from a
26
+ * `ClassBreaksRendererCompat` shim. Compat `minValue`/`maxValue` map to the
27
+ * WebMap `classMinValue`/`classMaxValue` fields and symbols convert through
28
+ * the shared WebMap symbol pipeline.
29
+ *
30
+ * @experimental
31
+ */
32
+ export declare function rendererObjectFromClassBreaksCompat(compat: ClassBreaksRendererCompat): CompatRendererProjection<ClassBreaksRenderer>;
33
+ /**
34
+ * Emit a first-class {@link UniqueValueRenderer} from a
35
+ * `UniqueValueRendererCompat` shim.
36
+ *
37
+ * @experimental
38
+ */
39
+ export declare function rendererObjectFromUniqueValueCompat(compat: UniqueValueRendererCompat): CompatRendererProjection<UniqueValueRenderer>;
40
+ //# sourceMappingURL=renderer-objects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-objects.d.ts","sourceRoot":"","sources":["../../../src/esri-compat/renderer-objects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,iFAAiF;AACjF,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC;IACjC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;CACjD;AAED;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,yBAAyB,GAChC,wBAAwB,CAAC,mBAAmB,CAAC,CAmB/C;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,yBAAyB,GAChC,wBAAwB,CAAC,mBAAmB,CAAC,CAmB/C"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Bridges the esri-compat renderer shims to the first-class renderer objects
3
+ * in `@honua/sdk-js/style` (issue #497 REQ-002). The compat classes stay
4
+ * pure state holders; these helpers project their state through the same
5
+ * WebMap symbol/renderer conversion path the WebMap converter uses, so the
6
+ * SDK has exactly one class-breaks/unique-value implementation.
7
+ *
8
+ * Kept out of the compat classes themselves so consumers who never emit
9
+ * renderer objects do not pay for the conversion pipeline.
10
+ *
11
+ * @module
12
+ */
13
+ import { classBreaksRendererFromWebMap, uniqueValueRendererFromWebMap } from "../webmap/convert-renderer.js";
14
+ import { createWarningCollector } from "../webmap/warnings.js";
15
+ /**
16
+ * Emit a first-class {@link ClassBreaksRenderer} from a
17
+ * `ClassBreaksRendererCompat` shim. Compat `minValue`/`maxValue` map to the
18
+ * WebMap `classMinValue`/`classMaxValue` fields and symbols convert through
19
+ * the shared WebMap symbol pipeline.
20
+ *
21
+ * @experimental
22
+ */
23
+ export function rendererObjectFromClassBreaksCompat(compat) {
24
+ const warn = createWarningCollector();
25
+ const renderer = classBreaksRendererFromWebMap({
26
+ type: "classBreaks",
27
+ field: compat.field,
28
+ minValue: compat.minValue,
29
+ defaultSymbol: compat.defaultSymbol,
30
+ defaultLabel: compat.defaultLabel,
31
+ classBreakInfos: compat.classBreakInfos.map((info) => ({
32
+ classMinValue: info.minValue,
33
+ classMaxValue: info.maxValue,
34
+ label: info.label,
35
+ symbol: info.symbol,
36
+ })),
37
+ }, warn);
38
+ return { renderer, warnings: warn.warnings };
39
+ }
40
+ /**
41
+ * Emit a first-class {@link UniqueValueRenderer} from a
42
+ * `UniqueValueRendererCompat` shim.
43
+ *
44
+ * @experimental
45
+ */
46
+ export function rendererObjectFromUniqueValueCompat(compat) {
47
+ const warn = createWarningCollector();
48
+ const renderer = uniqueValueRendererFromWebMap({
49
+ type: "uniqueValue",
50
+ field1: compat.field,
51
+ field2: compat.field2,
52
+ field3: compat.field3,
53
+ defaultSymbol: compat.defaultSymbol,
54
+ defaultLabel: compat.defaultLabel,
55
+ uniqueValueInfos: compat.uniqueValueInfos.map((info) => ({
56
+ value: info.value,
57
+ label: info.label,
58
+ symbol: info.symbol,
59
+ })),
60
+ }, warn);
61
+ return { renderer, warnings: warn.warnings };
62
+ }
@@ -1,6 +1,32 @@
1
+ import type { EditSketchTool } from "../contract/edit-sketch.js";
2
+ import type { SnappingConfig } from "../contract/edit-snapping.js";
1
3
  import { CompatEventBus } from "./event-bus.js";
4
+ import { type SnappingOptionsCompat } from "./snapping.js";
2
5
  export type SketchCreationModeCompat = "single" | "update" | "continuous";
3
6
  export type SketchToolCompat = "point" | "polyline" | "polygon" | "rectangle" | "circle";
7
+ /**
8
+ * Duck-typed subset of the runtime terra-draw sketch handle
9
+ * (`bindTerraDrawSketch` / `createTerraDrawSketch` from
10
+ * `@honua/sdk-js/runtime`) that the Sketch shim can delegate tool modes to.
11
+ * Structural on purpose: the compat layer never imports the optional
12
+ * terra-draw peer, it only feature-detects a binding the app wired up.
13
+ *
14
+ * @experimental
15
+ */
16
+ export interface SketchToolBindingCompat {
17
+ setTool(tool: EditSketchTool): unknown;
18
+ select?(): void;
19
+ cancel?(): void;
20
+ }
21
+ /**
22
+ * Feature-detect a terra-draw sketch binding: any object exposing a callable
23
+ * `setTool` qualifies; anything else (including `undefined` when terra-draw
24
+ * is not installed) resolves to `undefined` and the shim keeps its current
25
+ * headless behavior.
26
+ *
27
+ * @experimental
28
+ */
29
+ export declare function resolveSketchToolBindingCompat(value: unknown): SketchToolBindingCompat | undefined;
4
30
  export interface SketchCreateOptionsCompat {
5
31
  mode?: "click" | "freehand" | "hybrid";
6
32
  }
@@ -20,6 +46,15 @@ export interface SketchCompatOptions {
20
46
  creationMode?: SketchCreationModeCompat;
21
47
  defaultCreateOptions?: Partial<SketchCreateOptionsCompat>;
22
48
  defaultUpdateOptions?: Partial<SketchUpdateOptionsCompat>;
49
+ snappingOptions?: SnappingOptionsCompat;
50
+ /**
51
+ * Optional terra-draw sketch binding (see {@link SketchToolBindingCompat}).
52
+ * When present, `create`/`update`/`cancel`/`reset` delegate tool-mode
53
+ * changes to the binding; otherwise the shim keeps its headless behavior.
54
+ *
55
+ * @experimental
56
+ */
57
+ sketchBinding?: unknown;
23
58
  }
24
59
  export interface SketchCreateResultCompat {
25
60
  state: "complete" | "cancel";
@@ -46,8 +81,16 @@ export declare class SketchCompat {
46
81
  activeCreateOptions: Partial<SketchCreateOptionsCompat> | undefined;
47
82
  activeUpdateGraphics: Record<string, unknown>[];
48
83
  activeUpdateOptions: Partial<SketchUpdateOptionsCompat> | undefined;
84
+ snappingOptions: SnappingOptionsCompat;
49
85
  private readonly watchListeners;
86
+ private readonly sketchBinding;
50
87
  constructor(options?: SketchCompatOptions);
88
+ /** Whether tool modes delegate to a terra-draw sketch binding. @experimental */
89
+ delegatesToSketchBinding(): boolean;
90
+ /** Replace the ArcGIS-shaped snapping options and notify watchers. */
91
+ setSnappingOptions(options: SnappingOptionsCompat): void;
92
+ /** The snapping options mapped onto the contract `SnappingConfig`. */
93
+ snappingConfig(): SnappingConfig;
51
94
  load(): Promise<SketchCompat>;
52
95
  when(callback?: (widget: SketchCompat) => void): Promise<SketchCompat>;
53
96
  watch(propertyName: string, listener: (value: unknown) => void): SketchHandleCompat;