@honua/sdk-esri-compat 0.0.6-alpha.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/README.md +5 -0
- package/contract/edit-session.d.ts +203 -0
- package/contract/edit-session.d.ts.map +1 -0
- package/contract/edit-session.js +717 -0
- package/contract/index.d.ts +20 -0
- package/contract/index.d.ts.map +1 -0
- package/contract/index.js +15 -0
- package/contract/jobs.d.ts +115 -0
- package/contract/jobs.d.ts.map +1 -0
- package/contract/jobs.js +22 -0
- package/contract/source.d.ts +138 -0
- package/contract/source.d.ts.map +1 -0
- package/contract/source.js +3364 -0
- package/contract/spatial-aggregation.d.ts +312 -0
- package/contract/spatial-aggregation.d.ts.map +1 -0
- package/contract/spatial-aggregation.js +196 -0
- package/contract/types.d.ts +542 -0
- package/contract/types.d.ts.map +1 -0
- package/contract/types.js +171 -0
- package/core/batch.d.ts +37 -0
- package/core/batch.d.ts.map +1 -0
- package/core/batch.js +78 -0
- package/core/cache-state.d.ts +76 -0
- package/core/cache-state.d.ts.map +1 -0
- package/core/cache-state.js +84 -0
- package/core/client.d.ts +289 -0
- package/core/client.d.ts.map +1 -0
- package/core/client.js +2625 -0
- package/core/errors.d.ts +68 -0
- package/core/errors.d.ts.map +1 -0
- package/core/errors.js +116 -0
- package/core/grpc-adapter.d.ts +23 -0
- package/core/grpc-adapter.d.ts.map +1 -0
- package/core/grpc-adapter.js +704 -0
- package/core/odata.d.ts +347 -0
- package/core/odata.d.ts.map +1 -0
- package/core/odata.js +837 -0
- package/core/ogc-conformance.d.ts +35 -0
- package/core/ogc-conformance.d.ts.map +1 -0
- package/core/ogc-conformance.js +121 -0
- package/core/ogc-maps.d.ts +45 -0
- package/core/ogc-maps.d.ts.map +1 -0
- package/core/ogc-maps.js +53 -0
- package/core/ogc-processes.d.ts +92 -0
- package/core/ogc-processes.d.ts.map +1 -0
- package/core/ogc-processes.js +325 -0
- package/core/ogc-tiles.d.ts +55 -0
- package/core/ogc-tiles.d.ts.map +1 -0
- package/core/ogc-tiles.js +81 -0
- package/core/pbf-decoder.d.ts +28 -0
- package/core/pbf-decoder.d.ts.map +1 -0
- package/core/pbf-decoder.js +627 -0
- package/core/query-builder.d.ts +261 -0
- package/core/query-builder.d.ts.map +1 -0
- package/core/query-builder.js +538 -0
- package/core/spatial-filter.d.ts +93 -0
- package/core/spatial-filter.d.ts.map +1 -0
- package/core/spatial-filter.js +153 -0
- package/core/stac.d.ts +43 -0
- package/core/stac.d.ts.map +1 -0
- package/core/stac.js +116 -0
- package/core/surfaces.d.ts +464 -0
- package/core/surfaces.d.ts.map +1 -0
- package/core/surfaces.js +1322 -0
- package/core/types.d.ts +1238 -0
- package/core/types.d.ts.map +1 -0
- package/core/types.js +13 -0
- package/core/wfs-capabilities.d.ts +143 -0
- package/core/wfs-capabilities.d.ts.map +1 -0
- package/core/wfs-capabilities.js +478 -0
- package/core/wfs-filter.d.ts +118 -0
- package/core/wfs-filter.d.ts.map +1 -0
- package/core/wfs-filter.js +586 -0
- package/core/wfs.d.ts +219 -0
- package/core/wfs.d.ts.map +1 -0
- package/core/wfs.js +406 -0
- package/core/wms-capabilities.d.ts +110 -0
- package/core/wms-capabilities.d.ts.map +1 -0
- package/core/wms-capabilities.js +566 -0
- package/core/wms-types.d.ts +128 -0
- package/core/wms-types.d.ts.map +1 -0
- package/core/wms-types.js +32 -0
- package/core/wms.d.ts +108 -0
- package/core/wms.d.ts.map +1 -0
- package/core/wms.js +182 -0
- package/core/wmts-capabilities.d.ts +82 -0
- package/core/wmts-capabilities.d.ts.map +1 -0
- package/core/wmts-capabilities.js +409 -0
- package/core/wmts.d.ts +80 -0
- package/core/wmts.d.ts.map +1 -0
- package/core/wmts.js +173 -0
- package/esri-compat/basemap-gallery.d.ts +38 -0
- package/esri-compat/basemap-gallery.d.ts.map +1 -0
- package/esri-compat/basemap-gallery.js +159 -0
- package/esri-compat/basemap-layer-list.d.ts +35 -0
- package/esri-compat/basemap-layer-list.d.ts.map +1 -0
- package/esri-compat/basemap-layer-list.js +139 -0
- package/esri-compat/basemap.d.ts +32 -0
- package/esri-compat/basemap.d.ts.map +1 -0
- package/esri-compat/basemap.js +84 -0
- package/esri-compat/bookmarks.d.ts +36 -0
- package/esri-compat/bookmarks.d.ts.map +1 -0
- package/esri-compat/bookmarks.js +108 -0
- package/esri-compat/class-breaks-renderer.d.ts +50 -0
- package/esri-compat/class-breaks-renderer.d.ts.map +1 -0
- package/esri-compat/class-breaks-renderer.js +164 -0
- package/esri-compat/color.d.ts +22 -0
- package/esri-compat/color.d.ts.map +1 -0
- package/esri-compat/color.js +106 -0
- package/esri-compat/controls.d.ts +174 -0
- package/esri-compat/controls.d.ts.map +1 -0
- package/esri-compat/controls.js +479 -0
- package/esri-compat/coordinate-conversion.d.ts +41 -0
- package/esri-compat/coordinate-conversion.d.ts.map +1 -0
- package/esri-compat/coordinate-conversion.js +125 -0
- package/esri-compat/directions.d.ts +45 -0
- package/esri-compat/directions.d.ts.map +1 -0
- package/esri-compat/directions.js +123 -0
- package/esri-compat/editor.d.ts +47 -0
- package/esri-compat/editor.d.ts.map +1 -0
- package/esri-compat/editor.js +170 -0
- package/esri-compat/esri-config.d.ts +16 -0
- package/esri-compat/esri-config.d.ts.map +1 -0
- package/esri-compat/esri-config.js +23 -0
- package/esri-compat/esri-request.d.ts +17 -0
- package/esri-compat/esri-request.d.ts.map +1 -0
- package/esri-compat/esri-request.js +66 -0
- package/esri-compat/event-bus.d.ts +106 -0
- package/esri-compat/event-bus.d.ts.map +1 -0
- package/esri-compat/event-bus.js +90 -0
- package/esri-compat/expand.d.ts +36 -0
- package/esri-compat/expand.d.ts.map +1 -0
- package/esri-compat/expand.js +97 -0
- package/esri-compat/extent.d.ts +43 -0
- package/esri-compat/extent.d.ts.map +1 -0
- package/esri-compat/extent.js +140 -0
- package/esri-compat/feature-form.d.ts +64 -0
- package/esri-compat/feature-form.d.ts.map +1 -0
- package/esri-compat/feature-form.js +137 -0
- package/esri-compat/feature-layer.d.ts +173 -0
- package/esri-compat/feature-layer.d.ts.map +1 -0
- package/esri-compat/feature-layer.js +655 -0
- package/esri-compat/feature-set.d.ts +32 -0
- package/esri-compat/feature-set.d.ts.map +1 -0
- package/esri-compat/feature-set.js +80 -0
- package/esri-compat/feature-table.d.ts +141 -0
- package/esri-compat/feature-table.d.ts.map +1 -0
- package/esri-compat/feature-table.js +500 -0
- package/esri-compat/feature-templates.d.ts +41 -0
- package/esri-compat/feature-templates.d.ts.map +1 -0
- package/esri-compat/feature-templates.js +97 -0
- package/esri-compat/feature.d.ts +33 -0
- package/esri-compat/feature.d.ts.map +1 -0
- package/esri-compat/feature.js +83 -0
- package/esri-compat/graphic.d.ts +46 -0
- package/esri-compat/graphic.d.ts.map +1 -0
- package/esri-compat/graphic.js +103 -0
- package/esri-compat/graphics-layer.d.ts +49 -0
- package/esri-compat/graphics-layer.d.ts.map +1 -0
- package/esri-compat/graphics-layer.js +185 -0
- package/esri-compat/group-layer.d.ts +48 -0
- package/esri-compat/group-layer.d.ts.map +1 -0
- package/esri-compat/group-layer.js +212 -0
- package/esri-compat/identify.d.ts +71 -0
- package/esri-compat/identify.d.ts.map +1 -0
- package/esri-compat/identify.js +299 -0
- package/esri-compat/identity-manager.d.ts +31 -0
- package/esri-compat/identity-manager.d.ts.map +1 -0
- package/esri-compat/identity-manager.js +115 -0
- package/esri-compat/label-class.d.ts +31 -0
- package/esri-compat/label-class.d.ts.map +1 -0
- package/esri-compat/label-class.js +102 -0
- package/esri-compat/layer-list.d.ts +77 -0
- package/esri-compat/layer-list.d.ts.map +1 -0
- package/esri-compat/layer-list.js +342 -0
- package/esri-compat/legend.d.ts +53 -0
- package/esri-compat/legend.d.ts.map +1 -0
- package/esri-compat/legend.js +254 -0
- package/esri-compat/map-image-layer.d.ts +162 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -0
- package/esri-compat/map-image-layer.js +704 -0
- package/esri-compat/map-view.d.ts +315 -0
- package/esri-compat/map-view.d.ts.map +1 -0
- package/esri-compat/map-view.js +1110 -0
- package/esri-compat/map.d.ts +47 -0
- package/esri-compat/map.d.ts.map +1 -0
- package/esri-compat/map.js +209 -0
- package/esri-compat/measurement-2d.d.ts +61 -0
- package/esri-compat/measurement-2d.d.ts.map +1 -0
- package/esri-compat/measurement-2d.js +184 -0
- package/esri-compat/measurement.d.ts +45 -0
- package/esri-compat/measurement.d.ts.map +1 -0
- package/esri-compat/measurement.js +193 -0
- package/esri-compat/oauth-info.d.ts +35 -0
- package/esri-compat/oauth-info.d.ts.map +1 -0
- package/esri-compat/oauth-info.js +115 -0
- package/esri-compat/picture-marker-symbol.d.ts +35 -0
- package/esri-compat/picture-marker-symbol.d.ts.map +1 -0
- package/esri-compat/picture-marker-symbol.js +126 -0
- package/esri-compat/point.d.ts +31 -0
- package/esri-compat/point.d.ts.map +1 -0
- package/esri-compat/point.js +102 -0
- package/esri-compat/polygon.d.ts +31 -0
- package/esri-compat/polygon.d.ts.map +1 -0
- package/esri-compat/polygon.js +107 -0
- package/esri-compat/polyline.d.ts +31 -0
- package/esri-compat/polyline.d.ts.map +1 -0
- package/esri-compat/polyline.js +107 -0
- package/esri-compat/popup-template.d.ts +55 -0
- package/esri-compat/popup-template.d.ts.map +1 -0
- package/esri-compat/popup-template.js +128 -0
- package/esri-compat/popup.d.ts +54 -0
- package/esri-compat/popup.d.ts.map +1 -0
- package/esri-compat/popup.js +312 -0
- package/esri-compat/print.d.ts +47 -0
- package/esri-compat/print.d.ts.map +1 -0
- package/esri-compat/print.js +105 -0
- package/esri-compat/query.d.ts +46 -0
- package/esri-compat/query.d.ts.map +1 -0
- package/esri-compat/query.js +119 -0
- package/esri-compat/reactive-utils.d.ts +23 -0
- package/esri-compat/reactive-utils.d.ts.map +1 -0
- package/esri-compat/reactive-utils.js +178 -0
- package/esri-compat/request.d.ts +41 -0
- package/esri-compat/request.d.ts.map +1 -0
- package/esri-compat/request.js +253 -0
- package/esri-compat/route-layer.d.ts +59 -0
- package/esri-compat/route-layer.d.ts.map +1 -0
- package/esri-compat/route-layer.js +223 -0
- package/esri-compat/route-task.d.ts +88 -0
- package/esri-compat/route-task.d.ts.map +1 -0
- package/esri-compat/route-task.js +225 -0
- package/esri-compat/scene-view.d.ts +41 -0
- package/esri-compat/scene-view.d.ts.map +1 -0
- package/esri-compat/scene-view.js +68 -0
- package/esri-compat/search.d.ts +112 -0
- package/esri-compat/search.d.ts.map +1 -0
- package/esri-compat/search.js +820 -0
- package/esri-compat/simple-fill-symbol.d.ts +27 -0
- package/esri-compat/simple-fill-symbol.d.ts.map +1 -0
- package/esri-compat/simple-fill-symbol.js +85 -0
- package/esri-compat/simple-line-symbol.d.ts +27 -0
- package/esri-compat/simple-line-symbol.d.ts.map +1 -0
- package/esri-compat/simple-line-symbol.js +85 -0
- package/esri-compat/simple-marker-symbol.d.ts +29 -0
- package/esri-compat/simple-marker-symbol.d.ts.map +1 -0
- package/esri-compat/simple-marker-symbol.js +92 -0
- package/esri-compat/simple-renderer.d.ts +29 -0
- package/esri-compat/simple-renderer.d.ts.map +1 -0
- package/esri-compat/simple-renderer.js +92 -0
- package/esri-compat/sketch.d.ts +64 -0
- package/esri-compat/sketch.d.ts.map +1 -0
- package/esri-compat/sketch.js +227 -0
- package/esri-compat/spatial-reference.d.ts +31 -0
- package/esri-compat/spatial-reference.d.ts.map +1 -0
- package/esri-compat/spatial-reference.js +102 -0
- package/esri-compat/swipe.d.ts +34 -0
- package/esri-compat/swipe.d.ts.map +1 -0
- package/esri-compat/swipe.js +93 -0
- package/esri-compat/table-list.d.ts +36 -0
- package/esri-compat/table-list.d.ts.map +1 -0
- package/esri-compat/table-list.js +126 -0
- package/esri-compat/text-symbol.d.ts +37 -0
- package/esri-compat/text-symbol.d.ts.map +1 -0
- package/esri-compat/text-symbol.js +123 -0
- package/esri-compat/tile-layer.d.ts +52 -0
- package/esri-compat/tile-layer.d.ts.map +1 -0
- package/esri-compat/tile-layer.js +167 -0
- package/esri-compat/time-slider.d.ts +70 -0
- package/esri-compat/time-slider.d.ts.map +1 -0
- package/esri-compat/time-slider.js +208 -0
- package/esri-compat/track.d.ts +51 -0
- package/esri-compat/track.d.ts.map +1 -0
- package/esri-compat/track.js +174 -0
- package/esri-compat/unique-value-renderer.d.ts +41 -0
- package/esri-compat/unique-value-renderer.d.ts.map +1 -0
- package/esri-compat/unique-value-renderer.js +127 -0
- package/esri-compat/url.d.ts +12 -0
- package/esri-compat/url.d.ts.map +1 -0
- package/esri-compat/url.js +54 -0
- package/esri-compat/web-map.d.ts +14 -0
- package/esri-compat/web-map.d.ts.map +1 -0
- package/esri-compat/web-map.js +24 -0
- package/gen/honua/v1/feature_service_pb.d.ts +918 -0
- package/gen/honua/v1/feature_service_pb.d.ts.map +1 -0
- package/gen/honua/v1/feature_service_pb.js +375 -0
- package/index.d.ts +130 -0
- package/index.js +65 -0
- package/package.json +22 -0
package/core/wfs.d.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime classes for the WFS 2.0 adapter. Three layers:
|
|
3
|
+
*
|
|
4
|
+
* - `HonuaWfs` — root handle bound to a WFS endpoint URL. Owns the
|
|
5
|
+
* capabilities cache and exposes feature-type / stored-query factories.
|
|
6
|
+
* - `HonuaWfsFeatureType` — bound to a single namespace-qualified type
|
|
7
|
+
* name. Implements GetFeature / GetPropertyValue / Transaction; routed
|
|
8
|
+
* from `Source.protocol("wfs")`.
|
|
9
|
+
* - `HonuaWfsStoredQuery` — bound to a stored-query identifier. Used by
|
|
10
|
+
* `Source.protocol("wfs").storedQuery(id)`.
|
|
11
|
+
*
|
|
12
|
+
* All wire calls go through `HonuaClient.requestText`, so the existing
|
|
13
|
+
* interceptor / retry / timeout pipeline applies.
|
|
14
|
+
*
|
|
15
|
+
* Canonical translation (KVP and FES emission, GeoJSON ↔ canonical
|
|
16
|
+
* envelope, etc.) lives in `src/contract/source.ts`'s `wfsSource` factory;
|
|
17
|
+
* this module only carries the wire-level surface.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { HonuaClient } from "./client.js";
|
|
22
|
+
import { type WfsCapabilitiesSnapshot, type WfsTransactionSummary } from "./wfs-capabilities.js";
|
|
23
|
+
/**
|
|
24
|
+
* Negotiated output-format preference for a WFS GetFeature call. `format` is
|
|
25
|
+
* the wire value to send back (the original case the server advertised); the
|
|
26
|
+
* categorical kind is what the canonical surface acts on.
|
|
27
|
+
*/
|
|
28
|
+
export interface OutputFormatChoice {
|
|
29
|
+
kind: "json" | "gml";
|
|
30
|
+
format: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Construction options for `HonuaWfs`. The adapter is endpoint-bound: one
|
|
34
|
+
* `HonuaWfs` per server URL.
|
|
35
|
+
*/
|
|
36
|
+
export interface HonuaWfsOptions {
|
|
37
|
+
client: HonuaClient;
|
|
38
|
+
/** Fully qualified or relative WFS endpoint URL (e.g. `/wfs`). */
|
|
39
|
+
endpointUrl: string;
|
|
40
|
+
/** WFS version to request. Default `2.0.0`. */
|
|
41
|
+
version?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Root WFS handle. Holds the capabilities cache and exposes feature-type /
|
|
45
|
+
* stored-query factories.
|
|
46
|
+
*/
|
|
47
|
+
export declare class HonuaWfs {
|
|
48
|
+
readonly client: HonuaClient;
|
|
49
|
+
readonly endpointUrl: string;
|
|
50
|
+
readonly version: string;
|
|
51
|
+
/** Counter exposed for tests / diagnostics: how many times capabilities was fetched. */
|
|
52
|
+
capabilitiesFetches: number;
|
|
53
|
+
private capabilitiesPromise;
|
|
54
|
+
private rawCapabilitiesXml;
|
|
55
|
+
constructor(options: HonuaWfsOptions);
|
|
56
|
+
/**
|
|
57
|
+
* Fetch and cache the GetCapabilities document. Subsequent calls reuse the
|
|
58
|
+
* parsed snapshot. Throws `HonuaWfsExceptionError` on `<ows:ExceptionReport>`.
|
|
59
|
+
*/
|
|
60
|
+
capabilities(options?: {
|
|
61
|
+
signal?: AbortSignal;
|
|
62
|
+
}): Promise<WfsCapabilitiesSnapshot>;
|
|
63
|
+
/** Discard the cached capabilities snapshot so the next call re-fetches. */
|
|
64
|
+
refresh(): void;
|
|
65
|
+
/** Last raw capabilities XML payload (populated after the first fetch). */
|
|
66
|
+
rawCapabilities(): string | undefined;
|
|
67
|
+
/** Bind a feature-type handle. Does not network. */
|
|
68
|
+
featureType(typeName: string): HonuaWfsFeatureType;
|
|
69
|
+
/**
|
|
70
|
+
* Discover stored queries through the `ListStoredQueries` operation. Returns
|
|
71
|
+
* the bare list of identifier strings; per-query metadata is exposed via
|
|
72
|
+
* `storedQuery(id).describe()`.
|
|
73
|
+
*/
|
|
74
|
+
storedQueries(options?: {
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
}): Promise<readonly string[]>;
|
|
77
|
+
storedQuery(id: string): HonuaWfsStoredQuery;
|
|
78
|
+
/** Internal helper used by feature-type / stored-query handles. */
|
|
79
|
+
requestText(method: "GET" | "POST", path: string, options: {
|
|
80
|
+
accept: string;
|
|
81
|
+
contentType?: string;
|
|
82
|
+
body?: string;
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
text: string;
|
|
86
|
+
contentType: string;
|
|
87
|
+
status: number;
|
|
88
|
+
}>;
|
|
89
|
+
/** Negotiate an output format for the GetFeature call. */
|
|
90
|
+
negotiateOutputFormat(snapshot: WfsCapabilitiesSnapshot): OutputFormatChoice | undefined;
|
|
91
|
+
private fetchCapabilities;
|
|
92
|
+
}
|
|
93
|
+
interface HonuaWfsFeatureTypeOptions {
|
|
94
|
+
root: HonuaWfs;
|
|
95
|
+
typeName: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Per-feature-type WFS surface. Implements the wire methods that the
|
|
99
|
+
* canonical `wfsSource` translates onto, and the protocol escape-hatch
|
|
100
|
+
* methods that ship raw XML payloads back to callers.
|
|
101
|
+
*/
|
|
102
|
+
export declare class HonuaWfsFeatureType {
|
|
103
|
+
readonly root: HonuaWfs;
|
|
104
|
+
readonly typeName: string;
|
|
105
|
+
constructor(options: HonuaWfsFeatureTypeOptions);
|
|
106
|
+
/** Convenience: capabilities snapshot from the bound root. */
|
|
107
|
+
capabilities(options?: {
|
|
108
|
+
signal?: AbortSignal;
|
|
109
|
+
}): Promise<WfsCapabilitiesSnapshot>;
|
|
110
|
+
/**
|
|
111
|
+
* Issue a GetFeature request. Returns parsed JSON when the negotiated
|
|
112
|
+
* output format is JSON; otherwise returns the raw body as a string for
|
|
113
|
+
* downstream callers (the canonical surface throws in that case).
|
|
114
|
+
*/
|
|
115
|
+
getFeature(params: {
|
|
116
|
+
filter?: string;
|
|
117
|
+
bbox?: string;
|
|
118
|
+
propertyName?: string[];
|
|
119
|
+
sortBy?: string;
|
|
120
|
+
count?: number;
|
|
121
|
+
startIndex?: number;
|
|
122
|
+
resultType?: "results" | "hits";
|
|
123
|
+
srsName?: string;
|
|
124
|
+
outputFormat?: string;
|
|
125
|
+
method?: "GET" | "POST";
|
|
126
|
+
body?: string;
|
|
127
|
+
signal?: AbortSignal;
|
|
128
|
+
}): Promise<{
|
|
129
|
+
kind: "json";
|
|
130
|
+
data: unknown;
|
|
131
|
+
contentType: string;
|
|
132
|
+
} | {
|
|
133
|
+
kind: "raw";
|
|
134
|
+
text: string;
|
|
135
|
+
contentType: string;
|
|
136
|
+
}>;
|
|
137
|
+
/**
|
|
138
|
+
* Issue a `GetPropertyValue` request. WFS-specific (returns raw XML), so
|
|
139
|
+
* the canonical surface only reaches it via `protocol("wfs")`.
|
|
140
|
+
*/
|
|
141
|
+
getPropertyValue(params: {
|
|
142
|
+
valueReference: string;
|
|
143
|
+
filter?: string;
|
|
144
|
+
count?: number;
|
|
145
|
+
startIndex?: number;
|
|
146
|
+
signal?: AbortSignal;
|
|
147
|
+
}): Promise<{
|
|
148
|
+
text: string;
|
|
149
|
+
contentType: string;
|
|
150
|
+
}>;
|
|
151
|
+
/**
|
|
152
|
+
* Submit a `<wfs:Transaction>` POST body. Returns the parsed transaction
|
|
153
|
+
* summary; throws `HonuaWfsExceptionError` on `<ows:ExceptionReport>`.
|
|
154
|
+
*/
|
|
155
|
+
transaction(params: {
|
|
156
|
+
body: string;
|
|
157
|
+
signal?: AbortSignal;
|
|
158
|
+
}): Promise<WfsTransactionSummary>;
|
|
159
|
+
/** Build (but do not send) the URL the GET GetFeature request would use. */
|
|
160
|
+
buildGetFeatureUrl(params: {
|
|
161
|
+
filter?: string;
|
|
162
|
+
bbox?: string;
|
|
163
|
+
count?: number;
|
|
164
|
+
startIndex?: number;
|
|
165
|
+
outputFormat?: string;
|
|
166
|
+
}): string;
|
|
167
|
+
}
|
|
168
|
+
interface HonuaWfsStoredQueryOptions {
|
|
169
|
+
root: HonuaWfs;
|
|
170
|
+
id: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Bound stored-query handle. `execute(params)` runs `GetFeature?storedquery_id=…`.
|
|
174
|
+
*/
|
|
175
|
+
export declare class HonuaWfsStoredQuery {
|
|
176
|
+
readonly root: HonuaWfs;
|
|
177
|
+
readonly id: string;
|
|
178
|
+
constructor(options: HonuaWfsStoredQueryOptions);
|
|
179
|
+
/** Run `DescribeStoredQueries` for this stored query. Returns the raw XML. */
|
|
180
|
+
describe(options?: {
|
|
181
|
+
signal?: AbortSignal;
|
|
182
|
+
}): Promise<{
|
|
183
|
+
text: string;
|
|
184
|
+
contentType: string;
|
|
185
|
+
}>;
|
|
186
|
+
/**
|
|
187
|
+
* Execute the stored query against `GetFeature`. Caller passes the
|
|
188
|
+
* stored-query parameter map; values are coerced to strings via
|
|
189
|
+
* `String(value)`. Returns parsed JSON when the server replies with a
|
|
190
|
+
* JSON output format, raw text otherwise.
|
|
191
|
+
*/
|
|
192
|
+
execute(params: {
|
|
193
|
+
parameters?: Record<string, string | number | boolean>;
|
|
194
|
+
outputFormat?: string;
|
|
195
|
+
count?: number;
|
|
196
|
+
startIndex?: number;
|
|
197
|
+
signal?: AbortSignal;
|
|
198
|
+
}): Promise<{
|
|
199
|
+
kind: "json";
|
|
200
|
+
data: unknown;
|
|
201
|
+
contentType: string;
|
|
202
|
+
} | {
|
|
203
|
+
kind: "raw";
|
|
204
|
+
text: string;
|
|
205
|
+
contentType: string;
|
|
206
|
+
}>;
|
|
207
|
+
}
|
|
208
|
+
export declare function appendQuery(url: string, params: URLSearchParams): string;
|
|
209
|
+
export declare function looksLikeJson(contentType: string | undefined, text: string): boolean;
|
|
210
|
+
export declare function looksLikeXml(contentType: string | undefined, text: string): boolean;
|
|
211
|
+
/**
|
|
212
|
+
* If the underlying client failure carries a WFS ExceptionReport in its
|
|
213
|
+
* body, re-throw as `HonuaWfsExceptionError`; otherwise leave the original
|
|
214
|
+
* error in place. The body is wrapped by `parseResponseBody` as
|
|
215
|
+
* `{ raw: text, contentType? }` for non-JSON responses.
|
|
216
|
+
*/
|
|
217
|
+
export declare function rethrowAsWfsExceptionIfPossible(err: unknown): unknown;
|
|
218
|
+
export {};
|
|
219
|
+
//# sourceMappingURL=wfs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfs.d.ts","sourceRoot":"","sources":["../../../src/core/wfs.ts"],"names":[],"mappings":"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"}
|
package/core/wfs.js
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime classes for the WFS 2.0 adapter. Three layers:
|
|
3
|
+
*
|
|
4
|
+
* - `HonuaWfs` — root handle bound to a WFS endpoint URL. Owns the
|
|
5
|
+
* capabilities cache and exposes feature-type / stored-query factories.
|
|
6
|
+
* - `HonuaWfsFeatureType` — bound to a single namespace-qualified type
|
|
7
|
+
* name. Implements GetFeature / GetPropertyValue / Transaction; routed
|
|
8
|
+
* from `Source.protocol("wfs")`.
|
|
9
|
+
* - `HonuaWfsStoredQuery` — bound to a stored-query identifier. Used by
|
|
10
|
+
* `Source.protocol("wfs").storedQuery(id)`.
|
|
11
|
+
*
|
|
12
|
+
* All wire calls go through `HonuaClient.requestText`, so the existing
|
|
13
|
+
* interceptor / retry / timeout pipeline applies.
|
|
14
|
+
*
|
|
15
|
+
* Canonical translation (KVP and FES emission, GeoJSON ↔ canonical
|
|
16
|
+
* envelope, etc.) lives in `src/contract/source.ts`'s `wfsSource` factory;
|
|
17
|
+
* this module only carries the wire-level surface.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { HonuaHttpError, HonuaWfsExceptionError } from "./errors.js";
|
|
22
|
+
import { parseListStoredQueriesResponse, parseWfsCapabilities, parseWfsExceptionReport, parseWfsTransactionResponse, } from "./wfs-capabilities.js";
|
|
23
|
+
const DEFAULT_VERSION = "2.0.0";
|
|
24
|
+
const SERVICE_PARAM = "WFS";
|
|
25
|
+
/** Output formats (lower-cased) the canonical adapter treats as JSON. */
|
|
26
|
+
const JSON_OUTPUT_FORMATS = new Set([
|
|
27
|
+
"application/json",
|
|
28
|
+
"application/geo+json",
|
|
29
|
+
"application/vnd.geo+json",
|
|
30
|
+
"json",
|
|
31
|
+
"geojson",
|
|
32
|
+
]);
|
|
33
|
+
/** Output formats (lower-cased) the canonical adapter treats as GML. */
|
|
34
|
+
const GML_OUTPUT_FORMATS = new Set([
|
|
35
|
+
"application/gml+xml; version=3.2",
|
|
36
|
+
"application/gml+xml;version=3.2",
|
|
37
|
+
"application/gml+xml",
|
|
38
|
+
"gml3.2",
|
|
39
|
+
"gml32",
|
|
40
|
+
"text/xml; subtype=gml/3.2",
|
|
41
|
+
"text/xml;subtype=gml/3.2",
|
|
42
|
+
"text/xml; subtype=gml/3.2.1",
|
|
43
|
+
"text/xml;subtype=gml/3.2.1",
|
|
44
|
+
]);
|
|
45
|
+
/**
|
|
46
|
+
* Root WFS handle. Holds the capabilities cache and exposes feature-type /
|
|
47
|
+
* stored-query factories.
|
|
48
|
+
*/
|
|
49
|
+
export class HonuaWfs {
|
|
50
|
+
client;
|
|
51
|
+
endpointUrl;
|
|
52
|
+
version;
|
|
53
|
+
/** Counter exposed for tests / diagnostics: how many times capabilities was fetched. */
|
|
54
|
+
capabilitiesFetches = 0;
|
|
55
|
+
capabilitiesPromise;
|
|
56
|
+
rawCapabilitiesXml;
|
|
57
|
+
constructor(options) {
|
|
58
|
+
this.client = options.client;
|
|
59
|
+
this.endpointUrl = options.endpointUrl;
|
|
60
|
+
this.version = options.version ?? DEFAULT_VERSION;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fetch and cache the GetCapabilities document. Subsequent calls reuse the
|
|
64
|
+
* parsed snapshot. Throws `HonuaWfsExceptionError` on `<ows:ExceptionReport>`.
|
|
65
|
+
*/
|
|
66
|
+
capabilities(options) {
|
|
67
|
+
if (!this.capabilitiesPromise) {
|
|
68
|
+
this.capabilitiesPromise = this.fetchCapabilities(options).catch((err) => {
|
|
69
|
+
// Allow retry after a transient failure.
|
|
70
|
+
this.capabilitiesPromise = undefined;
|
|
71
|
+
throw err;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return this.capabilitiesPromise;
|
|
75
|
+
}
|
|
76
|
+
/** Discard the cached capabilities snapshot so the next call re-fetches. */
|
|
77
|
+
refresh() {
|
|
78
|
+
this.capabilitiesPromise = undefined;
|
|
79
|
+
this.rawCapabilitiesXml = undefined;
|
|
80
|
+
}
|
|
81
|
+
/** Last raw capabilities XML payload (populated after the first fetch). */
|
|
82
|
+
rawCapabilities() {
|
|
83
|
+
return this.rawCapabilitiesXml;
|
|
84
|
+
}
|
|
85
|
+
/** Bind a feature-type handle. Does not network. */
|
|
86
|
+
featureType(typeName) {
|
|
87
|
+
return new HonuaWfsFeatureType({ root: this, typeName });
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Discover stored queries through the `ListStoredQueries` operation. Returns
|
|
91
|
+
* the bare list of identifier strings; per-query metadata is exposed via
|
|
92
|
+
* `storedQuery(id).describe()`.
|
|
93
|
+
*/
|
|
94
|
+
async storedQueries(options) {
|
|
95
|
+
const params = new URLSearchParams({
|
|
96
|
+
service: SERVICE_PARAM,
|
|
97
|
+
version: this.version,
|
|
98
|
+
request: "ListStoredQueries",
|
|
99
|
+
});
|
|
100
|
+
const requestOptions = { accept: "application/xml, text/xml" };
|
|
101
|
+
if (options?.signal)
|
|
102
|
+
requestOptions.signal = options.signal;
|
|
103
|
+
const { text } = await this.requestText("GET", appendQuery(this.endpointUrl, params), requestOptions);
|
|
104
|
+
return parseListStoredQueriesResponse(text);
|
|
105
|
+
}
|
|
106
|
+
storedQuery(id) {
|
|
107
|
+
return new HonuaWfsStoredQuery({ root: this, id });
|
|
108
|
+
}
|
|
109
|
+
/** Internal helper used by feature-type / stored-query handles. */
|
|
110
|
+
async requestText(method, path, options) {
|
|
111
|
+
try {
|
|
112
|
+
const requestOptions = {
|
|
113
|
+
accept: options.accept,
|
|
114
|
+
};
|
|
115
|
+
if (options.contentType !== undefined)
|
|
116
|
+
requestOptions.contentType = options.contentType;
|
|
117
|
+
if (options.body !== undefined)
|
|
118
|
+
requestOptions.body = options.body;
|
|
119
|
+
if (options.signal !== undefined)
|
|
120
|
+
requestOptions.signal = options.signal;
|
|
121
|
+
return await this.client.requestText(method, path, requestOptions);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
throw rethrowAsWfsExceptionIfPossible(err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Negotiate an output format for the GetFeature call. */
|
|
128
|
+
negotiateOutputFormat(snapshot) {
|
|
129
|
+
const formats = snapshot.outputFormatsByOp.get("GetFeature") ?? [];
|
|
130
|
+
for (const format of formats) {
|
|
131
|
+
if (JSON_OUTPUT_FORMATS.has(format))
|
|
132
|
+
return { kind: "json", format };
|
|
133
|
+
}
|
|
134
|
+
for (const format of formats) {
|
|
135
|
+
if (GML_OUTPUT_FORMATS.has(format))
|
|
136
|
+
return { kind: "gml", format };
|
|
137
|
+
}
|
|
138
|
+
if (formats.length === 0) {
|
|
139
|
+
// Honua Server advertises GeoJSON in OperationsMetadata; absence is
|
|
140
|
+
// treated as "JSON unknown" — fall back to GeoJSON optimistically. The
|
|
141
|
+
// first request will surface the actual server behaviour through an
|
|
142
|
+
// ExceptionReport.
|
|
143
|
+
return { kind: "json", format: "application/geo+json" };
|
|
144
|
+
}
|
|
145
|
+
// Server advertises an output format the canonical adapter does not
|
|
146
|
+
// recognise — let the caller decide whether to throw or escape-hatch.
|
|
147
|
+
return { kind: "gml", format: formats[0] };
|
|
148
|
+
}
|
|
149
|
+
async fetchCapabilities(options) {
|
|
150
|
+
this.capabilitiesFetches += 1;
|
|
151
|
+
const params = new URLSearchParams({
|
|
152
|
+
service: SERVICE_PARAM,
|
|
153
|
+
version: this.version,
|
|
154
|
+
request: "GetCapabilities",
|
|
155
|
+
});
|
|
156
|
+
const requestOptions = { accept: "application/xml, text/xml" };
|
|
157
|
+
if (options?.signal)
|
|
158
|
+
requestOptions.signal = options.signal;
|
|
159
|
+
const { text } = await this.requestText("GET", appendQuery(this.endpointUrl, params), requestOptions);
|
|
160
|
+
this.rawCapabilitiesXml = text;
|
|
161
|
+
return parseWfsCapabilities(text);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Per-feature-type WFS surface. Implements the wire methods that the
|
|
166
|
+
* canonical `wfsSource` translates onto, and the protocol escape-hatch
|
|
167
|
+
* methods that ship raw XML payloads back to callers.
|
|
168
|
+
*/
|
|
169
|
+
export class HonuaWfsFeatureType {
|
|
170
|
+
root;
|
|
171
|
+
typeName;
|
|
172
|
+
constructor(options) {
|
|
173
|
+
this.root = options.root;
|
|
174
|
+
this.typeName = options.typeName;
|
|
175
|
+
}
|
|
176
|
+
/** Convenience: capabilities snapshot from the bound root. */
|
|
177
|
+
capabilities(options) {
|
|
178
|
+
return this.root.capabilities(options);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Issue a GetFeature request. Returns parsed JSON when the negotiated
|
|
182
|
+
* output format is JSON; otherwise returns the raw body as a string for
|
|
183
|
+
* downstream callers (the canonical surface throws in that case).
|
|
184
|
+
*/
|
|
185
|
+
async getFeature(params) {
|
|
186
|
+
const method = params.method ?? "GET";
|
|
187
|
+
const accept = params.outputFormat ?? "application/geo+json, application/json;q=0.9, application/xml;q=0.5";
|
|
188
|
+
const requestOptions = { accept };
|
|
189
|
+
if (params.signal)
|
|
190
|
+
requestOptions.signal = params.signal;
|
|
191
|
+
let response;
|
|
192
|
+
if (method === "POST" && params.body !== undefined) {
|
|
193
|
+
requestOptions.contentType = "application/xml";
|
|
194
|
+
requestOptions.body = params.body;
|
|
195
|
+
response = await this.root.requestText("POST", this.root.endpointUrl, requestOptions);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const search = new URLSearchParams({
|
|
199
|
+
service: SERVICE_PARAM,
|
|
200
|
+
version: this.root.version,
|
|
201
|
+
request: "GetFeature",
|
|
202
|
+
typeNames: this.typeName,
|
|
203
|
+
});
|
|
204
|
+
if (params.filter !== undefined)
|
|
205
|
+
search.set("filter", params.filter);
|
|
206
|
+
if (params.bbox !== undefined)
|
|
207
|
+
search.set("bbox", params.bbox);
|
|
208
|
+
if (params.propertyName && params.propertyName.length > 0) {
|
|
209
|
+
search.set("propertyName", params.propertyName.join(","));
|
|
210
|
+
}
|
|
211
|
+
if (params.sortBy !== undefined)
|
|
212
|
+
search.set("sortBy", params.sortBy);
|
|
213
|
+
if (typeof params.count === "number")
|
|
214
|
+
search.set("count", String(params.count));
|
|
215
|
+
if (typeof params.startIndex === "number")
|
|
216
|
+
search.set("startIndex", String(params.startIndex));
|
|
217
|
+
if (params.resultType !== undefined)
|
|
218
|
+
search.set("resultType", params.resultType);
|
|
219
|
+
if (params.srsName !== undefined)
|
|
220
|
+
search.set("srsName", params.srsName);
|
|
221
|
+
if (params.outputFormat !== undefined)
|
|
222
|
+
search.set("outputFormat", params.outputFormat);
|
|
223
|
+
response = await this.root.requestText("GET", appendQuery(this.root.endpointUrl, search), requestOptions);
|
|
224
|
+
}
|
|
225
|
+
if (looksLikeJson(response.contentType, response.text)) {
|
|
226
|
+
return { kind: "json", data: parseJsonOrThrow(response.text), contentType: response.contentType };
|
|
227
|
+
}
|
|
228
|
+
if (looksLikeXml(response.contentType, response.text) && /ExceptionReport/i.test(response.text)) {
|
|
229
|
+
const report = parseWfsExceptionReport(response.text);
|
|
230
|
+
throw new HonuaWfsExceptionError(report.exceptionCode, report.message, report.locator);
|
|
231
|
+
}
|
|
232
|
+
return { kind: "raw", text: response.text, contentType: response.contentType };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Issue a `GetPropertyValue` request. WFS-specific (returns raw XML), so
|
|
236
|
+
* the canonical surface only reaches it via `protocol("wfs")`.
|
|
237
|
+
*/
|
|
238
|
+
async getPropertyValue(params) {
|
|
239
|
+
const search = new URLSearchParams({
|
|
240
|
+
service: SERVICE_PARAM,
|
|
241
|
+
version: this.root.version,
|
|
242
|
+
request: "GetPropertyValue",
|
|
243
|
+
typeNames: this.typeName,
|
|
244
|
+
valueReference: params.valueReference,
|
|
245
|
+
});
|
|
246
|
+
if (params.filter !== undefined)
|
|
247
|
+
search.set("filter", params.filter);
|
|
248
|
+
if (typeof params.count === "number")
|
|
249
|
+
search.set("count", String(params.count));
|
|
250
|
+
if (typeof params.startIndex === "number")
|
|
251
|
+
search.set("startIndex", String(params.startIndex));
|
|
252
|
+
const requestOptions = { accept: "application/xml, text/xml" };
|
|
253
|
+
if (params.signal)
|
|
254
|
+
requestOptions.signal = params.signal;
|
|
255
|
+
const { text, contentType } = await this.root.requestText("GET", appendQuery(this.root.endpointUrl, search), requestOptions);
|
|
256
|
+
return { text, contentType };
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Submit a `<wfs:Transaction>` POST body. Returns the parsed transaction
|
|
260
|
+
* summary; throws `HonuaWfsExceptionError` on `<ows:ExceptionReport>`.
|
|
261
|
+
*/
|
|
262
|
+
async transaction(params) {
|
|
263
|
+
const requestOptions = {
|
|
264
|
+
accept: "application/xml, text/xml",
|
|
265
|
+
contentType: "application/xml",
|
|
266
|
+
body: params.body,
|
|
267
|
+
};
|
|
268
|
+
if (params.signal)
|
|
269
|
+
requestOptions.signal = params.signal;
|
|
270
|
+
const { text } = await this.root.requestText("POST", this.root.endpointUrl, requestOptions);
|
|
271
|
+
return parseWfsTransactionResponse(text);
|
|
272
|
+
}
|
|
273
|
+
/** Build (but do not send) the URL the GET GetFeature request would use. */
|
|
274
|
+
buildGetFeatureUrl(params) {
|
|
275
|
+
const search = new URLSearchParams({
|
|
276
|
+
service: SERVICE_PARAM,
|
|
277
|
+
version: this.root.version,
|
|
278
|
+
request: "GetFeature",
|
|
279
|
+
typeNames: this.typeName,
|
|
280
|
+
});
|
|
281
|
+
if (params.filter !== undefined)
|
|
282
|
+
search.set("filter", params.filter);
|
|
283
|
+
if (params.bbox !== undefined)
|
|
284
|
+
search.set("bbox", params.bbox);
|
|
285
|
+
if (typeof params.count === "number")
|
|
286
|
+
search.set("count", String(params.count));
|
|
287
|
+
if (typeof params.startIndex === "number")
|
|
288
|
+
search.set("startIndex", String(params.startIndex));
|
|
289
|
+
if (params.outputFormat !== undefined)
|
|
290
|
+
search.set("outputFormat", params.outputFormat);
|
|
291
|
+
return appendQuery(this.root.endpointUrl, search);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Bound stored-query handle. `execute(params)` runs `GetFeature?storedquery_id=…`.
|
|
296
|
+
*/
|
|
297
|
+
export class HonuaWfsStoredQuery {
|
|
298
|
+
root;
|
|
299
|
+
id;
|
|
300
|
+
constructor(options) {
|
|
301
|
+
this.root = options.root;
|
|
302
|
+
this.id = options.id;
|
|
303
|
+
}
|
|
304
|
+
/** Run `DescribeStoredQueries` for this stored query. Returns the raw XML. */
|
|
305
|
+
async describe(options) {
|
|
306
|
+
const search = new URLSearchParams({
|
|
307
|
+
service: SERVICE_PARAM,
|
|
308
|
+
version: this.root.version,
|
|
309
|
+
request: "DescribeStoredQueries",
|
|
310
|
+
storedQuery_Id: this.id,
|
|
311
|
+
});
|
|
312
|
+
const requestOptions = { accept: "application/xml, text/xml" };
|
|
313
|
+
if (options?.signal)
|
|
314
|
+
requestOptions.signal = options.signal;
|
|
315
|
+
const { text, contentType } = await this.root.requestText("GET", appendQuery(this.root.endpointUrl, search), requestOptions);
|
|
316
|
+
return { text, contentType };
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Execute the stored query against `GetFeature`. Caller passes the
|
|
320
|
+
* stored-query parameter map; values are coerced to strings via
|
|
321
|
+
* `String(value)`. Returns parsed JSON when the server replies with a
|
|
322
|
+
* JSON output format, raw text otherwise.
|
|
323
|
+
*/
|
|
324
|
+
async execute(params) {
|
|
325
|
+
const search = new URLSearchParams({
|
|
326
|
+
service: SERVICE_PARAM,
|
|
327
|
+
version: this.root.version,
|
|
328
|
+
request: "GetFeature",
|
|
329
|
+
storedquery_id: this.id,
|
|
330
|
+
});
|
|
331
|
+
if (typeof params.count === "number")
|
|
332
|
+
search.set("count", String(params.count));
|
|
333
|
+
if (typeof params.startIndex === "number")
|
|
334
|
+
search.set("startIndex", String(params.startIndex));
|
|
335
|
+
if (params.outputFormat !== undefined)
|
|
336
|
+
search.set("outputFormat", params.outputFormat);
|
|
337
|
+
if (params.parameters) {
|
|
338
|
+
for (const [key, value] of Object.entries(params.parameters)) {
|
|
339
|
+
search.set(key, String(value));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const accept = params.outputFormat ?? "application/geo+json, application/json;q=0.9, application/xml;q=0.5";
|
|
343
|
+
const requestOptions = { accept };
|
|
344
|
+
if (params.signal)
|
|
345
|
+
requestOptions.signal = params.signal;
|
|
346
|
+
const { text, contentType } = await this.root.requestText("GET", appendQuery(this.root.endpointUrl, search), requestOptions);
|
|
347
|
+
if (looksLikeJson(contentType, text)) {
|
|
348
|
+
return { kind: "json", data: parseJsonOrThrow(text), contentType };
|
|
349
|
+
}
|
|
350
|
+
if (looksLikeXml(contentType, text) && /ExceptionReport/i.test(text)) {
|
|
351
|
+
const report = parseWfsExceptionReport(text);
|
|
352
|
+
throw new HonuaWfsExceptionError(report.exceptionCode, report.message, report.locator);
|
|
353
|
+
}
|
|
354
|
+
return { kind: "raw", text, contentType };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// ── Helpers ───────────────────────────────────────────────────
|
|
358
|
+
export function appendQuery(url, params) {
|
|
359
|
+
// Preserve any pre-existing query string on the endpoint URL (some servers
|
|
360
|
+
// sit behind URL signatures that include their own params).
|
|
361
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
362
|
+
return `${url}${sep}${params.toString()}`;
|
|
363
|
+
}
|
|
364
|
+
export function looksLikeJson(contentType, text) {
|
|
365
|
+
if (contentType && /json/i.test(contentType))
|
|
366
|
+
return true;
|
|
367
|
+
const trimmed = text.trimStart();
|
|
368
|
+
return trimmed.startsWith("{") || trimmed.startsWith("[");
|
|
369
|
+
}
|
|
370
|
+
export function looksLikeXml(contentType, text) {
|
|
371
|
+
if (contentType && /xml/i.test(contentType))
|
|
372
|
+
return true;
|
|
373
|
+
return text.trimStart().startsWith("<");
|
|
374
|
+
}
|
|
375
|
+
function parseJsonOrThrow(text) {
|
|
376
|
+
try {
|
|
377
|
+
return JSON.parse(text);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
381
|
+
throw new Error(`WFS GetFeature returned non-JSON output despite Accept negotiation: ${message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* If the underlying client failure carries a WFS ExceptionReport in its
|
|
386
|
+
* body, re-throw as `HonuaWfsExceptionError`; otherwise leave the original
|
|
387
|
+
* error in place. The body is wrapped by `parseResponseBody` as
|
|
388
|
+
* `{ raw: text, contentType? }` for non-JSON responses.
|
|
389
|
+
*/
|
|
390
|
+
export function rethrowAsWfsExceptionIfPossible(err) {
|
|
391
|
+
if (!(err instanceof HonuaHttpError))
|
|
392
|
+
return err;
|
|
393
|
+
const body = err.body;
|
|
394
|
+
if (!body || typeof body !== "object" || typeof body.raw !== "string")
|
|
395
|
+
return err;
|
|
396
|
+
const raw = body.raw;
|
|
397
|
+
if (!/ExceptionReport/i.test(raw))
|
|
398
|
+
return err;
|
|
399
|
+
try {
|
|
400
|
+
const report = parseWfsExceptionReport(raw);
|
|
401
|
+
return new HonuaWfsExceptionError(report.exceptionCode, report.message, report.locator);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return err;
|
|
405
|
+
}
|
|
406
|
+
}
|