@honua/react 0.1.11-beta.0 → 0.1.13
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.
- package/columnar/apache-arrow.d.ts +17 -0
- package/columnar/apache-arrow.d.ts.map +1 -0
- package/columnar/apache-arrow.js +1036 -0
- package/columnar/batch-cache-conformance.d.ts +66 -0
- package/columnar/batch-cache-conformance.d.ts.map +1 -0
- package/columnar/batch-cache-conformance.js +317 -0
- package/columnar/batch-cache-indexeddb.d.ts +31 -0
- package/columnar/batch-cache-indexeddb.d.ts.map +1 -0
- package/columnar/batch-cache-indexeddb.js +148 -0
- package/columnar/batch-cache.d.ts +298 -0
- package/columnar/batch-cache.d.ts.map +1 -0
- package/columnar/batch-cache.js +757 -0
- package/columnar/geoarrow-aggregate.d.ts +178 -0
- package/columnar/geoarrow-aggregate.d.ts.map +1 -0
- package/columnar/geoarrow-aggregate.js +976 -0
- package/columnar/geoarrow-patch.d.ts +382 -0
- package/columnar/geoarrow-patch.d.ts.map +1 -0
- package/columnar/geoarrow-patch.js +1656 -0
- package/columnar/geoarrow-reproject.d.ts +22 -0
- package/columnar/geoarrow-reproject.d.ts.map +1 -0
- package/columnar/geoarrow-reproject.js +119 -0
- package/columnar/geoarrow-serialization.d.ts +68 -0
- package/columnar/geoarrow-serialization.d.ts.map +1 -0
- package/columnar/geoarrow-serialization.js +331 -0
- package/columnar/geoarrow-types.d.ts +271 -0
- package/columnar/geoarrow-types.d.ts.map +1 -0
- package/columnar/geoarrow-types.js +15 -0
- package/columnar/geoarrow.d.ts +52 -0
- package/columnar/geoarrow.d.ts.map +1 -0
- package/columnar/geoarrow.js +1469 -0
- package/columnar/index.d.ts +43 -0
- package/columnar/index.d.ts.map +1 -0
- package/columnar/index.js +29 -0
- package/columnar/operators.d.ts +70 -0
- package/columnar/operators.d.ts.map +1 -0
- package/columnar/operators.js +307 -0
- package/columnar/result.d.ts +369 -0
- package/columnar/result.d.ts.map +1 -0
- package/columnar/result.js +815 -0
- package/columnar/telemetry.d.ts +152 -0
- package/columnar/telemetry.d.ts.map +1 -0
- package/columnar/telemetry.js +265 -0
- package/columnar/transfer.d.ts +28 -0
- package/columnar/transfer.d.ts.map +1 -0
- package/columnar/transfer.js +669 -0
- package/columnar/types.d.ts +175 -0
- package/columnar/types.d.ts.map +1 -0
- package/columnar/types.js +22 -0
- package/columnar/worker.d.ts +157 -0
- package/columnar/worker.d.ts.map +1 -0
- package/columnar/worker.js +1059 -0
- package/connect-url-safety.d.ts +53 -0
- package/connect-url-safety.js +189 -0
- package/contract/pmtiles.d.ts +6 -5
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +30 -5
- package/control-plane/generated/admin-operations.d.ts +3 -3
- package/control-plane/generated/admin-operations.d.ts.map +1 -1
- package/control-plane/generated/admin-operations.js +3 -3
- package/core/client.d.ts.map +1 -1
- package/core/client.js +87 -19
- package/core/deprecation-notice.d.ts +28 -0
- package/core/deprecation-notice.d.ts.map +1 -0
- package/core/deprecation-notice.js +22 -0
- package/core/esri-geojson.d.ts.map +1 -1
- package/core/esri-geojson.js +10 -6
- package/core/optional-grpc-peer.d.ts +15 -0
- package/core/optional-grpc-peer.d.ts.map +1 -0
- package/core/optional-grpc-peer.js +60 -0
- package/esri-compat/basemap-gallery.d.ts +2 -0
- package/esri-compat/basemap-gallery.d.ts.map +1 -1
- package/esri-compat/basemap-gallery.js +12 -0
- package/esri-compat/basemap.d.ts +4 -0
- package/esri-compat/basemap.d.ts.map +1 -1
- package/esri-compat/basemap.js +70 -0
- package/esri-compat/bookmarks.d.ts +2 -0
- package/esri-compat/bookmarks.d.ts.map +1 -1
- package/esri-compat/bookmarks.js +12 -0
- package/esri-compat/controls.d.ts +18 -0
- package/esri-compat/controls.d.ts.map +1 -1
- package/esri-compat/controls.js +120 -57
- package/esri-compat/directions.d.ts +4 -0
- package/esri-compat/directions.d.ts.map +1 -1
- package/esri-compat/directions.js +30 -20
- package/esri-compat/editor.d.ts +4 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +16 -0
- package/esri-compat/esri-config.d.ts +2 -1
- package/esri-compat/esri-config.d.ts.map +1 -1
- package/esri-compat/feature-effect.d.ts +23 -0
- package/esri-compat/feature-effect.d.ts.map +1 -0
- package/esri-compat/feature-effect.js +12 -0
- package/esri-compat/feature-form.d.ts +6 -0
- package/esri-compat/feature-form.d.ts.map +1 -1
- package/esri-compat/feature-form.js +63 -0
- package/esri-compat/feature-layer.d.ts +21 -2
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +172 -1
- package/esri-compat/feature-table.d.ts +5 -0
- package/esri-compat/feature-table.d.ts.map +1 -1
- package/esri-compat/feature-table.js +23 -0
- package/esri-compat/identity-manager.d.ts +1 -1
- package/esri-compat/identity-manager.js +1 -1
- package/esri-compat/legend.d.ts +2 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +98 -0
- package/esri-compat/locator.d.ts +1 -1
- package/esri-compat/locator.js +1 -1
- package/esri-compat/map-view-mount.d.ts +1 -0
- package/esri-compat/map-view-mount.d.ts.map +1 -1
- package/esri-compat/map-view-mount.js +46 -25
- package/esri-compat/map-view.d.ts +13 -0
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +94 -8
- package/esri-compat/map.d.ts +5 -1
- package/esri-compat/map.d.ts.map +1 -1
- package/esri-compat/map.js +10 -0
- package/esri-compat/measurement.d.ts +2 -0
- package/esri-compat/measurement.d.ts.map +1 -1
- package/esri-compat/measurement.js +14 -0
- package/esri-compat/point.d.ts +7 -0
- package/esri-compat/point.d.ts.map +1 -1
- package/esri-compat/point.js +33 -3
- package/esri-compat/popup.d.ts +2 -0
- package/esri-compat/popup.d.ts.map +1 -1
- package/esri-compat/popup.js +12 -0
- package/esri-compat/portal.d.ts +1 -1
- package/esri-compat/portal.js +1 -1
- package/esri-compat/print.d.ts +3 -0
- package/esri-compat/print.d.ts.map +1 -1
- package/esri-compat/print.js +15 -0
- package/esri-compat/search.d.ts +4 -0
- package/esri-compat/search.d.ts.map +1 -1
- package/esri-compat/search.js +25 -28
- package/esri-compat/sketch.d.ts +2 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +12 -0
- package/esri-compat/widget-host.d.ts +46 -17
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +84 -20
- package/esri-compat/widget-shell-hosts.d.ts +61 -0
- package/esri-compat/widget-shell-hosts.d.ts.map +1 -0
- package/esri-compat/widget-shell-hosts.js +76 -0
- package/geocoding/index.d.ts +114 -0
- package/geocoding/index.d.ts.map +1 -0
- package/geocoding/index.js +293 -0
- package/geocoding/provider-http.d.ts +37 -0
- package/geocoding/provider-http.d.ts.map +1 -0
- package/geocoding/provider-http.js +93 -0
- package/geocoding/provider.d.ts +145 -0
- package/geocoding/provider.d.ts.map +1 -0
- package/geocoding/provider.js +41 -0
- package/geocoding/providers/honua.d.ts +28 -0
- package/geocoding/providers/honua.d.ts.map +1 -0
- package/geocoding/providers/honua.js +68 -0
- package/geocoding/providers/nominatim.d.ts +47 -0
- package/geocoding/providers/nominatim.d.ts.map +1 -0
- package/geocoding/providers/nominatim.js +105 -0
- package/geocoding/providers/pelias.d.ts +40 -0
- package/geocoding/providers/pelias.d.ts.map +1 -0
- package/geocoding/providers/pelias.js +115 -0
- package/geocoding/providers/photon.d.ts +39 -0
- package/geocoding/providers/photon.d.ts.map +1 -0
- package/geocoding/providers/photon.js +107 -0
- package/geometry/convert.d.ts +13 -0
- package/geometry/convert.d.ts.map +1 -0
- package/geometry/convert.js +12 -0
- package/geometry/index.d.ts +17 -0
- package/geometry/index.d.ts.map +1 -0
- package/geometry/index.js +15 -0
- package/geometry/internal.d.ts +25 -0
- package/geometry/internal.d.ts.map +1 -0
- package/geometry/internal.js +40 -0
- package/geometry/ops.d.ts +71 -0
- package/geometry/ops.d.ts.map +1 -0
- package/geometry/ops.js +147 -0
- package/geometry/project.d.ts +40 -0
- package/geometry/project.d.ts.map +1 -0
- package/geometry/project.js +88 -0
- package/geometry/types.d.ts +36 -0
- package/geometry/types.d.ts.map +1 -0
- package/geometry/types.js +12 -0
- package/kernel/renderer.d.ts +82 -0
- package/kernel/renderer.js +1 -0
- package/offline/digest.d.ts +15 -0
- package/offline/digest.js +58 -0
- package/offline/quota.d.ts +161 -0
- package/offline/quota.js +370 -0
- package/offline/types.d.ts +349 -0
- package/offline/types.js +75 -0
- package/package.json +14 -2
- package/widget-capabilities.d.ts +67 -0
- 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"}
|