@honua/react 0.1.2-beta.0 → 0.1.4-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.
- package/contract/discovery.d.ts +34 -0
- package/contract/discovery.d.ts.map +1 -1
- package/contract/index.d.ts +7 -5
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +3 -2
- package/contract/pmtiles.d.ts +10 -1
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +10 -2
- package/contract/protocol-module.d.ts +84 -9
- package/contract/protocol-module.d.ts.map +1 -1
- package/contract/query-filter-fes.d.ts +18 -0
- package/contract/query-filter-fes.d.ts.map +1 -0
- package/contract/query-filter-fes.js +122 -0
- package/contract/query-filter.d.ts +300 -0
- package/contract/query-filter.d.ts.map +1 -0
- package/contract/query-filter.js +883 -0
- package/contract/schema.d.ts +12 -0
- package/contract/schema.d.ts.map +1 -1
- package/contract/schema.js +34 -0
- package/contract/source-capability-support.d.ts.map +1 -1
- package/contract/source-capability-support.js +15 -3
- package/contract/source.d.ts +45 -25
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +719 -479
- package/contract/types.d.ts +87 -18
- package/contract/types.d.ts.map +1 -1
- package/contract/widget-source.d.ts.map +1 -1
- package/core/client.d.ts +45 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +224 -46
- package/core/error-classifications.d.ts +6 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +6 -0
- package/core/error-code-registry.d.ts +6 -0
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +6 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +68 -4
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +325 -8
- package/core/odata-write-codec.d.ts.map +1 -1
- package/core/odata-write-codec.js +0 -1
- package/core/odata.d.ts +6 -0
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +6 -1
- package/core/ogc-processes.d.ts +182 -25
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +602 -30
- package/core/process-runner.d.ts +8 -1
- package/core/process-runner.d.ts.map +1 -1
- package/core/process-runner.js +1 -0
- package/core/protocol-transport.d.ts +2 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/stac.d.ts +31 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +136 -19
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +123 -9
- package/core/types.d.ts.map +1 -1
- package/core/wfs-axis-order.d.ts +18 -0
- package/core/wfs-axis-order.d.ts.map +1 -0
- package/core/wfs-axis-order.js +108 -0
- package/core/wfs-capabilities.d.ts +65 -24
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +237 -27
- package/core/wfs-filter.d.ts +26 -3
- package/core/wfs-filter.d.ts.map +1 -1
- package/core/wfs-filter.js +48 -53
- package/core/wfs-protocol-error.d.ts +12 -0
- package/core/wfs-protocol-error.d.ts.map +1 -0
- package/core/wfs-protocol-error.js +13 -0
- package/core/wfs.d.ts +53 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +251 -29
- package/core/wms-feature-info.d.ts +92 -0
- package/core/wms-feature-info.d.ts.map +1 -0
- package/core/wms-feature-info.js +285 -0
- package/core/wms.d.ts +9 -0
- package/core/wms.d.ts.map +1 -1
- package/core/wms.js +17 -5
- package/esri-compat/event-bus.d.ts +20 -0
- package/esri-compat/event-bus.d.ts.map +1 -1
- package/esri-compat/feature-filter.d.ts +46 -1
- package/esri-compat/feature-filter.d.ts.map +1 -1
- package/esri-compat/feature-filter.js +49 -0
- package/esri-compat/geojson-layer.d.ts +4 -2
- package/esri-compat/geojson-layer.d.ts.map +1 -1
- package/esri-compat/geojson-layer.js +4 -2
- package/esri-compat/identity-manager.js +2 -2
- package/esri-compat/imagery-layer.d.ts +2 -1
- package/esri-compat/imagery-layer.d.ts.map +1 -1
- package/esri-compat/imagery-layer.js +2 -1
- package/esri-compat/layer-list.d.ts +8 -1
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +11 -4
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +1 -1
- package/esri-compat/locator.d.ts +297 -0
- package/esri-compat/locator.d.ts.map +1 -0
- package/esri-compat/locator.js +579 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -1
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +1 -1
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/time-slider.d.ts +29 -0
- package/esri-compat/time-slider.d.ts.map +1 -1
- package/esri-compat/time-slider.js +117 -0
- package/esri-compat/wfs-layer.d.ts +2 -1
- package/esri-compat/wfs-layer.d.ts.map +1 -1
- package/esri-compat/wfs-layer.js +2 -1
- package/esri-compat/widget-host.d.ts +42 -6
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +99 -10
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/runtime.d.ts.map +1 -1
- package/map/data-to-map-bridge.d.ts +1 -1
- package/map/data-to-map-bridge.d.ts.map +1 -1
- package/map/data-to-map-bridge.js +1 -2
- package/map/honua-map.d.ts.map +1 -1
- package/map/honua-map.js +1 -1
- package/map/index.d.ts +2 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +2 -0
- package/map/realtime-reconciliation-adapter.d.ts +98 -0
- package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
- package/map/realtime-reconciliation-adapter.js +84 -0
- package/map/temporal-playback.d.ts +25 -0
- package/map/temporal-playback.d.ts.map +1 -1
- package/map/temporal-playback.js +29 -1
- package/package.json +4 -3
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- package/query-planner/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -0
- package/query-planner/diagnostics.d.ts +3 -3
- package/query-planner/diagnostics.d.ts.map +1 -1
- package/query-planner/diagnostics.js +17 -4
- package/query-planner/duckdb.d.ts.map +1 -1
- package/query-planner/duckdb.js +16 -2
- package/query-planner/execution-context.d.ts.map +1 -1
- package/query-planner/execution-context.js +3 -1
- package/query-planner/executor.d.ts.map +1 -1
- package/query-planner/executor.js +7 -1
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +24 -5
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +29 -5
- package/query-planner/index.d.ts +20 -5
- package/query-planner/index.d.ts.map +1 -1
- package/query-planner/index.js +16 -3
- package/query-planner/ir.d.ts +6 -1
- package/query-planner/ir.d.ts.map +1 -1
- package/query-planner/ir.js +63 -1
- package/query-planner/odata-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +0 -3
- package/query-planner/odata.d.ts.map +1 -1
- package/query-planner/odata.js +0 -143
- package/query-planner/ogc-features.d.ts.map +1 -1
- package/query-planner/ogc-features.js +23 -1
- package/query-planner/planner.d.ts +2 -2
- package/query-planner/planner.d.ts.map +1 -1
- package/query-planner/planner.js +146 -27
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -0
- package/query-planner/types.d.ts +153 -3
- package/query-planner/types.d.ts.map +1 -1
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -0
- package/query-planner/wfs-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +1 -3
- package/query-planner/wfs.d.ts.map +1 -1
- package/query-planner/wfs.js +1 -70
- package/react/honua-map.d.ts +3 -1
- package/react/honua-map.d.ts.map +1 -1
- package/react/honua-map.js +11 -1
- package/react/hooks.d.ts +1 -1
- package/react/hooks.js +1 -1
- package/react/selection.d.ts.map +1 -1
- package/react/selection.js +0 -0
- package/react/use-mounted-source.d.ts +1 -1
- package/react/use-mounted-source.js +1 -1
- package/realtime/checkpoint-store.d.ts +206 -0
- package/realtime/checkpoint-store.d.ts.map +1 -0
- package/realtime/checkpoint-store.js +504 -0
- package/realtime/contract.d.ts +142 -0
- package/realtime/contract.d.ts.map +1 -0
- package/realtime/contract.js +154 -0
- package/realtime/exploration.d.ts +16 -0
- package/realtime/exploration.d.ts.map +1 -0
- package/realtime/exploration.js +32 -0
- package/realtime/honua-server.d.ts +131 -0
- package/realtime/honua-server.d.ts.map +1 -0
- package/realtime/honua-server.js +302 -0
- package/realtime/index.d.ts +39 -0
- package/realtime/index.d.ts.map +1 -0
- package/realtime/index.js +26 -0
- package/realtime/odata-delta.d.ts +114 -0
- package/realtime/odata-delta.d.ts.map +1 -0
- package/realtime/odata-delta.js +483 -0
- package/realtime/projections.d.ts +30 -0
- package/realtime/projections.d.ts.map +1 -0
- package/realtime/projections.js +51 -0
- package/realtime/reconciliation.d.ts +245 -0
- package/realtime/reconciliation.d.ts.map +1 -0
- package/realtime/reconciliation.js +377 -0
- package/realtime/reducer.d.ts +14 -0
- package/realtime/reducer.d.ts.map +1 -0
- package/realtime/reducer.js +351 -0
- package/realtime/resumable-transport.d.ts +111 -0
- package/realtime/resumable-transport.d.ts.map +1 -0
- package/realtime/resumable-transport.js +406 -0
- package/realtime/resumable.d.ts +104 -0
- package/realtime/resumable.d.ts.map +1 -0
- package/realtime/resumable.js +632 -0
- package/realtime/sse.d.ts +23 -0
- package/realtime/sse.d.ts.map +1 -0
- package/realtime/sse.js +147 -0
- package/realtime/store.d.ts +18 -0
- package/realtime/store.d.ts.map +1 -0
- package/realtime/store.js +63 -0
- package/realtime/types.d.ts +190 -0
- package/realtime/types.d.ts.map +1 -0
- package/realtime/types.js +10 -0
- package/realtime/websocket.d.ts +60 -0
- package/realtime/websocket.d.ts.map +1 -0
- package/realtime/websocket.js +157 -0
- package/realtime/wire.d.ts +28 -0
- package/realtime/wire.d.ts.map +1 -0
- package/realtime/wire.js +73 -0
- package/runtime/index.d.ts +6 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -1
- package/runtime/load-package.d.ts +24 -0
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +45 -1
- package/runtime/maplibre-renderer.d.ts +11 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -1
- package/runtime/maplibre-renderer.js +32 -7
- package/runtime/offline-region-protocol.d.ts +73 -0
- package/runtime/offline-region-protocol.d.ts.map +1 -0
- package/runtime/offline-region-protocol.js +63 -0
- package/runtime/offline-region-style.d.ts +78 -0
- package/runtime/offline-region-style.d.ts.map +1 -0
- package/runtime/offline-region-style.js +147 -0
- package/runtime/pmtiles-protocol.d.ts +7 -8
- package/runtime/pmtiles-protocol.d.ts.map +1 -1
- package/runtime/pmtiles-protocol.js +19 -66
- package/runtime/protocol-registry.d.ts +55 -0
- package/runtime/protocol-registry.d.ts.map +1 -0
- package/runtime/protocol-registry.js +103 -0
- package/runtime/runtime.d.ts +2 -0
- package/runtime/runtime.d.ts.map +1 -1
- package/runtime/runtime.js +6 -1
- package/studio/index.d.ts +24 -7
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -7
- package/studio/lifecycle-client.d.ts +164 -0
- package/studio/lifecycle-client.d.ts.map +1 -0
- package/studio/lifecycle-client.js +299 -0
- package/studio/lifecycle-errors.d.ts +91 -0
- package/studio/lifecycle-errors.d.ts.map +1 -0
- package/studio/lifecycle-errors.js +77 -0
- package/studio/lifecycle-types.d.ts +321 -0
- package/studio/lifecycle-types.d.ts.map +1 -0
- package/studio/lifecycle-types.js +22 -0
- package/webmap/convert-label.js +0 -1
- package/webmap/convert-symbol.d.ts.map +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HonuaSdkError } from "./error-envelope.js";
|
|
2
|
+
/** Typed, credential-safe fail-closed WFS protocol error. */
|
|
3
|
+
export class HonuaWfsProtocolError extends HonuaSdkError {
|
|
4
|
+
reason;
|
|
5
|
+
constructor(reason, message, options = {}) {
|
|
6
|
+
super("query.execution.wfs-protocol", message, {
|
|
7
|
+
context: { reason },
|
|
8
|
+
...("cause" in options ? { cause: options.cause } : {}),
|
|
9
|
+
});
|
|
10
|
+
this.reason = reason;
|
|
11
|
+
this.name = "HonuaWfsProtocolError";
|
|
12
|
+
}
|
|
13
|
+
}
|
package/core/wfs.d.ts
CHANGED
|
@@ -50,9 +50,10 @@ export declare class HonuaWfs {
|
|
|
50
50
|
readonly version: string;
|
|
51
51
|
/** Counter exposed for tests / diagnostics: how many times capabilities was fetched. */
|
|
52
52
|
capabilitiesFetches: number;
|
|
53
|
-
private capabilitiesPromise;
|
|
54
53
|
private rawCapabilitiesXml;
|
|
55
54
|
private resolvedSnapshot;
|
|
55
|
+
/** Resolved geometry property per feature type; shares the metadata cache lifecycle. */
|
|
56
|
+
private readonly geometryPropertyNames;
|
|
56
57
|
constructor(options: HonuaWfsOptions);
|
|
57
58
|
/**
|
|
58
59
|
* Fetch and cache the GetCapabilities document. Subsequent calls reuse the
|
|
@@ -63,6 +64,33 @@ export declare class HonuaWfs {
|
|
|
63
64
|
}): Promise<WfsCapabilitiesSnapshot>;
|
|
64
65
|
/** Discard the cached capabilities snapshot so the next call re-fetches. */
|
|
65
66
|
refresh(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Fetch the `DescribeFeatureType` XSD for one feature type. Returned raw so
|
|
69
|
+
* `Source.protocol("wfs")` callers can read schema detail the canonical
|
|
70
|
+
* surface does not model.
|
|
71
|
+
*/
|
|
72
|
+
describeFeatureType(typeName: string, options?: {
|
|
73
|
+
signal?: AbortSignal;
|
|
74
|
+
}): Promise<{
|
|
75
|
+
text: string;
|
|
76
|
+
contentType: string;
|
|
77
|
+
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the geometry property name of one feature type from its
|
|
80
|
+
* `DescribeFeatureType` schema, caching the result alongside the
|
|
81
|
+
* capabilities snapshot. Fails closed with
|
|
82
|
+
* `HonuaWfsProtocolError("unresolved-geometry-property")` rather than
|
|
83
|
+
* assuming a vendor default: `the_geom` is only the PostGIS-via-GeoServer
|
|
84
|
+
* convention, MapServer serves `msGeometry`, and other servers use
|
|
85
|
+
* per-schema names, so guessing silently matches nothing.
|
|
86
|
+
*
|
|
87
|
+
* Feature types that declare several geometry properties resolve to the
|
|
88
|
+
* first declared one (the server's default geometry); pin a different one
|
|
89
|
+
* with `locator.geometryName`.
|
|
90
|
+
*/
|
|
91
|
+
geometryPropertyName(typeName: string, options?: {
|
|
92
|
+
signal?: AbortSignal;
|
|
93
|
+
}): Promise<string>;
|
|
66
94
|
/**
|
|
67
95
|
* Resolve the concrete request URL for a WFS operation, honouring the
|
|
68
96
|
* DCP `xlink:href` a raw server advertises in GetCapabilities (e.g.
|
|
@@ -94,6 +122,7 @@ export declare class HonuaWfs {
|
|
|
94
122
|
contentType?: string;
|
|
95
123
|
body?: string;
|
|
96
124
|
signal?: AbortSignal;
|
|
125
|
+
maxResponseBytes?: number;
|
|
97
126
|
}): Promise<{
|
|
98
127
|
text: string;
|
|
99
128
|
contentType: string;
|
|
@@ -120,6 +149,21 @@ export declare class HonuaWfsFeatureType {
|
|
|
120
149
|
capabilities(options?: {
|
|
121
150
|
signal?: AbortSignal;
|
|
122
151
|
}): Promise<WfsCapabilitiesSnapshot>;
|
|
152
|
+
/** Raw `DescribeFeatureType` XSD for the bound type name. */
|
|
153
|
+
describeFeatureType(options?: {
|
|
154
|
+
signal?: AbortSignal;
|
|
155
|
+
}): Promise<{
|
|
156
|
+
text: string;
|
|
157
|
+
contentType: string;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Geometry property name of the bound feature type, resolved from
|
|
161
|
+
* `DescribeFeatureType` and cached on the root. Fails closed when the schema
|
|
162
|
+
* does not name one — see {@link HonuaWfs.geometryPropertyName}.
|
|
163
|
+
*/
|
|
164
|
+
geometryPropertyName(options?: {
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
}): Promise<string>;
|
|
123
167
|
/**
|
|
124
168
|
* Issue a GetFeature request. Returns parsed JSON when the negotiated
|
|
125
169
|
* output format is JSON; otherwise returns the raw body as a string for
|
|
@@ -137,6 +181,10 @@ export declare class HonuaWfsFeatureType {
|
|
|
137
181
|
outputFormat?: string;
|
|
138
182
|
method?: "GET" | "POST";
|
|
139
183
|
body?: string;
|
|
184
|
+
namespace?: {
|
|
185
|
+
readonly prefix: string;
|
|
186
|
+
readonly uri: string;
|
|
187
|
+
};
|
|
140
188
|
signal?: AbortSignal;
|
|
141
189
|
}): Promise<{
|
|
142
190
|
kind: "json";
|
|
@@ -176,6 +224,10 @@ export declare class HonuaWfsFeatureType {
|
|
|
176
224
|
count?: number;
|
|
177
225
|
startIndex?: number;
|
|
178
226
|
outputFormat?: string;
|
|
227
|
+
namespace?: {
|
|
228
|
+
readonly prefix: string;
|
|
229
|
+
readonly uri: string;
|
|
230
|
+
};
|
|
179
231
|
}): string;
|
|
180
232
|
}
|
|
181
233
|
interface HonuaWfsStoredQueryOptions {
|
package/core/wfs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wfs.d.ts","sourceRoot":"","sources":["../../../src/core/wfs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,
|
|
1
|
+
{"version":3,"file":"wfs.d.ts","sourceRoot":"","sources":["../../../src/core/wfs.ts"],"names":[],"mappings":"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"}
|
package/core/wfs.js
CHANGED
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
*
|
|
19
19
|
* @module
|
|
20
20
|
*/
|
|
21
|
-
import { HonuaHttpError, HonuaWfsExceptionError } from "./errors.js";
|
|
22
|
-
import { parseListStoredQueriesResponse, parseWfsCapabilities, parseWfsExceptionReport, parseWfsTransactionResponse, } from "./wfs-capabilities.js";
|
|
21
|
+
import { HonuaAbortError, HonuaHttpError, HonuaWfsExceptionError } from "./errors.js";
|
|
22
|
+
import { parseListStoredQueriesResponse, parseWfsCapabilities, parseWfsDescribeFeatureTypeGeometry, parseWfsExceptionReport, parseWfsTransactionResponse, } from "./wfs-capabilities.js";
|
|
23
|
+
import { HonuaWfsProtocolError } from "./wfs-protocol-error.js";
|
|
23
24
|
const DEFAULT_VERSION = "2.0.0";
|
|
24
25
|
const SERVICE_PARAM = "WFS";
|
|
26
|
+
const WFS_METADATA_MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
27
|
+
const WFS_FEATURE_MAX_RESPONSE_BYTES = 32 * 1024 * 1024;
|
|
25
28
|
/** Output formats (lower-cased) the canonical adapter treats as JSON. */
|
|
26
29
|
const JSON_OUTPUT_FORMATS = new Set([
|
|
27
30
|
"application/json",
|
|
@@ -42,6 +45,7 @@ const GML_OUTPUT_FORMATS = new Set([
|
|
|
42
45
|
"text/xml; subtype=gml/3.2.1",
|
|
43
46
|
"text/xml;subtype=gml/3.2.1",
|
|
44
47
|
]);
|
|
48
|
+
const CAPABILITIES_STATES = new WeakMap();
|
|
45
49
|
/**
|
|
46
50
|
* Root WFS handle. Holds the capabilities cache and exposes feature-type /
|
|
47
51
|
* stored-query factories.
|
|
@@ -52,33 +56,129 @@ export class HonuaWfs {
|
|
|
52
56
|
version;
|
|
53
57
|
/** Counter exposed for tests / diagnostics: how many times capabilities was fetched. */
|
|
54
58
|
capabilitiesFetches = 0;
|
|
55
|
-
capabilitiesPromise;
|
|
56
59
|
rawCapabilitiesXml;
|
|
57
60
|
resolvedSnapshot;
|
|
61
|
+
/** Resolved geometry property per feature type; shares the metadata cache lifecycle. */
|
|
62
|
+
geometryPropertyNames = new Map();
|
|
58
63
|
constructor(options) {
|
|
59
64
|
this.client = options.client;
|
|
60
65
|
this.endpointUrl = options.endpointUrl;
|
|
61
66
|
this.version = options.version ?? DEFAULT_VERSION;
|
|
67
|
+
CAPABILITIES_STATES.set(this, { generation: 0 });
|
|
62
68
|
}
|
|
63
69
|
/**
|
|
64
70
|
* Fetch and cache the GetCapabilities document. Subsequent calls reuse the
|
|
65
71
|
* parsed snapshot. Throws `HonuaWfsExceptionError` on `<ows:ExceptionReport>`.
|
|
66
72
|
*/
|
|
67
|
-
capabilities(options) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
async capabilities(options) {
|
|
74
|
+
if (options?.signal?.aborted)
|
|
75
|
+
throw new HonuaAbortError();
|
|
76
|
+
if (this.resolvedSnapshot)
|
|
77
|
+
return this.resolvedSnapshot;
|
|
78
|
+
const state = capabilitiesState(this);
|
|
79
|
+
const generation = state.generation;
|
|
80
|
+
let flight = state.flight;
|
|
81
|
+
if (!flight || flight.generation !== generation) {
|
|
82
|
+
const identity = {};
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const promise = this.fetchCapabilities({ signal: controller.signal }).then((fetched) => {
|
|
85
|
+
// A refresh advances the generation. An older response may still
|
|
86
|
+
// settle after a transport ignores abort, but it must never repopulate
|
|
87
|
+
// the cache or become evidence for the new generation.
|
|
88
|
+
if (state.generation === generation && state.flight?.identity === identity) {
|
|
89
|
+
this.rawCapabilitiesXml = fetched.xml;
|
|
90
|
+
this.resolvedSnapshot = fetched.snapshot;
|
|
91
|
+
}
|
|
92
|
+
return fetched.snapshot;
|
|
93
|
+
});
|
|
94
|
+
const nextFlight = {
|
|
95
|
+
generation,
|
|
96
|
+
identity,
|
|
97
|
+
controller,
|
|
98
|
+
promise,
|
|
99
|
+
subscribers: 0,
|
|
100
|
+
settled: false,
|
|
101
|
+
};
|
|
102
|
+
flight = nextFlight;
|
|
103
|
+
state.flight = nextFlight;
|
|
104
|
+
void promise.then(() => {
|
|
105
|
+
nextFlight.settled = true;
|
|
106
|
+
if (state.flight === nextFlight)
|
|
107
|
+
state.flight = undefined;
|
|
108
|
+
}, () => {
|
|
109
|
+
nextFlight.settled = true;
|
|
110
|
+
if (state.flight === nextFlight)
|
|
111
|
+
state.flight = undefined;
|
|
73
112
|
});
|
|
74
113
|
}
|
|
75
|
-
return
|
|
114
|
+
return subscribeCapabilitiesFlight(state, flight, options?.signal);
|
|
76
115
|
}
|
|
77
116
|
/** Discard the cached capabilities snapshot so the next call re-fetches. */
|
|
78
117
|
refresh() {
|
|
79
|
-
|
|
118
|
+
const state = capabilitiesState(this);
|
|
119
|
+
state.generation += 1;
|
|
120
|
+
const staleFlight = state.flight;
|
|
121
|
+
state.flight = undefined;
|
|
80
122
|
this.rawCapabilitiesXml = undefined;
|
|
81
123
|
this.resolvedSnapshot = undefined;
|
|
124
|
+
this.geometryPropertyNames.clear();
|
|
125
|
+
if (staleFlight && !staleFlight.settled)
|
|
126
|
+
staleFlight.controller.abort();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fetch the `DescribeFeatureType` XSD for one feature type. Returned raw so
|
|
130
|
+
* `Source.protocol("wfs")` callers can read schema detail the canonical
|
|
131
|
+
* surface does not model.
|
|
132
|
+
*/
|
|
133
|
+
async describeFeatureType(typeName, options) {
|
|
134
|
+
const params = new URLSearchParams({
|
|
135
|
+
service: SERVICE_PARAM,
|
|
136
|
+
version: this.version,
|
|
137
|
+
request: "DescribeFeatureType",
|
|
138
|
+
typeNames: typeName,
|
|
139
|
+
});
|
|
140
|
+
const requestOptions = {
|
|
141
|
+
accept: "application/xml, text/xml",
|
|
142
|
+
maxResponseBytes: WFS_METADATA_MAX_RESPONSE_BYTES,
|
|
143
|
+
};
|
|
144
|
+
if (options?.signal)
|
|
145
|
+
requestOptions.signal = options.signal;
|
|
146
|
+
const { text, contentType } = await this.requestText("GET", appendQuery(this.operationUrl("DescribeFeatureType", "GET"), params), requestOptions);
|
|
147
|
+
return { text, contentType };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolve the geometry property name of one feature type from its
|
|
151
|
+
* `DescribeFeatureType` schema, caching the result alongside the
|
|
152
|
+
* capabilities snapshot. Fails closed with
|
|
153
|
+
* `HonuaWfsProtocolError("unresolved-geometry-property")` rather than
|
|
154
|
+
* assuming a vendor default: `the_geom` is only the PostGIS-via-GeoServer
|
|
155
|
+
* convention, MapServer serves `msGeometry`, and other servers use
|
|
156
|
+
* per-schema names, so guessing silently matches nothing.
|
|
157
|
+
*
|
|
158
|
+
* Feature types that declare several geometry properties resolve to the
|
|
159
|
+
* first declared one (the server's default geometry); pin a different one
|
|
160
|
+
* with `locator.geometryName`.
|
|
161
|
+
*/
|
|
162
|
+
async geometryPropertyName(typeName, options) {
|
|
163
|
+
const cached = this.geometryPropertyNames.get(typeName);
|
|
164
|
+
if (cached !== undefined)
|
|
165
|
+
return cached;
|
|
166
|
+
let candidates;
|
|
167
|
+
try {
|
|
168
|
+
const { text } = await this.describeFeatureType(typeName, options);
|
|
169
|
+
candidates = parseWfsDescribeFeatureTypeGeometry(text, typeName);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (error instanceof HonuaAbortError)
|
|
173
|
+
throw error;
|
|
174
|
+
throw new HonuaWfsProtocolError("unresolved-geometry-property", `WFS DescribeFeatureType could not resolve the geometry property of feature type "${typeName}"; set locator.geometryName to name it explicitly`, { cause: error });
|
|
175
|
+
}
|
|
176
|
+
const resolved = candidates[0];
|
|
177
|
+
if (resolved === undefined) {
|
|
178
|
+
throw new HonuaWfsProtocolError("unresolved-geometry-property", `WFS DescribeFeatureType declares no geometry property for feature type "${typeName}"; set locator.geometryName to name it explicitly`);
|
|
179
|
+
}
|
|
180
|
+
this.geometryPropertyNames.set(typeName, resolved);
|
|
181
|
+
return resolved;
|
|
82
182
|
}
|
|
83
183
|
/**
|
|
84
184
|
* Resolve the concrete request URL for a WFS operation, honouring the
|
|
@@ -115,7 +215,10 @@ export class HonuaWfs {
|
|
|
115
215
|
version: this.version,
|
|
116
216
|
request: "ListStoredQueries",
|
|
117
217
|
});
|
|
118
|
-
const requestOptions = {
|
|
218
|
+
const requestOptions = {
|
|
219
|
+
accept: "application/xml, text/xml",
|
|
220
|
+
maxResponseBytes: WFS_METADATA_MAX_RESPONSE_BYTES,
|
|
221
|
+
};
|
|
119
222
|
if (options?.signal)
|
|
120
223
|
requestOptions.signal = options.signal;
|
|
121
224
|
const { text } = await this.requestText("GET", appendQuery(this.endpointUrl, params), requestOptions);
|
|
@@ -129,6 +232,7 @@ export class HonuaWfs {
|
|
|
129
232
|
try {
|
|
130
233
|
const requestOptions = {
|
|
131
234
|
accept: options.accept,
|
|
235
|
+
maxResponseBytes: options.maxResponseBytes ?? WFS_METADATA_MAX_RESPONSE_BYTES,
|
|
132
236
|
};
|
|
133
237
|
if (options.contentType !== undefined)
|
|
134
238
|
requestOptions.contentType = options.contentType;
|
|
@@ -146,11 +250,11 @@ export class HonuaWfs {
|
|
|
146
250
|
negotiateOutputFormat(snapshot) {
|
|
147
251
|
const formats = snapshot.outputFormatsByOp.get("GetFeature") ?? [];
|
|
148
252
|
for (const format of formats) {
|
|
149
|
-
if (JSON_OUTPUT_FORMATS.has(format))
|
|
253
|
+
if (JSON_OUTPUT_FORMATS.has(format.toLowerCase()))
|
|
150
254
|
return { kind: "json", format };
|
|
151
255
|
}
|
|
152
256
|
for (const format of formats) {
|
|
153
|
-
if (GML_OUTPUT_FORMATS.has(format))
|
|
257
|
+
if (GML_OUTPUT_FORMATS.has(format.toLowerCase()))
|
|
154
258
|
return { kind: "gml", format };
|
|
155
259
|
}
|
|
156
260
|
if (formats.length === 0) {
|
|
@@ -171,25 +275,116 @@ export class HonuaWfs {
|
|
|
171
275
|
version: this.version,
|
|
172
276
|
request: "GetCapabilities",
|
|
173
277
|
});
|
|
174
|
-
const requestOptions = {
|
|
278
|
+
const requestOptions = {
|
|
279
|
+
accept: "application/xml, text/xml",
|
|
280
|
+
maxResponseBytes: WFS_METADATA_MAX_RESPONSE_BYTES,
|
|
281
|
+
};
|
|
175
282
|
if (options?.signal)
|
|
176
283
|
requestOptions.signal = options.signal;
|
|
177
284
|
const { text } = await this.requestText("GET", appendQuery(this.endpointUrl, params), requestOptions);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
canonicalizeOperationUrls(snapshot, this.endpointUrl, this.client.serverBaseUrl);
|
|
181
|
-
this.resolvedSnapshot = snapshot;
|
|
182
|
-
return snapshot;
|
|
285
|
+
const snapshot = canonicalizeOperationUrls(parseWfsCapabilities(text), this.endpointUrl, this.client.serverBaseUrl);
|
|
286
|
+
return { snapshot, xml: text };
|
|
183
287
|
}
|
|
184
288
|
}
|
|
289
|
+
function capabilitiesState(root) {
|
|
290
|
+
const state = CAPABILITIES_STATES.get(root);
|
|
291
|
+
if (!state)
|
|
292
|
+
throw new TypeError("WFS capabilities state is unavailable");
|
|
293
|
+
return state;
|
|
294
|
+
}
|
|
295
|
+
function subscribeCapabilitiesFlight(state, flight, signal) {
|
|
296
|
+
flight.subscribers += 1;
|
|
297
|
+
return new Promise((resolve, reject) => {
|
|
298
|
+
let finished = false;
|
|
299
|
+
const finish = () => {
|
|
300
|
+
if (finished)
|
|
301
|
+
return false;
|
|
302
|
+
finished = true;
|
|
303
|
+
signal?.removeEventListener("abort", onCallerAbort);
|
|
304
|
+
flight.controller.signal.removeEventListener("abort", onGenerationAbort);
|
|
305
|
+
flight.subscribers -= 1;
|
|
306
|
+
return true;
|
|
307
|
+
};
|
|
308
|
+
const abortOrphanedFlight = () => {
|
|
309
|
+
if (flight.settled || flight.subscribers !== 0 || flight.controller.signal.aborted)
|
|
310
|
+
return;
|
|
311
|
+
if (state.flight === flight)
|
|
312
|
+
state.flight = undefined;
|
|
313
|
+
flight.controller.abort();
|
|
314
|
+
};
|
|
315
|
+
const onCallerAbort = () => {
|
|
316
|
+
if (!finish())
|
|
317
|
+
return;
|
|
318
|
+
reject(new HonuaAbortError());
|
|
319
|
+
abortOrphanedFlight();
|
|
320
|
+
};
|
|
321
|
+
const onGenerationAbort = () => {
|
|
322
|
+
if (!finish())
|
|
323
|
+
return;
|
|
324
|
+
reject(new HonuaAbortError("WFS capabilities discovery was invalidated"));
|
|
325
|
+
};
|
|
326
|
+
signal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
327
|
+
flight.controller.signal.addEventListener("abort", onGenerationAbort, { once: true });
|
|
328
|
+
if (signal?.aborted)
|
|
329
|
+
onCallerAbort();
|
|
330
|
+
else if (flight.controller.signal.aborted)
|
|
331
|
+
onGenerationAbort();
|
|
332
|
+
flight.promise.then((snapshot) => {
|
|
333
|
+
if (!finish())
|
|
334
|
+
return;
|
|
335
|
+
resolve(snapshot);
|
|
336
|
+
}, (error) => {
|
|
337
|
+
if (!finish())
|
|
338
|
+
return;
|
|
339
|
+
reject(error);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
}
|
|
185
343
|
function canonicalizeOperationUrls(snapshot, endpointUrl, clientBaseUrl) {
|
|
186
344
|
const capabilitiesEndpoint = new URL(endpointUrl, clientBaseUrl);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
operation.
|
|
192
|
-
|
|
345
|
+
const operations = new Map([...snapshot.operations].map(([name, operation]) => [
|
|
346
|
+
name,
|
|
347
|
+
Object.freeze({
|
|
348
|
+
...operation,
|
|
349
|
+
...(operation.getUrl ? { getUrl: new URL(operation.getUrl, capabilitiesEndpoint).toString() } : {}),
|
|
350
|
+
...(operation.postUrl ? { postUrl: new URL(operation.postUrl, capabilitiesEndpoint).toString() } : {}),
|
|
351
|
+
}),
|
|
352
|
+
]));
|
|
353
|
+
return Object.freeze({
|
|
354
|
+
...snapshot,
|
|
355
|
+
operations: immutableWfsMap(operations),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function immutableWfsMap(source) {
|
|
359
|
+
const owned = new Map(source);
|
|
360
|
+
const view = {
|
|
361
|
+
get size() {
|
|
362
|
+
return owned.size;
|
|
363
|
+
},
|
|
364
|
+
get(key) {
|
|
365
|
+
return owned.get(key);
|
|
366
|
+
},
|
|
367
|
+
has(key) {
|
|
368
|
+
return owned.has(key);
|
|
369
|
+
},
|
|
370
|
+
forEach(callbackfn, thisArg) {
|
|
371
|
+
for (const [key, value] of owned)
|
|
372
|
+
callbackfn.call(thisArg, value, key, view);
|
|
373
|
+
},
|
|
374
|
+
entries() {
|
|
375
|
+
return owned.entries();
|
|
376
|
+
},
|
|
377
|
+
keys() {
|
|
378
|
+
return owned.keys();
|
|
379
|
+
},
|
|
380
|
+
values() {
|
|
381
|
+
return owned.values();
|
|
382
|
+
},
|
|
383
|
+
[Symbol.iterator]() {
|
|
384
|
+
return owned[Symbol.iterator]();
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
return Object.freeze(view);
|
|
193
388
|
}
|
|
194
389
|
/**
|
|
195
390
|
* Per-feature-type WFS surface. Implements the wire methods that the
|
|
@@ -207,6 +402,18 @@ export class HonuaWfsFeatureType {
|
|
|
207
402
|
capabilities(options) {
|
|
208
403
|
return this.root.capabilities(options);
|
|
209
404
|
}
|
|
405
|
+
/** Raw `DescribeFeatureType` XSD for the bound type name. */
|
|
406
|
+
describeFeatureType(options) {
|
|
407
|
+
return this.root.describeFeatureType(this.typeName, options);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Geometry property name of the bound feature type, resolved from
|
|
411
|
+
* `DescribeFeatureType` and cached on the root. Fails closed when the schema
|
|
412
|
+
* does not name one — see {@link HonuaWfs.geometryPropertyName}.
|
|
413
|
+
*/
|
|
414
|
+
geometryPropertyName(options) {
|
|
415
|
+
return this.root.geometryPropertyName(this.typeName, options);
|
|
416
|
+
}
|
|
210
417
|
/**
|
|
211
418
|
* Issue a GetFeature request. Returns parsed JSON when the negotiated
|
|
212
419
|
* output format is JSON; otherwise returns the raw body as a string for
|
|
@@ -215,7 +422,10 @@ export class HonuaWfsFeatureType {
|
|
|
215
422
|
async getFeature(params) {
|
|
216
423
|
const method = params.method ?? "GET";
|
|
217
424
|
const accept = params.outputFormat ?? "application/geo+json, application/json;q=0.9, application/xml;q=0.5";
|
|
218
|
-
const requestOptions = {
|
|
425
|
+
const requestOptions = {
|
|
426
|
+
accept,
|
|
427
|
+
maxResponseBytes: WFS_FEATURE_MAX_RESPONSE_BYTES,
|
|
428
|
+
};
|
|
219
429
|
if (params.signal)
|
|
220
430
|
requestOptions.signal = params.signal;
|
|
221
431
|
let response;
|
|
@@ -231,6 +441,9 @@ export class HonuaWfsFeatureType {
|
|
|
231
441
|
request: "GetFeature",
|
|
232
442
|
typeNames: this.typeName,
|
|
233
443
|
});
|
|
444
|
+
if (params.namespace !== undefined) {
|
|
445
|
+
search.set("NAMESPACES", `xmlns(${params.namespace.prefix},${params.namespace.uri})`);
|
|
446
|
+
}
|
|
234
447
|
if (params.filter !== undefined)
|
|
235
448
|
search.set("filter", params.filter);
|
|
236
449
|
if (params.bbox !== undefined)
|
|
@@ -279,7 +492,10 @@ export class HonuaWfsFeatureType {
|
|
|
279
492
|
search.set("count", String(params.count));
|
|
280
493
|
if (typeof params.startIndex === "number")
|
|
281
494
|
search.set("startIndex", String(params.startIndex));
|
|
282
|
-
const requestOptions = {
|
|
495
|
+
const requestOptions = {
|
|
496
|
+
accept: "application/xml, text/xml",
|
|
497
|
+
maxResponseBytes: WFS_FEATURE_MAX_RESPONSE_BYTES,
|
|
498
|
+
};
|
|
283
499
|
if (params.signal)
|
|
284
500
|
requestOptions.signal = params.signal;
|
|
285
501
|
const { text, contentType } = await this.root.requestText("GET", appendQuery(this.root.endpointUrl, search), requestOptions);
|
|
@@ -318,6 +534,9 @@ export class HonuaWfsFeatureType {
|
|
|
318
534
|
search.set("startIndex", String(params.startIndex));
|
|
319
535
|
if (params.outputFormat !== undefined)
|
|
320
536
|
search.set("outputFormat", params.outputFormat);
|
|
537
|
+
if (params.namespace !== undefined) {
|
|
538
|
+
search.set("NAMESPACES", `xmlns(${params.namespace.prefix},${params.namespace.uri})`);
|
|
539
|
+
}
|
|
321
540
|
return appendQuery(this.root.endpointUrl, search);
|
|
322
541
|
}
|
|
323
542
|
}
|
|
@@ -370,7 +589,10 @@ export class HonuaWfsStoredQuery {
|
|
|
370
589
|
}
|
|
371
590
|
}
|
|
372
591
|
const accept = params.outputFormat ?? "application/geo+json, application/json;q=0.9, application/xml;q=0.5";
|
|
373
|
-
const requestOptions = {
|
|
592
|
+
const requestOptions = {
|
|
593
|
+
accept,
|
|
594
|
+
maxResponseBytes: WFS_FEATURE_MAX_RESPONSE_BYTES,
|
|
595
|
+
};
|
|
374
596
|
if (params.signal)
|
|
375
597
|
requestOptions.signal = params.signal;
|
|
376
598
|
const { text, contentType } = await this.root.requestText("GET", appendQuery(this.root.operationUrl("GetFeature", "GET"), search), requestOptions);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capabilities-driven WMS 1.3 `GetFeatureInfo` execution.
|
|
3
|
+
*
|
|
4
|
+
* The first-party path in `wms.ts` addresses Honua Server's
|
|
5
|
+
* `/rest/services/{id}/MapServer/WMS` alias by service id. This module
|
|
6
|
+
* generalizes the same wire request so it can also be issued against the
|
|
7
|
+
* DCP operation URL a third-party `GetCapabilities` advertises, reusing the
|
|
8
|
+
* shared KVP serializer (and therefore the shared WMS 1.3 axis-order rule)
|
|
9
|
+
* rather than restating it.
|
|
10
|
+
*
|
|
11
|
+
* Everything here is fail-closed. A format the canonical `Result` contract
|
|
12
|
+
* cannot represent is never selected, a CRS whose WMS 1.3 axis order the SDK
|
|
13
|
+
* cannot prove is never sent, and a response body that does not decode into
|
|
14
|
+
* features raises `HonuaCapabilityNotSupportedError` instead of degrading into
|
|
15
|
+
* a silently empty result.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import type { HonuaProtocolTransport } from "./protocol-transport.js";
|
|
20
|
+
import type { HonuaTypedFeature } from "./types.js";
|
|
21
|
+
import type { WmsFeatureInfoRequest } from "./wms-types.js";
|
|
22
|
+
/**
|
|
23
|
+
* Response ceiling for a point `GetFeatureInfo`. The request renders a 1×1
|
|
24
|
+
* image, so a conformant answer is small; the bound keeps a hostile or
|
|
25
|
+
* misconfigured server from turning identify-on-click into an unbounded read.
|
|
26
|
+
*/
|
|
27
|
+
export declare const WMS_FEATURE_INFO_MAX_RESPONSE_BYTES: number;
|
|
28
|
+
/** Negotiated `INFO_FORMAT` plus the decoder family it selects. */
|
|
29
|
+
export interface WmsFeatureInfoFormatChoice {
|
|
30
|
+
readonly kind: "json" | "gml";
|
|
31
|
+
/** Exact spelling the service advertised, sent verbatim on the wire. */
|
|
32
|
+
readonly format: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Classify one advertised `INFO_FORMAT`. Returns `undefined` when the format
|
|
36
|
+
* carries no structure the canonical contract can project.
|
|
37
|
+
*/
|
|
38
|
+
export declare function classifyWmsFeatureInfoFormat(format: string): "json" | "gml" | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Pick the `INFO_FORMAT` the canonical adapter should request from the formats
|
|
41
|
+
* a service advertises for `GetFeatureInfo`. JSON families win over GML; within
|
|
42
|
+
* a family the SDK's preference order decides, not the server's ordering, so
|
|
43
|
+
* the selection is deterministic across deployments.
|
|
44
|
+
*/
|
|
45
|
+
export declare function selectWmsFeatureInfoFormat(advertised: readonly string[]): WmsFeatureInfoFormatChoice | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Filter a layer's advertised CRS list down to the identifiers a point
|
|
48
|
+
* `GetFeatureInfo` may use, preserving the advertised spelling and order.
|
|
49
|
+
*/
|
|
50
|
+
export declare function reviewedWmsQueryCrs(advertised: readonly string[]): readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the CRS a canonical query should put on the wire.
|
|
53
|
+
*
|
|
54
|
+
* The requested code comes from the spatial filter geometry (defaulting to
|
|
55
|
+
* `CRS:84`). An exact advertised spelling always wins. `CRS:84` and `EPSG:4326`
|
|
56
|
+
* are interchangeable *inputs* — both describe the same canonical `(x, y)` =
|
|
57
|
+
* `(lon, lat)` point and differ only in the wire axis order, which the shared
|
|
58
|
+
* serializer applies for whichever spelling is chosen — so a request in one is
|
|
59
|
+
* satisfied by the other when only that one is advertised. Anything else
|
|
60
|
+
* returns `undefined` so the caller can fail closed.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveWmsQueryCrs(reviewed: readonly string[], requested: string): string | undefined;
|
|
63
|
+
/** Reviewed, same-origin `GetFeatureInfo` operation binding. */
|
|
64
|
+
export interface WmsFeatureInfoBinding {
|
|
65
|
+
/** Absolute operation URL advertised by `GetCapabilities`. */
|
|
66
|
+
readonly url: string;
|
|
67
|
+
/** Negotiated `INFO_FORMAT`. */
|
|
68
|
+
readonly format: string;
|
|
69
|
+
}
|
|
70
|
+
export interface ExecuteWmsFeatureInfoOptions {
|
|
71
|
+
readonly binding: WmsFeatureInfoBinding;
|
|
72
|
+
readonly request: WmsFeatureInfoRequest;
|
|
73
|
+
/** Source id used for capability errors raised on an unprojectable response. */
|
|
74
|
+
readonly sourceId: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Issue a `GetFeatureInfo` against the capabilities-advertised operation URL
|
|
78
|
+
* and project the response into canonical typed features.
|
|
79
|
+
*
|
|
80
|
+
* Vendor query state already present on the advertised URL (tenant selectors,
|
|
81
|
+
* map identifiers) is preserved; the WMS KVP names are overwritten so a
|
|
82
|
+
* capabilities document cannot pin a stale `BBOX` or `INFO_FORMAT`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function executeWmsFeatureInfo<T = Record<string, unknown>>(transport: Pick<HonuaProtocolTransport, "requestText">, options: ExecuteWmsFeatureInfoOptions): Promise<ReadonlyArray<HonuaTypedFeature<T>>>;
|
|
85
|
+
/**
|
|
86
|
+
* Project a decoded `GetFeatureInfo` body into canonical typed features.
|
|
87
|
+
* `kind` is the negotiated decoder family; the observed `contentType` only
|
|
88
|
+
* narrows a JSON negotiation that the server answered with XML (a common
|
|
89
|
+
* shape for OGC `ServiceExceptionReport` bodies returned with HTTP 200).
|
|
90
|
+
*/
|
|
91
|
+
export declare function decodeWmsFeatureInfoBody<T = Record<string, unknown>>(text: string, contentType: string, kind: "json" | "gml", sourceId: string): ReadonlyArray<HonuaTypedFeature<T>>;
|
|
92
|
+
//# sourceMappingURL=wms-feature-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wms-feature-info.d.ts","sourceRoot":"","sources":["../../../src/core/wms-feature-info.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAG5D;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,QAAc,CAAC;AAoC/D,mEAAmE;AACnE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAMD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAKvF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,0BAA0B,GAAG,SAAS,CAWhH;AAkBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CASpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYrG;AAED,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,SAAS,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAC,EACtD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAoB9C;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GAAG,KAAK,EACpB,QAAQ,EAAE,MAAM,GACf,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAarC"}
|