@honua/react 0.1.12 → 0.1.14

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 (195) hide show
  1. package/columnar/apache-arrow.d.ts +17 -0
  2. package/columnar/apache-arrow.d.ts.map +1 -0
  3. package/columnar/apache-arrow.js +1036 -0
  4. package/columnar/batch-cache-conformance.d.ts +66 -0
  5. package/columnar/batch-cache-conformance.d.ts.map +1 -0
  6. package/columnar/batch-cache-conformance.js +317 -0
  7. package/columnar/batch-cache-indexeddb.d.ts +31 -0
  8. package/columnar/batch-cache-indexeddb.d.ts.map +1 -0
  9. package/columnar/batch-cache-indexeddb.js +148 -0
  10. package/columnar/batch-cache.d.ts +298 -0
  11. package/columnar/batch-cache.d.ts.map +1 -0
  12. package/columnar/batch-cache.js +757 -0
  13. package/columnar/geoarrow-aggregate.d.ts +178 -0
  14. package/columnar/geoarrow-aggregate.d.ts.map +1 -0
  15. package/columnar/geoarrow-aggregate.js +976 -0
  16. package/columnar/geoarrow-patch.d.ts +382 -0
  17. package/columnar/geoarrow-patch.d.ts.map +1 -0
  18. package/columnar/geoarrow-patch.js +1656 -0
  19. package/columnar/geoarrow-reproject.d.ts +22 -0
  20. package/columnar/geoarrow-reproject.d.ts.map +1 -0
  21. package/columnar/geoarrow-reproject.js +119 -0
  22. package/columnar/geoarrow-serialization.d.ts +68 -0
  23. package/columnar/geoarrow-serialization.d.ts.map +1 -0
  24. package/columnar/geoarrow-serialization.js +331 -0
  25. package/columnar/geoarrow-types.d.ts +271 -0
  26. package/columnar/geoarrow-types.d.ts.map +1 -0
  27. package/columnar/geoarrow-types.js +15 -0
  28. package/columnar/geoarrow.d.ts +52 -0
  29. package/columnar/geoarrow.d.ts.map +1 -0
  30. package/columnar/geoarrow.js +1469 -0
  31. package/columnar/index.d.ts +43 -0
  32. package/columnar/index.d.ts.map +1 -0
  33. package/columnar/index.js +29 -0
  34. package/columnar/operators.d.ts +70 -0
  35. package/columnar/operators.d.ts.map +1 -0
  36. package/columnar/operators.js +307 -0
  37. package/columnar/result.d.ts +369 -0
  38. package/columnar/result.d.ts.map +1 -0
  39. package/columnar/result.js +815 -0
  40. package/columnar/telemetry.d.ts +152 -0
  41. package/columnar/telemetry.d.ts.map +1 -0
  42. package/columnar/telemetry.js +265 -0
  43. package/columnar/transfer.d.ts +28 -0
  44. package/columnar/transfer.d.ts.map +1 -0
  45. package/columnar/transfer.js +669 -0
  46. package/columnar/types.d.ts +175 -0
  47. package/columnar/types.d.ts.map +1 -0
  48. package/columnar/types.js +22 -0
  49. package/columnar/worker.d.ts +157 -0
  50. package/columnar/worker.d.ts.map +1 -0
  51. package/columnar/worker.js +1059 -0
  52. package/connect-url-safety.d.ts +53 -0
  53. package/connect-url-safety.js +189 -0
  54. package/contract/pmtiles.d.ts +6 -5
  55. package/contract/pmtiles.d.ts.map +1 -1
  56. package/contract/pmtiles.js +30 -5
  57. package/contract/source.d.ts.map +1 -1
  58. package/contract/source.js +11 -8
  59. package/core/client.d.ts.map +1 -1
  60. package/core/client.js +87 -19
  61. package/core/deprecation-notice.d.ts +28 -0
  62. package/core/deprecation-notice.d.ts.map +1 -0
  63. package/core/deprecation-notice.js +22 -0
  64. package/core/esri-geojson.d.ts.map +1 -1
  65. package/core/esri-geojson.js +14 -8
  66. package/core/optional-grpc-peer.d.ts +15 -0
  67. package/core/optional-grpc-peer.d.ts.map +1 -0
  68. package/core/optional-grpc-peer.js +60 -0
  69. package/esri-compat/basemap-gallery.d.ts +2 -0
  70. package/esri-compat/basemap-gallery.d.ts.map +1 -1
  71. package/esri-compat/basemap-gallery.js +12 -0
  72. package/esri-compat/basemap.d.ts +4 -0
  73. package/esri-compat/basemap.d.ts.map +1 -1
  74. package/esri-compat/basemap.js +70 -0
  75. package/esri-compat/bookmarks.d.ts +2 -0
  76. package/esri-compat/bookmarks.d.ts.map +1 -1
  77. package/esri-compat/bookmarks.js +12 -0
  78. package/esri-compat/controls.d.ts +18 -0
  79. package/esri-compat/controls.d.ts.map +1 -1
  80. package/esri-compat/controls.js +120 -57
  81. package/esri-compat/directions.d.ts +4 -0
  82. package/esri-compat/directions.d.ts.map +1 -1
  83. package/esri-compat/directions.js +30 -20
  84. package/esri-compat/editor.d.ts +4 -0
  85. package/esri-compat/editor.d.ts.map +1 -1
  86. package/esri-compat/editor.js +16 -0
  87. package/esri-compat/esri-config.d.ts +2 -1
  88. package/esri-compat/esri-config.d.ts.map +1 -1
  89. package/esri-compat/feature-effect.d.ts +23 -0
  90. package/esri-compat/feature-effect.d.ts.map +1 -0
  91. package/esri-compat/feature-effect.js +12 -0
  92. package/esri-compat/feature-form.d.ts +6 -0
  93. package/esri-compat/feature-form.d.ts.map +1 -1
  94. package/esri-compat/feature-form.js +63 -0
  95. package/esri-compat/feature-layer.d.ts +21 -2
  96. package/esri-compat/feature-layer.d.ts.map +1 -1
  97. package/esri-compat/feature-layer.js +172 -1
  98. package/esri-compat/feature-table.d.ts +5 -0
  99. package/esri-compat/feature-table.d.ts.map +1 -1
  100. package/esri-compat/feature-table.js +23 -0
  101. package/esri-compat/identity-manager.d.ts +1 -1
  102. package/esri-compat/identity-manager.js +1 -1
  103. package/esri-compat/legend.d.ts +2 -0
  104. package/esri-compat/legend.d.ts.map +1 -1
  105. package/esri-compat/legend.js +98 -0
  106. package/esri-compat/locator.d.ts +1 -1
  107. package/esri-compat/locator.js +1 -1
  108. package/esri-compat/map-view-mount.d.ts +1 -0
  109. package/esri-compat/map-view-mount.d.ts.map +1 -1
  110. package/esri-compat/map-view-mount.js +46 -25
  111. package/esri-compat/map-view.d.ts +13 -0
  112. package/esri-compat/map-view.d.ts.map +1 -1
  113. package/esri-compat/map-view.js +94 -8
  114. package/esri-compat/map.d.ts +5 -1
  115. package/esri-compat/map.d.ts.map +1 -1
  116. package/esri-compat/map.js +10 -0
  117. package/esri-compat/measurement.d.ts +2 -0
  118. package/esri-compat/measurement.d.ts.map +1 -1
  119. package/esri-compat/measurement.js +14 -0
  120. package/esri-compat/point.d.ts +7 -0
  121. package/esri-compat/point.d.ts.map +1 -1
  122. package/esri-compat/point.js +33 -3
  123. package/esri-compat/popup.d.ts +2 -0
  124. package/esri-compat/popup.d.ts.map +1 -1
  125. package/esri-compat/popup.js +12 -0
  126. package/esri-compat/portal.d.ts +1 -1
  127. package/esri-compat/portal.js +1 -1
  128. package/esri-compat/print.d.ts +3 -0
  129. package/esri-compat/print.d.ts.map +1 -1
  130. package/esri-compat/print.js +15 -0
  131. package/esri-compat/search.d.ts +4 -0
  132. package/esri-compat/search.d.ts.map +1 -1
  133. package/esri-compat/search.js +25 -28
  134. package/esri-compat/sketch.d.ts +2 -0
  135. package/esri-compat/sketch.d.ts.map +1 -1
  136. package/esri-compat/sketch.js +12 -0
  137. package/esri-compat/widget-host.d.ts +46 -17
  138. package/esri-compat/widget-host.d.ts.map +1 -1
  139. package/esri-compat/widget-host.js +84 -20
  140. package/esri-compat/widget-shell-hosts.d.ts +61 -0
  141. package/esri-compat/widget-shell-hosts.d.ts.map +1 -0
  142. package/esri-compat/widget-shell-hosts.js +76 -0
  143. package/geocoding/index.d.ts +114 -0
  144. package/geocoding/index.d.ts.map +1 -0
  145. package/geocoding/index.js +293 -0
  146. package/geocoding/provider-http.d.ts +37 -0
  147. package/geocoding/provider-http.d.ts.map +1 -0
  148. package/geocoding/provider-http.js +93 -0
  149. package/geocoding/provider.d.ts +145 -0
  150. package/geocoding/provider.d.ts.map +1 -0
  151. package/geocoding/provider.js +41 -0
  152. package/geocoding/providers/honua.d.ts +28 -0
  153. package/geocoding/providers/honua.d.ts.map +1 -0
  154. package/geocoding/providers/honua.js +68 -0
  155. package/geocoding/providers/nominatim.d.ts +47 -0
  156. package/geocoding/providers/nominatim.d.ts.map +1 -0
  157. package/geocoding/providers/nominatim.js +105 -0
  158. package/geocoding/providers/pelias.d.ts +40 -0
  159. package/geocoding/providers/pelias.d.ts.map +1 -0
  160. package/geocoding/providers/pelias.js +115 -0
  161. package/geocoding/providers/photon.d.ts +39 -0
  162. package/geocoding/providers/photon.d.ts.map +1 -0
  163. package/geocoding/providers/photon.js +107 -0
  164. package/geometry/convert.d.ts +13 -0
  165. package/geometry/convert.d.ts.map +1 -0
  166. package/geometry/convert.js +12 -0
  167. package/geometry/index.d.ts +17 -0
  168. package/geometry/index.d.ts.map +1 -0
  169. package/geometry/index.js +15 -0
  170. package/geometry/internal.d.ts +25 -0
  171. package/geometry/internal.d.ts.map +1 -0
  172. package/geometry/internal.js +40 -0
  173. package/geometry/ops.d.ts +71 -0
  174. package/geometry/ops.d.ts.map +1 -0
  175. package/geometry/ops.js +147 -0
  176. package/geometry/project.d.ts +40 -0
  177. package/geometry/project.d.ts.map +1 -0
  178. package/geometry/project.js +88 -0
  179. package/geometry/types.d.ts +36 -0
  180. package/geometry/types.d.ts.map +1 -0
  181. package/geometry/types.js +12 -0
  182. package/kernel/renderer.d.ts +82 -0
  183. package/kernel/renderer.js +1 -0
  184. package/offline/digest.d.ts +15 -0
  185. package/offline/digest.js +58 -0
  186. package/offline/quota.d.ts +161 -0
  187. package/offline/quota.js +370 -0
  188. package/offline/types.d.ts +349 -0
  189. package/offline/types.js +75 -0
  190. package/package.json +14 -2
  191. package/realtime/odata-delta.d.ts +1 -1
  192. package/realtime/odata-delta.d.ts.map +1 -1
  193. package/realtime/odata-delta.js +38 -10
  194. package/widget-capabilities.d.ts +67 -0
  195. package/widget-capabilities.js +152 -0
@@ -0,0 +1,293 @@
1
+ /**
2
+ * `@honua/sdk-js/geocoding` — `HonuaGeocodingClient` for forward / reverse
3
+ * geocoding and typeahead suggestions over a Honua-hosted GeocodeServer.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { HonuaGeocodingClient } from "@honua/sdk-js/geocoding";
8
+ *
9
+ * const geo = new HonuaGeocodingClient({
10
+ * baseUrl: "https://your-honua-server.example",
11
+ * locatorName: "world-geocoder",
12
+ * });
13
+ *
14
+ * const results = await geo.forwardGeocode("1 Honolulu Pl, HI");
15
+ * // reverseGeocode is latitude-first, then longitude.
16
+ * const here = await geo.reverseGeocode(21.30, -157.85);
17
+ * const hints = await geo.suggest("honol");
18
+ * ```
19
+ *
20
+ * @example Debounced typeahead
21
+ * ```ts
22
+ * let timer: ReturnType<typeof setTimeout> | undefined;
23
+ * input.addEventListener("input", (event) => {
24
+ * clearTimeout(timer);
25
+ * const text = (event.target as HTMLInputElement).value;
26
+ * timer = setTimeout(async () => {
27
+ * render(await geo.suggest(text));
28
+ * }, 200);
29
+ * });
30
+ * ```
31
+ *
32
+ * @packageDocumentation
33
+ */
34
+ import { HonuaAbortError, HonuaHttpError, HonuaNetworkError, HonuaTimeoutError } from "../core/errors.js";
35
+ import { encodeServiceIdPath, trimTrailingSlashes } from "../core/path-utils.js";
36
+ export { assertGeocodingCapability, supportsGeocodingCapability } from "./provider.js";
37
+ export { honuaGeocodingProvider } from "./providers/honua.js";
38
+ export { nominatimGeocodingProvider } from "./providers/nominatim.js";
39
+ export { peliasGeocodingProvider } from "./providers/pelias.js";
40
+ export { photonGeocodingProvider } from "./providers/photon.js";
41
+ // ---------------------------------------------------------------------------
42
+ // Helpers
43
+ // ---------------------------------------------------------------------------
44
+ /** Redirect status codes that carry a `Location` header. */
45
+ const GEOCODING_REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
46
+ /** Maximum number of redirects {@link HonuaGeocodingClient} will follow. */
47
+ const GEOCODING_MAX_REDIRECTS = 20;
48
+ function isAbsoluteHttpUrl(value) {
49
+ return value.startsWith("http://") || value.startsWith("https://");
50
+ }
51
+ function normalizeBaseUrl(url) {
52
+ return trimTrailingSlashes(url);
53
+ }
54
+ function stringifyAttributes(attrs) {
55
+ const result = {};
56
+ for (const [key, value] of Object.entries(attrs)) {
57
+ if (value === null || value === undefined) {
58
+ result[key] = null;
59
+ }
60
+ else {
61
+ result[key] = String(value);
62
+ }
63
+ }
64
+ return result;
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Client
68
+ // ---------------------------------------------------------------------------
69
+ export class HonuaGeocodingClient {
70
+ baseUrl;
71
+ locatorName;
72
+ fetchFn;
73
+ defaultHeaders;
74
+ timeoutMs;
75
+ constructor(options) {
76
+ this.baseUrl = normalizeBaseUrl(options.baseUrl);
77
+ this.locatorName = options.locatorName ?? "World";
78
+ // Bind to `globalThis` at assignment: invoking an unbound `window.fetch`
79
+ // as `this.fetchFn(...)` throws "TypeError: Illegal invocation" in
80
+ // browsers. Binding is a no-op for Node's undici fetch and for
81
+ // caller-supplied wrappers.
82
+ this.fetchFn = (options.fetchFn ?? fetch).bind(globalThis);
83
+ this.timeoutMs = options.timeoutMs;
84
+ const headers = {};
85
+ if (options.apiKey) {
86
+ headers["X-API-Key"] = options.apiKey;
87
+ }
88
+ if (options.bearerToken) {
89
+ headers.Authorization = `Bearer ${options.bearerToken}`;
90
+ }
91
+ this.defaultHeaders = headers;
92
+ }
93
+ // -------------------------------------------------------------------------
94
+ // Public methods
95
+ // -------------------------------------------------------------------------
96
+ /**
97
+ * Forward-geocode a single-line address string into one or more candidate
98
+ * locations.
99
+ */
100
+ async forwardGeocode(address, options) {
101
+ const params = new URLSearchParams();
102
+ params.set("singleLine", address);
103
+ params.set("f", "json");
104
+ if (options?.maxResults !== undefined) {
105
+ params.set("maxLocations", String(options.maxResults));
106
+ }
107
+ if (options?.countryCodes !== undefined) {
108
+ params.set("countryCode", options.countryCodes);
109
+ }
110
+ if (options?.spatialReferenceWkid !== undefined) {
111
+ params.set("outSR", String(options.spatialReferenceWkid));
112
+ }
113
+ const url = `${this.serviceBasePath()}/findAddressCandidates?${params.toString()}`;
114
+ const { data, responseHeaders } = await this.request(url);
115
+ if (data.error) {
116
+ throw this.geoServicesError(data.error, "Geocode", responseHeaders);
117
+ }
118
+ return (data.candidates ?? []).map((c) => ({
119
+ address: c.address,
120
+ longitude: c.location.x,
121
+ latitude: c.location.y,
122
+ score: c.score,
123
+ attributes: stringifyAttributes(c.attributes ?? {}),
124
+ }));
125
+ }
126
+ /**
127
+ * Reverse-geocode a latitude/longitude pair to the nearest address.
128
+ * Returns `null` when the server cannot find an address for the given
129
+ * coordinates.
130
+ */
131
+ async reverseGeocode(latitude, longitude, options) {
132
+ const params = new URLSearchParams();
133
+ params.set("location", `${longitude},${latitude}`);
134
+ params.set("f", "json");
135
+ if (options?.spatialReferenceWkid !== undefined) {
136
+ params.set("outSR", String(options.spatialReferenceWkid));
137
+ }
138
+ const url = `${this.serviceBasePath()}/reverseGeocode?${params.toString()}`;
139
+ let data;
140
+ let responseHeaders;
141
+ try {
142
+ ({ data, responseHeaders } = await this.request(url));
143
+ }
144
+ catch (err) {
145
+ // Some geocode servers return an HTTP error when no address is found.
146
+ if (err instanceof HonuaHttpError && err.statusCode === 400) {
147
+ return null;
148
+ }
149
+ throw err;
150
+ }
151
+ if (data.error) {
152
+ // Server-level "no result" errors are not exceptional.
153
+ if (data.error.code === 400) {
154
+ return null;
155
+ }
156
+ throw this.geoServicesError(data.error, "Reverse geocode", responseHeaders);
157
+ }
158
+ if (!data.address || !data.location) {
159
+ return null;
160
+ }
161
+ const { Match_addr, ...rest } = data.address;
162
+ return {
163
+ address: Match_addr ?? "",
164
+ longitude: data.location.x,
165
+ latitude: data.location.y,
166
+ attributes: stringifyAttributes(rest),
167
+ };
168
+ }
169
+ /**
170
+ * Retrieve type-ahead suggestions for a partial address string.
171
+ */
172
+ async suggest(text, options) {
173
+ const params = new URLSearchParams();
174
+ params.set("text", text);
175
+ params.set("f", "json");
176
+ if (options?.maxSuggestions !== undefined) {
177
+ params.set("maxSuggestions", String(options.maxSuggestions));
178
+ }
179
+ if (options?.countryCodes !== undefined) {
180
+ params.set("countryCode", options.countryCodes);
181
+ }
182
+ const url = `${this.serviceBasePath()}/suggest?${params.toString()}`;
183
+ const { data, responseHeaders } = await this.request(url);
184
+ if (data.error) {
185
+ throw this.geoServicesError(data.error, "Suggest", responseHeaders);
186
+ }
187
+ return (data.suggestions ?? []).map((s) => ({
188
+ text: s.text,
189
+ magicKey: s.magicKey,
190
+ isCollection: s.isCollection,
191
+ }));
192
+ }
193
+ // -------------------------------------------------------------------------
194
+ // Internals
195
+ // -------------------------------------------------------------------------
196
+ serviceBasePath() {
197
+ return `${this.baseUrl}/rest/services/${encodeServiceIdPath(this.locatorName)}/GeocodeServer`;
198
+ }
199
+ /**
200
+ * Fetch with `redirect: "manual"`, only following a redirect when its target
201
+ * stays on the configured base origin. The geocoding client attaches its API
202
+ * key as a custom `X-API-Key` header that the runtime does not strip across a
203
+ * cross-origin redirect, so auto-following one would leak the key to the
204
+ * redirect target's host. Cross-origin (or origin-unverifiable) redirects
205
+ * throw instead of replaying the credentialed request off-origin.
206
+ */
207
+ async fetchWithSafeRedirects(url, init) {
208
+ const baseOrigin = isAbsoluteHttpUrl(this.baseUrl) ? new URL(this.baseUrl).origin : undefined;
209
+ let currentUrl = url;
210
+ for (let redirects = 0;; redirects += 1) {
211
+ const response = await this.fetchFn(currentUrl, { ...init, redirect: "manual" });
212
+ if (response.type === "opaqueredirect") {
213
+ throw new HonuaNetworkError("Refusing to follow an opaque cross-origin redirect; the geocoding API key would be leaked to the redirect target.", undefined);
214
+ }
215
+ if (!GEOCODING_REDIRECT_STATUSES.has(response.status)) {
216
+ return response;
217
+ }
218
+ if (redirects >= GEOCODING_MAX_REDIRECTS) {
219
+ throw new HonuaNetworkError(`Exceeded the maximum of ${GEOCODING_MAX_REDIRECTS} redirects.`, undefined);
220
+ }
221
+ const location = response.headers.get("location");
222
+ if (!location) {
223
+ throw new HonuaNetworkError("Redirect response is missing a Location header.", undefined);
224
+ }
225
+ let target;
226
+ try {
227
+ target = new URL(location, currentUrl);
228
+ }
229
+ catch {
230
+ throw new HonuaNetworkError(`Redirect response has an invalid Location header: ${location}`, undefined);
231
+ }
232
+ if (baseOrigin === undefined || target.origin !== baseOrigin) {
233
+ throw new HonuaNetworkError(`Refusing to follow a cross-origin redirect to ${target.origin}; the geocoding API key would be leaked.`, undefined);
234
+ }
235
+ currentUrl = target.toString();
236
+ await response.body?.cancel().catch(() => undefined);
237
+ }
238
+ }
239
+ geoServicesError(error, operation, responseHeaders) {
240
+ return new HonuaHttpError(error.code, `${operation} server error: ${error.message}`, { error }, {
241
+ transportStatus: 200,
242
+ protocolCode: error.code,
243
+ ...(responseHeaders ? { responseHeaders } : {}),
244
+ });
245
+ }
246
+ async request(url) {
247
+ const controller = new AbortController();
248
+ let timeoutId;
249
+ if (this.timeoutMs !== undefined) {
250
+ timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
251
+ }
252
+ let response;
253
+ try {
254
+ response = await this.fetchWithSafeRedirects(url, {
255
+ method: "GET",
256
+ headers: this.defaultHeaders,
257
+ signal: controller.signal,
258
+ });
259
+ }
260
+ catch (err) {
261
+ if (timeoutId !== undefined) {
262
+ clearTimeout(timeoutId);
263
+ }
264
+ if (err instanceof DOMException && err.name === "AbortError") {
265
+ if (this.timeoutMs !== undefined) {
266
+ throw new HonuaTimeoutError(this.timeoutMs);
267
+ }
268
+ throw new HonuaAbortError();
269
+ }
270
+ throw new HonuaNetworkError(err instanceof Error
271
+ ? `Geocoding request failed: ${err.message}`
272
+ : "Geocoding request failed due to a network error", err);
273
+ }
274
+ finally {
275
+ if (timeoutId !== undefined) {
276
+ clearTimeout(timeoutId);
277
+ }
278
+ }
279
+ if (!response.ok) {
280
+ let body;
281
+ try {
282
+ body = await response.json();
283
+ }
284
+ catch {
285
+ body = await response.text().catch(() => null);
286
+ }
287
+ throw new HonuaHttpError(response.status, `Geocoding request failed with status ${response.status}`, body, {
288
+ responseHeaders: response.headers,
289
+ });
290
+ }
291
+ return { data: (await response.json()), responseHeaders: response.headers };
292
+ }
293
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Minimal shared HTTP helper for the third-party geocoding / routing provider
3
+ * adapters. Mirrors the request semantics of the SDK's core clients — timeout
4
+ * composition and the typed error envelope (`HonuaTimeoutError`,
5
+ * `HonuaAbortError`, `HonuaNetworkError`, `HonuaHttpError`) — without pulling
6
+ * the full request pipeline into these small subpath bundles.
7
+ *
8
+ * Unlike `HonuaGeocodingClient`, provider adapters never attach Honua
9
+ * credentials, so the default fetch redirect behavior is safe here.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ /** Transport options shared by every provider adapter. @experimental */
14
+ export interface ProviderTransportOptions {
15
+ /** Custom fetch implementation (testing, interception, auth bridges). */
16
+ fetchFn?: typeof fetch;
17
+ /** Per-request timeout in milliseconds. */
18
+ timeoutMs?: number;
19
+ }
20
+ /** @internal */
21
+ export interface ProviderRequestInit extends ProviderTransportOptions {
22
+ /** Extra request headers (e.g. a Nominatim-policy `User-Agent`). */
23
+ headers?: Record<string, string>;
24
+ /** Label used in error messages, e.g. `"nominatim geocode"`. */
25
+ label: string;
26
+ }
27
+ /**
28
+ * GET a JSON document with the SDK's typed error mapping.
29
+ *
30
+ * @internal
31
+ */
32
+ export declare function providerGetJson<T>(url: string, init: ProviderRequestInit): Promise<T>;
33
+ /** Strip trailing slashes so adapters can join paths deterministically. @internal */
34
+ export declare function trimProviderBaseUrl(baseUrl: string): string;
35
+ /** Stringify provider attributes to the contract `Record<string, string | null>` shape. @internal */
36
+ export declare function stringifyProviderAttributes(attrs: Record<string, unknown>): Record<string, string | null>;
37
+ //# sourceMappingURL=provider-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-http.d.ts","sourceRoot":"","sources":["../../../src/geocoding/provider-http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,wEAAwE;AACxE,MAAM,WAAW,wBAAwB;IACvC,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gBAAgB;AAChB,MAAM,WAAW,mBAAoB,SAAQ,wBAAwB;IACnE,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAqD3F;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU3D;AAED,qGAAqG;AACrG,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CASzG"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Minimal shared HTTP helper for the third-party geocoding / routing provider
3
+ * adapters. Mirrors the request semantics of the SDK's core clients — timeout
4
+ * composition and the typed error envelope (`HonuaTimeoutError`,
5
+ * `HonuaAbortError`, `HonuaNetworkError`, `HonuaHttpError`) — without pulling
6
+ * the full request pipeline into these small subpath bundles.
7
+ *
8
+ * Unlike `HonuaGeocodingClient`, provider adapters never attach Honua
9
+ * credentials, so the default fetch redirect behavior is safe here.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { HonuaAbortError, HonuaHttpError, HonuaNetworkError, HonuaTimeoutError } from "../core/errors.js";
14
+ /**
15
+ * GET a JSON document with the SDK's typed error mapping.
16
+ *
17
+ * @internal
18
+ */
19
+ export async function providerGetJson(url, init) {
20
+ // Bind to `globalThis` at call time: invoking an unbound `window.fetch`
21
+ // throws "TypeError: Illegal invocation" in browsers.
22
+ const fetchFn = (init.fetchFn ?? fetch).bind(globalThis);
23
+ const controller = new AbortController();
24
+ let timeoutId;
25
+ if (init.timeoutMs !== undefined) {
26
+ timeoutId = setTimeout(() => controller.abort(), init.timeoutMs);
27
+ }
28
+ let response;
29
+ try {
30
+ response = await fetchFn(url, {
31
+ method: "GET",
32
+ headers: { Accept: "application/json", ...init.headers },
33
+ signal: controller.signal,
34
+ });
35
+ }
36
+ catch (err) {
37
+ if (err instanceof DOMException && err.name === "AbortError") {
38
+ if (init.timeoutMs !== undefined) {
39
+ throw new HonuaTimeoutError(init.timeoutMs);
40
+ }
41
+ throw new HonuaAbortError();
42
+ }
43
+ throw new HonuaNetworkError(err instanceof Error
44
+ ? `${init.label} request failed: ${err.message}`
45
+ : `${init.label} request failed due to a network error`, err);
46
+ }
47
+ finally {
48
+ if (timeoutId !== undefined) {
49
+ clearTimeout(timeoutId);
50
+ }
51
+ }
52
+ if (!response.ok) {
53
+ let body;
54
+ try {
55
+ body = await response.json();
56
+ }
57
+ catch {
58
+ body = await response.text().catch(() => null);
59
+ }
60
+ throw new HonuaHttpError(response.status, `${init.label} request failed with status ${response.status}`, body, {
61
+ responseHeaders: response.headers,
62
+ });
63
+ }
64
+ try {
65
+ return (await response.json());
66
+ }
67
+ catch (err) {
68
+ throw new HonuaNetworkError(`${init.label} response was not valid JSON`, err);
69
+ }
70
+ }
71
+ /** Strip trailing slashes so adapters can join paths deterministically. @internal */
72
+ export function trimProviderBaseUrl(baseUrl) {
73
+ let end = baseUrl.length;
74
+ while (end > 0 && baseUrl[end - 1] === "/") {
75
+ end -= 1;
76
+ }
77
+ const trimmed = baseUrl.slice(0, end);
78
+ if (!trimmed) {
79
+ throw new Error("Provider baseUrl must be a non-empty URL (no default third-party endpoint is baked in).");
80
+ }
81
+ return trimmed;
82
+ }
83
+ /** Stringify provider attributes to the contract `Record<string, string | null>` shape. @internal */
84
+ export function stringifyProviderAttributes(attrs) {
85
+ const result = {};
86
+ for (const [key, value] of Object.entries(attrs)) {
87
+ if (value === undefined) {
88
+ continue;
89
+ }
90
+ result[key] = value === null ? null : String(value);
91
+ }
92
+ return result;
93
+ }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Provider-pluggable geocoding contract: `GeocodingProvider` plus the
3
+ * normalized result shapes every adapter maps into. The Honua facade
4
+ * (`honuaGeocodingProvider`) and the open-source adapters (Nominatim, Photon,
5
+ * Pelias) all implement this one interface so hosts can swap providers with
6
+ * configuration only.
7
+ *
8
+ * Capability differences between providers are declared up front via
9
+ * {@link GeocodingProvider.capabilities} and enforced with the SDK's existing
10
+ * capability policy: an unsupported operation throws
11
+ * `HonuaCapabilityNotSupportedError` under the default `"strict"` policy and
12
+ * degrades to an empty result under `"degraded"`.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ import type { CapabilityPolicy } from "../contract/types.js";
17
+ /**
18
+ * Operations a {@link GeocodingProvider} may support.
19
+ *
20
+ * @experimental
21
+ */
22
+ export type GeocodingCapability = "geocode" | "reverse" | "suggest";
23
+ /**
24
+ * Identifies which provider produced a result and carries that provider's
25
+ * attribution / usage-policy obligations so hosts can surface them (for
26
+ * example in a map attribution control).
27
+ *
28
+ * @experimental
29
+ */
30
+ export interface GeocodingProvenance {
31
+ /** Provider identifier, e.g. `"nominatim"`, `"photon"`, `"pelias"`, `"honua"`. */
32
+ readonly provider: string;
33
+ /** Human-readable data attribution the host is obliged to display. */
34
+ readonly attribution: string;
35
+ /** Usage/acceptable-use policy for the configured endpoint, when known. */
36
+ readonly usagePolicyUrl?: string;
37
+ }
38
+ /**
39
+ * Normalized forward-geocode candidate. Mirrors the contract shape of
40
+ * `GeocodeResult` with provider provenance stamped on every result.
41
+ *
42
+ * @experimental
43
+ */
44
+ export interface ProviderGeocodeMatch {
45
+ /** Formatted address / place label. */
46
+ address: string;
47
+ latitude: number;
48
+ longitude: number;
49
+ /**
50
+ * Provider-reported match quality when available (Nominatim `importance`,
51
+ * Pelias `confidence`, Honua locator `score`). Scale is provider-specific.
52
+ */
53
+ score?: number;
54
+ /** Provider-specific attributes, stringified to the contract shape. */
55
+ attributes: Record<string, string | null>;
56
+ provenance: GeocodingProvenance;
57
+ }
58
+ /**
59
+ * Normalized reverse-geocode result.
60
+ *
61
+ * @experimental
62
+ */
63
+ export interface ProviderReverseMatch {
64
+ address: string;
65
+ latitude: number;
66
+ longitude: number;
67
+ attributes: Record<string, string | null>;
68
+ provenance: GeocodingProvenance;
69
+ }
70
+ /**
71
+ * Normalized typeahead suggestion.
72
+ *
73
+ * @experimental
74
+ */
75
+ export interface ProviderSuggestion {
76
+ text: string;
77
+ provenance: GeocodingProvenance;
78
+ }
79
+ /**
80
+ * Options for {@link GeocodingProvider.geocode}.
81
+ *
82
+ * @experimental
83
+ */
84
+ export interface ProviderGeocodeOptions {
85
+ /** Maximum number of candidates to return. */
86
+ limit?: number;
87
+ /** Comma-separated ISO 3166-1 alpha-2 country codes, e.g. `"us,ca"`. */
88
+ countryCodes?: string;
89
+ }
90
+ /**
91
+ * Options for {@link GeocodingProvider.suggest}.
92
+ *
93
+ * @experimental
94
+ */
95
+ export interface ProviderSuggestOptions {
96
+ /** Maximum number of suggestions to return. */
97
+ limit?: number;
98
+ /** Comma-separated ISO 3166-1 alpha-2 country codes, e.g. `"us,ca"`. */
99
+ countryCodes?: string;
100
+ }
101
+ /**
102
+ * Provider-pluggable geocoding contract. All adapters normalize into the same
103
+ * typed result shapes; capability differences are declared, not discovered at
104
+ * runtime.
105
+ *
106
+ * Operations outside {@link capabilities} throw
107
+ * `HonuaCapabilityNotSupportedError` under the `"strict"` capability policy
108
+ * (the default) and resolve to an empty result under `"degraded"`.
109
+ *
110
+ * @experimental
111
+ */
112
+ export interface GeocodingProvider {
113
+ /** Stable provider identifier, e.g. `"nominatim"`. */
114
+ readonly id: string;
115
+ /** Operations this provider supports. */
116
+ readonly capabilities: ReadonlyArray<GeocodingCapability>;
117
+ /** Human-readable data attribution the host is obliged to display. */
118
+ readonly attribution: string;
119
+ /** Usage/acceptable-use policy for the configured endpoint, when known. */
120
+ readonly usagePolicyUrl?: string;
121
+ /** Forward-geocode a free-text query into candidate locations. */
122
+ geocode(query: string, options?: ProviderGeocodeOptions): Promise<ProviderGeocodeMatch[]>;
123
+ /** Reverse-geocode a latitude/longitude pair; `null` when nothing is found. */
124
+ reverse(latitude: number, longitude: number): Promise<ProviderReverseMatch | null>;
125
+ /** Typeahead suggestions for a partial query. */
126
+ suggest(text: string, options?: ProviderSuggestOptions): Promise<ProviderSuggestion[]>;
127
+ }
128
+ /**
129
+ * `true` when `provider` declares `capability`.
130
+ *
131
+ * @experimental
132
+ */
133
+ export declare function supportsGeocodingCapability(provider: GeocodingProvider, capability: GeocodingCapability): boolean;
134
+ /**
135
+ * Enforce a capability declaration against the active capability policy.
136
+ * Returns `true` when the capability is supported. When it is missing, throws
137
+ * `HonuaCapabilityNotSupportedError` under `"strict"` (the default) or returns
138
+ * `false` under `"degraded"` so callers can resolve to an empty result.
139
+ *
140
+ * @experimental
141
+ */
142
+ export declare function assertGeocodingCapability(provider: Pick<GeocodingProvider, "id" | "capabilities">, capability: GeocodingCapability, policy?: CapabilityPolicy): boolean;
143
+ /** Re-exported so provider hosts can type their policy without importing `/contract`. */
144
+ export type { CapabilityPolicy };
145
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/geocoding/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Provider-pluggable geocoding contract: `GeocodingProvider` plus the
3
+ * normalized result shapes every adapter maps into. The Honua facade
4
+ * (`honuaGeocodingProvider`) and the open-source adapters (Nominatim, Photon,
5
+ * Pelias) all implement this one interface so hosts can swap providers with
6
+ * configuration only.
7
+ *
8
+ * Capability differences between providers are declared up front via
9
+ * {@link GeocodingProvider.capabilities} and enforced with the SDK's existing
10
+ * capability policy: an unsupported operation throws
11
+ * `HonuaCapabilityNotSupportedError` under the default `"strict"` policy and
12
+ * degrades to an empty result under `"degraded"`.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ import { HonuaCapabilityNotSupportedError } from "../core/errors.js";
17
+ /**
18
+ * `true` when `provider` declares `capability`.
19
+ *
20
+ * @experimental
21
+ */
22
+ export function supportsGeocodingCapability(provider, capability) {
23
+ return provider.capabilities.includes(capability);
24
+ }
25
+ /**
26
+ * Enforce a capability declaration against the active capability policy.
27
+ * Returns `true` when the capability is supported. When it is missing, throws
28
+ * `HonuaCapabilityNotSupportedError` under `"strict"` (the default) or returns
29
+ * `false` under `"degraded"` so callers can resolve to an empty result.
30
+ *
31
+ * @experimental
32
+ */
33
+ export function assertGeocodingCapability(provider, capability, policy = "strict") {
34
+ if (provider.capabilities.includes(capability)) {
35
+ return true;
36
+ }
37
+ if (policy === "strict") {
38
+ throw new HonuaCapabilityNotSupportedError(capability, provider.id);
39
+ }
40
+ return false;
41
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Honua facade adapter: wraps the existing {@link HonuaGeocodingClient}
3
+ * (Honua-hosted GeocodeServer locator) in the provider-pluggable
4
+ * {@link GeocodingProvider} contract, making the Honua facade one provider
5
+ * among several.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import type { CapabilityPolicy } from "../../contract/types.js";
10
+ import type { HonuaGeocodingClient } from "../index.js";
11
+ import { type GeocodingProvider } from "../provider.js";
12
+ /** Options for {@link honuaGeocodingProvider}. @experimental */
13
+ export interface HonuaGeocodingProviderOptions {
14
+ /** Capability policy; the Honua locator supports all declared operations. */
15
+ capabilityPolicy?: CapabilityPolicy;
16
+ /** Override the default attribution string for your deployment's data. */
17
+ attribution?: string;
18
+ /** Usage-policy URL for your deployment, when applicable. */
19
+ usagePolicyUrl?: string;
20
+ }
21
+ /**
22
+ * Wrap a {@link HonuaGeocodingClient} in the {@link GeocodingProvider}
23
+ * contract.
24
+ *
25
+ * @experimental
26
+ */
27
+ export declare function honuaGeocodingProvider(client: HonuaGeocodingClient, options?: HonuaGeocodingProviderOptions): GeocodingProvider;
28
+ //# sourceMappingURL=honua.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"honua.d.ts","sourceRoot":"","sources":["../../../../src/geocoding/providers/honua.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAGL,KAAK,iBAAiB,EAOvB,MAAM,gBAAgB,CAAC;AAExB,gEAAgE;AAChE,MAAM,WAAW,6BAA6B;IAC5C,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAKD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,GAAE,6BAAkC,GAC1C,iBAAiB,CAsDnB"}