@honua/react 0.1.1-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,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight deterministic WFS 2.0 compiler.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from the semantic WFS compiler so importing the public
|
|
5
|
+
* `wfsProtocolModule()` does not pull the larger semantic compiler graph into
|
|
6
|
+
* contract-only bundles.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProtocolModuleQueryCompileInput, ProtocolModuleQueryOperation } from "../contract/protocol-module.js";
|
|
9
|
+
import type { CanonicalQuery, QueryIrSourceIdentity, WfsCompiledQueryV1, WfsProtocolCompiledQueryV1 } from "./types.js";
|
|
10
|
+
/** Compile canonical query IR to the legacy deterministic WFS 2.0 GetFeature request. */
|
|
11
|
+
export declare function compileWfsQuery(source: QueryIrSourceIdentity, query: CanonicalQuery): WfsCompiledQueryV1;
|
|
12
|
+
/**
|
|
13
|
+
* The exact deterministic compiler hook installed on the first-party WFS
|
|
14
|
+
* protocol module and used by planner dispatch.
|
|
15
|
+
*/
|
|
16
|
+
export declare const wfsProtocolQueryCompiler: Readonly<{
|
|
17
|
+
kind: "wfs";
|
|
18
|
+
compile(input: ProtocolModuleQueryCompileInput<QueryIrSourceIdentity, CanonicalQuery>): WfsProtocolCompiledQueryV1;
|
|
19
|
+
}>;
|
|
20
|
+
type WfsProtocolRequest = Omit<WfsProtocolCompiledQueryV1, "compiler" | "operation">;
|
|
21
|
+
/** Bind a WFS wire request to the exact operation authorized to execute it. */
|
|
22
|
+
export declare function bindWfsProtocolQueryOperation(request: WfsProtocolRequest, operation: ProtocolModuleQueryOperation): WfsProtocolCompiledQueryV1;
|
|
23
|
+
/** Credential-free endpoint identity used to bind an executable artifact to a runtime handle. */
|
|
24
|
+
export declare function wfsRuntimeEndpointIdentity(value: string): string;
|
|
25
|
+
/** Derive the only transport method authorized by the compiled filter budget. */
|
|
26
|
+
export declare function wfsProtocolMethodForFilter(filter: string | undefined): "GET" | "POST";
|
|
27
|
+
/**
|
|
28
|
+
* @internal True when the compiled request must name the geometry property in
|
|
29
|
+
* an FES spatial predicate. The `bbox=` KVP shortcut addresses the feature
|
|
30
|
+
* type's default geometry positionally, so it needs no name; every other
|
|
31
|
+
* spatial predicate emits `<fes:ValueReference>` and does. The live adapter
|
|
32
|
+
* uses this to resolve the property (and fail closed) only when the wire
|
|
33
|
+
* actually depends on it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function wfsSpatialFilterNeedsGeometryProperty(query: CanonicalQuery): boolean;
|
|
36
|
+
/** @internal Shared with legacy non-query WFS drains to preserve CRS parity. */
|
|
37
|
+
export declare function wfsSrsNameFromOutSr(outSr: string | number | undefined): string | undefined;
|
|
38
|
+
/** @internal Resolve only the input geometry CRS; response `outSr` is separate. */
|
|
39
|
+
export declare function wfsFilterSrsNameFromGeometry(geometry: Readonly<Record<string, unknown>>, fallback: string | number | undefined): string | undefined;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=wfs-v1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfs-v1.d.ts","sourceRoot":"","sources":["../../../src/query-planner/wfs-v1.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,+BAA+B,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAkBpH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAaxH,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,cAAc,GAAG,kBAAkB,CA4BxG;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;mBAEpB,+BAA+B,CAAC,qBAAqB,EAAE,cAAc,CAAC,GAAG,0BAA0B;EAuDlH,CAAC;AAEH,KAAK,kBAAkB,GAAG,IAAI,CAAC,0BAA0B,EAAE,UAAU,GAAG,WAAW,CAAC,CAAC;AAErF,+EAA+E;AAC/E,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,4BAA4B,GACtC,0BAA0B,CA+B5B;AAED,iGAAiG;AACjG,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,iFAAiF;AACjF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAErF;AAuFD;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAGpF;AAeD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAa1F;AAQD,mFAAmF;AACnF,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GACpC,MAAM,GAAG,SAAS,CAiCpB"}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { compileQueryFilterToFes } from "../contract/query-filter-fes.js";
|
|
2
|
+
import { andQueryFilters, temporalFilterToExpression, } from "../contract/query-filter.js";
|
|
3
|
+
import { UNSUPPORTED_FES, compileSpatialFilter, compileWhere, formatWfsBboxKvp, serializeFes, } from "../core/wfs-filter.js";
|
|
4
|
+
import { queryIrAuthorityFingerprint } from "./ir.js";
|
|
5
|
+
import { HonuaQueryPlanningError } from "./types.js";
|
|
6
|
+
const WFS_GET_FILTER_BUDGET = 7000;
|
|
7
|
+
/**
|
|
8
|
+
* Metadata-free planning fallback only. The live WFS adapter resolves the real
|
|
9
|
+
* geometry property per feature type (DescribeFeatureType, or an explicit
|
|
10
|
+
* `locator.geometryName`) and carries it on the IR source identity, so this
|
|
11
|
+
* legacy PostGIS-via-GeoServer default is used only when a caller compiles a
|
|
12
|
+
* plan without any geometry evidence at all.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_WFS_GEOMETRY_PROPERTY = "the_geom";
|
|
15
|
+
/** Compile canonical query IR to the legacy deterministic WFS 2.0 GetFeature request. */
|
|
16
|
+
export function compileWfsQuery(source, query) {
|
|
17
|
+
const typeName = requireWfsTypeName(source);
|
|
18
|
+
const geometryProperty = wfsGeometryProperty(source);
|
|
19
|
+
assertNoWfsAggregation(query);
|
|
20
|
+
if (query.spatialFilter && query.outSr !== undefined) {
|
|
21
|
+
throw new HonuaQueryPlanningError("unsupported-query", "WFS planning cannot use outSr to label input filter coordinates; stamp the input geometry through the typed WFS escape hatch");
|
|
22
|
+
}
|
|
23
|
+
const filter = compileWfsFes(typeName, query, geometryProperty);
|
|
24
|
+
const propertyName = compileWfsPropertyNames(query, geometryProperty);
|
|
25
|
+
return {
|
|
26
|
+
compiler: "wfs-2.0-get-feature-v1",
|
|
27
|
+
typeName,
|
|
28
|
+
...(filter !== undefined ? { filter } : {}),
|
|
29
|
+
...(propertyName ? { propertyName } : {}),
|
|
30
|
+
...(query.orderBy && query.orderBy.length > 0
|
|
31
|
+
? {
|
|
32
|
+
sortBy: query.orderBy.map((sort) => `${sort.field} ${sort.direction === "desc" ? "DESC" : "ASC"}`).join(","),
|
|
33
|
+
}
|
|
34
|
+
: {}),
|
|
35
|
+
...(query.pagination?.offset !== undefined ? { startIndex: query.pagination.offset } : {}),
|
|
36
|
+
...(query.pagination?.limit !== undefined ? { count: query.pagination.limit } : {}),
|
|
37
|
+
...(query.outSr !== undefined ? { srsName: String(query.outSr) } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The exact deterministic compiler hook installed on the first-party WFS
|
|
42
|
+
* protocol module and used by planner dispatch.
|
|
43
|
+
*/
|
|
44
|
+
export const wfsProtocolQueryCompiler = Object.freeze({
|
|
45
|
+
kind: "wfs",
|
|
46
|
+
compile(input) {
|
|
47
|
+
const typeName = requireWfsTypeName(input.source);
|
|
48
|
+
if (!/^[A-Za-z_][A-Za-z0-9_.-]*(?::[A-Za-z_][A-Za-z0-9_.-]*)?$/.test(typeName)) {
|
|
49
|
+
throw new HonuaQueryPlanningError("invalid-query", `Source "${input.source.id}" has an invalid WFS typeName`);
|
|
50
|
+
}
|
|
51
|
+
assertNoWfsAggregation(input.query);
|
|
52
|
+
const endpoint = requireCredentialFreeWfsCompileEndpoint(input.source.endpoint);
|
|
53
|
+
const authorityFingerprint = input.source.authorityFingerprint ??
|
|
54
|
+
queryIrAuthorityFingerprint(input.source.endpoint, input.source.authorizationScope);
|
|
55
|
+
if (!/^sha256:[0-9a-f]{64}$/.test(authorityFingerprint)) {
|
|
56
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS source authority fingerprint is invalid");
|
|
57
|
+
}
|
|
58
|
+
if (typeof input.source.id !== "string" ||
|
|
59
|
+
input.source.id.length === 0 ||
|
|
60
|
+
containsControlCharacter(input.source.id)) {
|
|
61
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS source id is invalid");
|
|
62
|
+
}
|
|
63
|
+
const srsName = wfsSrsNameFromOutSr(input.query.outSr);
|
|
64
|
+
const filterSrsName = wfsSpatialFilterSrsName(input.source, input.query);
|
|
65
|
+
const geometryProperty = wfsGeometryProperty(input.source);
|
|
66
|
+
const bbox = wfsBboxKvp(input.query, filterSrsName);
|
|
67
|
+
const filter = bbox === undefined ? compileWfsFes(typeName, input.query, geometryProperty, filterSrsName) : undefined;
|
|
68
|
+
const method = wfsProtocolMethodForFilter(filter);
|
|
69
|
+
const propertyName = compileWfsPropertyNames(input.query, geometryProperty);
|
|
70
|
+
const sortBy = input.query.orderBy && input.query.orderBy.length > 0
|
|
71
|
+
? input.query.orderBy.map((sort) => `${sort.field}${sort.direction === "desc" ? " D" : " A"}`).join(",")
|
|
72
|
+
: undefined;
|
|
73
|
+
const startIndex = input.query.pagination?.offset !== undefined && input.query.pagination.offset > 0
|
|
74
|
+
? input.query.pagination.offset
|
|
75
|
+
: undefined;
|
|
76
|
+
return bindWfsProtocolQueryOperation({
|
|
77
|
+
sourceId: input.source.id,
|
|
78
|
+
endpoint,
|
|
79
|
+
authorityFingerprint,
|
|
80
|
+
typeName,
|
|
81
|
+
method,
|
|
82
|
+
...(filter !== undefined ? { filter } : {}),
|
|
83
|
+
...(bbox !== undefined ? { bbox } : {}),
|
|
84
|
+
...(propertyName !== undefined ? { propertyName: Object.freeze([...propertyName]) } : {}),
|
|
85
|
+
...(sortBy !== undefined ? { sortBy } : {}),
|
|
86
|
+
...(startIndex !== undefined ? { startIndex } : {}),
|
|
87
|
+
...(input.query.pagination?.limit !== undefined ? { count: input.query.pagination.limit } : {}),
|
|
88
|
+
...(filterSrsName !== undefined ? { filterSrsName } : {}),
|
|
89
|
+
...(srsName !== undefined ? { srsName } : {}),
|
|
90
|
+
}, input.operation);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
/** Bind a WFS wire request to the exact operation authorized to execute it. */
|
|
94
|
+
export function bindWfsProtocolQueryOperation(request, operation) {
|
|
95
|
+
if (operation !== "query" && operation !== "queryAll" && operation !== "queryAggregate") {
|
|
96
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS protocol operation is invalid");
|
|
97
|
+
}
|
|
98
|
+
let count = request.count;
|
|
99
|
+
if (operation === "queryAll" && count !== undefined) {
|
|
100
|
+
if (!Number.isSafeInteger(count) || count < 0 || count >= Number.MAX_SAFE_INTEGER) {
|
|
101
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS queryAll pagination.limit must leave room for one lookahead row");
|
|
102
|
+
}
|
|
103
|
+
count += 1;
|
|
104
|
+
}
|
|
105
|
+
return Object.freeze({
|
|
106
|
+
compiler: "wfs-2.0-protocol-query-v1",
|
|
107
|
+
operation,
|
|
108
|
+
sourceId: request.sourceId,
|
|
109
|
+
endpoint: request.endpoint,
|
|
110
|
+
authorityFingerprint: request.authorityFingerprint,
|
|
111
|
+
typeName: request.typeName,
|
|
112
|
+
method: request.method,
|
|
113
|
+
...(request.filter !== undefined ? { filter: request.filter } : {}),
|
|
114
|
+
...(request.bbox !== undefined ? { bbox: request.bbox } : {}),
|
|
115
|
+
...(request.propertyName !== undefined ? { propertyName: Object.freeze([...request.propertyName]) } : {}),
|
|
116
|
+
...(request.sortBy !== undefined ? { sortBy: request.sortBy } : {}),
|
|
117
|
+
...(request.startIndex !== undefined ? { startIndex: request.startIndex } : {}),
|
|
118
|
+
...(count !== undefined ? { count } : {}),
|
|
119
|
+
...(request.filterSrsName !== undefined ? { filterSrsName: request.filterSrsName } : {}),
|
|
120
|
+
...(request.srsName !== undefined ? { srsName: request.srsName } : {}),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** Credential-free endpoint identity used to bind an executable artifact to a runtime handle. */
|
|
124
|
+
export function wfsRuntimeEndpointIdentity(value) {
|
|
125
|
+
return normalizeWfsEndpoint(value, true);
|
|
126
|
+
}
|
|
127
|
+
/** Derive the only transport method authorized by the compiled filter budget. */
|
|
128
|
+
export function wfsProtocolMethodForFilter(filter) {
|
|
129
|
+
return filter !== undefined && encodeURIComponent(filter).length > WFS_GET_FILTER_BUDGET ? "POST" : "GET";
|
|
130
|
+
}
|
|
131
|
+
function requireCredentialFreeWfsCompileEndpoint(value) {
|
|
132
|
+
return normalizeWfsEndpoint(value, false);
|
|
133
|
+
}
|
|
134
|
+
function normalizeWfsEndpoint(value, allowRuntimeAuthority) {
|
|
135
|
+
if (typeof value !== "string" ||
|
|
136
|
+
value.length === 0 ||
|
|
137
|
+
value === "[invalid-endpoint]" ||
|
|
138
|
+
containsControlCharacter(value)) {
|
|
139
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS endpoint identity is invalid");
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const parsed = new URL(value);
|
|
143
|
+
if (!allowRuntimeAuthority && (parsed.username || parsed.password || parsed.search || parsed.hash)) {
|
|
144
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS compile endpoint must not contain credentials, query, or fragment");
|
|
145
|
+
}
|
|
146
|
+
parsed.username = "";
|
|
147
|
+
parsed.password = "";
|
|
148
|
+
parsed.search = "";
|
|
149
|
+
parsed.hash = "";
|
|
150
|
+
// Match queryIrSourceIdentity(): normalize the URL serializer's single
|
|
151
|
+
// terminal separator without collapsing a path that intentionally ends
|
|
152
|
+
// in multiple slashes.
|
|
153
|
+
return parsed.toString().replace(/\/$/, "");
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error instanceof HonuaQueryPlanningError)
|
|
157
|
+
throw error;
|
|
158
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(value) || value.startsWith("//") || value.includes("@")) {
|
|
159
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS endpoint identity is invalid");
|
|
160
|
+
}
|
|
161
|
+
const queryIndex = value.search(/[?#]/);
|
|
162
|
+
if (!allowRuntimeAuthority && queryIndex >= 0) {
|
|
163
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS compile endpoint must not contain credentials, query, or fragment");
|
|
164
|
+
}
|
|
165
|
+
const path = queryIndex >= 0 ? value.slice(0, queryIndex) : value;
|
|
166
|
+
const normalized = path.replace(/\/$/, "");
|
|
167
|
+
if (path === "/")
|
|
168
|
+
return "/";
|
|
169
|
+
if (normalized.length === 0) {
|
|
170
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS endpoint identity is invalid");
|
|
171
|
+
}
|
|
172
|
+
return normalized;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function wfsBboxKvp(query, filterSrsName) {
|
|
176
|
+
const envelope = wfsBboxShortcutEnvelope(query);
|
|
177
|
+
if (!envelope)
|
|
178
|
+
return undefined;
|
|
179
|
+
return formatWfsBboxKvp(envelope.xmin, envelope.ymin, envelope.xmax, envelope.ymax, filterSrsName);
|
|
180
|
+
}
|
|
181
|
+
function wfsBboxShortcutEnvelope(query) {
|
|
182
|
+
const filter = query.spatialFilter;
|
|
183
|
+
// The `bbox=` KVP is mutually exclusive with `FILTER=`, so any other
|
|
184
|
+
// constraint that has to be expressed as FES (source-native `where`, the
|
|
185
|
+
// typed filter, a temporal predicate) disables the shortcut.
|
|
186
|
+
if (query.where !== undefined || query.filter !== undefined || query.temporalFilter !== undefined)
|
|
187
|
+
return undefined;
|
|
188
|
+
if (!filter || filter.geometryType !== "esriGeometryEnvelope")
|
|
189
|
+
return undefined;
|
|
190
|
+
if (filter.spatialRel !== undefined &&
|
|
191
|
+
filter.spatialRel !== "esriSpatialRelIntersects" &&
|
|
192
|
+
filter.spatialRel !== "esriSpatialRelEnvelopeIntersects") {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
const envelope = filter.geometry;
|
|
196
|
+
if (typeof envelope.xmin !== "number" ||
|
|
197
|
+
typeof envelope.ymin !== "number" ||
|
|
198
|
+
typeof envelope.xmax !== "number" ||
|
|
199
|
+
typeof envelope.ymax !== "number") {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return { xmin: envelope.xmin, ymin: envelope.ymin, xmax: envelope.xmax, ymax: envelope.ymax };
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* @internal True when the compiled request must name the geometry property in
|
|
206
|
+
* an FES spatial predicate. The `bbox=` KVP shortcut addresses the feature
|
|
207
|
+
* type's default geometry positionally, so it needs no name; every other
|
|
208
|
+
* spatial predicate emits `<fes:ValueReference>` and does. The live adapter
|
|
209
|
+
* uses this to resolve the property (and fail closed) only when the wire
|
|
210
|
+
* actually depends on it.
|
|
211
|
+
*/
|
|
212
|
+
export function wfsSpatialFilterNeedsGeometryProperty(query) {
|
|
213
|
+
if (query.filter !== undefined && queryFilterContainsSpatial(query.filter))
|
|
214
|
+
return true;
|
|
215
|
+
return query.spatialFilter !== undefined && wfsBboxShortcutEnvelope(query) === undefined;
|
|
216
|
+
}
|
|
217
|
+
/** True when the typed filter references the feature type's geometry property. */
|
|
218
|
+
function queryFilterContainsSpatial(filter) {
|
|
219
|
+
if (filter.kind === "spatial")
|
|
220
|
+
return filter.property === undefined;
|
|
221
|
+
if (filter.kind === "boolean")
|
|
222
|
+
return filter.args.some(queryFilterContainsSpatial);
|
|
223
|
+
if (filter.kind === "not")
|
|
224
|
+
return queryFilterContainsSpatial(filter.arg);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
/** Geometry property the compiled request references by name. */
|
|
228
|
+
function wfsGeometryProperty(source) {
|
|
229
|
+
return source.geometryProperty ?? DEFAULT_WFS_GEOMETRY_PROPERTY;
|
|
230
|
+
}
|
|
231
|
+
/** @internal Shared with legacy non-query WFS drains to preserve CRS parity. */
|
|
232
|
+
export function wfsSrsNameFromOutSr(outSr) {
|
|
233
|
+
if (typeof outSr === "string") {
|
|
234
|
+
if (outSr.length === 0)
|
|
235
|
+
return undefined;
|
|
236
|
+
if (outSr.trim() !== outSr || /[\s,]/.test(outSr) || containsControlCharacter(outSr)) {
|
|
237
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS CRS identifier is invalid");
|
|
238
|
+
}
|
|
239
|
+
return outSr;
|
|
240
|
+
}
|
|
241
|
+
if (typeof outSr === "number" && Number.isSafeInteger(outSr) && outSr > 0) {
|
|
242
|
+
return `urn:ogc:def:crs:EPSG::${outSr}`;
|
|
243
|
+
}
|
|
244
|
+
if (outSr === undefined)
|
|
245
|
+
return undefined;
|
|
246
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS CRS identifier is invalid");
|
|
247
|
+
}
|
|
248
|
+
function wfsSpatialFilterSrsName(source, query) {
|
|
249
|
+
const spatialFilter = query.spatialFilter;
|
|
250
|
+
if (!spatialFilter)
|
|
251
|
+
return undefined;
|
|
252
|
+
return wfsFilterSrsNameFromGeometry(spatialFilter.geometry, source.srsName);
|
|
253
|
+
}
|
|
254
|
+
/** @internal Resolve only the input geometry CRS; response `outSr` is separate. */
|
|
255
|
+
export function wfsFilterSrsNameFromGeometry(geometry, fallback) {
|
|
256
|
+
const spatialReference = geometry.spatialReference;
|
|
257
|
+
if (spatialReference === undefined)
|
|
258
|
+
return wfsSrsNameFromOutSr(fallback);
|
|
259
|
+
if (spatialReference === null || typeof spatialReference !== "object" || Array.isArray(spatialReference)) {
|
|
260
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS spatial filter geometry has an invalid spatialReference");
|
|
261
|
+
}
|
|
262
|
+
const reference = spatialReference;
|
|
263
|
+
const keys = Object.keys(reference);
|
|
264
|
+
if (keys.some((key) => key !== "wkid" && key !== "latestWkid" && key !== "wkt")) {
|
|
265
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS spatial filter geometry has an unsupported spatialReference member");
|
|
266
|
+
}
|
|
267
|
+
if (reference.wkt !== undefined) {
|
|
268
|
+
throw new HonuaQueryPlanningError("unsupported-query", "WFS spatial filters require a WKID-backed CRS; WKT cannot be serialized as a portable srsName");
|
|
269
|
+
}
|
|
270
|
+
for (const [name, value] of [
|
|
271
|
+
["wkid", reference.wkid],
|
|
272
|
+
["latestWkid", reference.latestWkid],
|
|
273
|
+
]) {
|
|
274
|
+
if (value !== undefined && (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)) {
|
|
275
|
+
throw new HonuaQueryPlanningError("invalid-query", `WFS spatial filter geometry has an invalid ${name}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const wkid = reference.latestWkid ?? reference.wkid;
|
|
279
|
+
if (typeof wkid !== "number") {
|
|
280
|
+
throw new HonuaQueryPlanningError("invalid-query", "WFS spatial filter geometry requires a positive WKID");
|
|
281
|
+
}
|
|
282
|
+
return wfsSrsNameFromOutSr(wkid);
|
|
283
|
+
}
|
|
284
|
+
function requireWfsTypeName(source) {
|
|
285
|
+
if (source.protocol !== "wfs") {
|
|
286
|
+
throw new HonuaQueryPlanningError("unsupported-compiler", `wfs-2.0-get-feature-v1 does not compile protocol "${source.protocol}"`);
|
|
287
|
+
}
|
|
288
|
+
if (!source.typeName) {
|
|
289
|
+
throw new HonuaQueryPlanningError("invalid-query", `Source "${source.id}" requires locator.typeName for WFS planning`);
|
|
290
|
+
}
|
|
291
|
+
return source.typeName;
|
|
292
|
+
}
|
|
293
|
+
function assertNoWfsAggregation(query) {
|
|
294
|
+
if (query.aggregation) {
|
|
295
|
+
throw new HonuaQueryPlanningError("unsupported-query", "WFS 2.0 has no portable remote aggregation; use degraded policy with an explicit bounded-local fallback");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function compileWfsFes(typeName, query, geometryProperty, srsName) {
|
|
299
|
+
const filters = [];
|
|
300
|
+
const typed = compileWfsTypedFilter(query, geometryProperty);
|
|
301
|
+
if (typed)
|
|
302
|
+
filters.push(typed);
|
|
303
|
+
if (query.where) {
|
|
304
|
+
const where = compileWhere(query.where.expression);
|
|
305
|
+
if (where === UNSUPPORTED_FES) {
|
|
306
|
+
throw new HonuaQueryPlanningError("unsupported-query", "The where clause is not expressible as FES 2.0");
|
|
307
|
+
}
|
|
308
|
+
if (where.kind !== "and" || where.operands.length > 0)
|
|
309
|
+
filters.push(where);
|
|
310
|
+
}
|
|
311
|
+
if (query.spatialFilter) {
|
|
312
|
+
const spatial = compileSpatialFilter({
|
|
313
|
+
geometry: query.spatialFilter.geometry,
|
|
314
|
+
geometryType: query.spatialFilter.geometryType,
|
|
315
|
+
...(query.spatialFilter.spatialRel ? { spatialRel: query.spatialFilter.spatialRel } : {}),
|
|
316
|
+
}, {
|
|
317
|
+
geometryProperty,
|
|
318
|
+
...(srsName !== undefined ? { srsName } : {}),
|
|
319
|
+
});
|
|
320
|
+
if (spatial === UNSUPPORTED_FES) {
|
|
321
|
+
throw new HonuaQueryPlanningError("unsupported-query", "The spatial predicate is not expressible as FES 2.0");
|
|
322
|
+
}
|
|
323
|
+
filters.push(spatial);
|
|
324
|
+
}
|
|
325
|
+
return filters.length > 0 ? serializeFes(filters, { typeName }) : undefined;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Compile the canonical typed filter (and a field-bound temporal filter) into
|
|
329
|
+
* FES 2.0. WFS has no protocol-level time parameter, so a temporal filter
|
|
330
|
+
* without a field is refused instead of being applied to a guessed column.
|
|
331
|
+
*/
|
|
332
|
+
function compileWfsTypedFilter(query, geometryProperty) {
|
|
333
|
+
const ctx = { protocol: "wfs", geometryProperty };
|
|
334
|
+
const temporalExpression = query.temporalFilter ? temporalFilterToExpression(query.temporalFilter, ctx) : undefined;
|
|
335
|
+
if (query.temporalFilter && temporalExpression === undefined) {
|
|
336
|
+
throw new HonuaQueryPlanningError("unsupported-query", "WFS has no protocol-level time parameter; Query.temporalFilter must name the temporal field");
|
|
337
|
+
}
|
|
338
|
+
const expression = andQueryFilters(query.filter, temporalExpression);
|
|
339
|
+
if (!expression)
|
|
340
|
+
return undefined;
|
|
341
|
+
return compileQueryFilterToFes(expression, ctx);
|
|
342
|
+
}
|
|
343
|
+
function compileWfsPropertyNames(query, geometryProperty) {
|
|
344
|
+
if (query.outFields && query.outFields.length > 0) {
|
|
345
|
+
const fields = [...query.outFields];
|
|
346
|
+
if (query.returnGeometry === false && fields.includes(geometryProperty)) {
|
|
347
|
+
throw new HonuaQueryPlanningError("unsupported-query", `WFS returnGeometry=false conflicts with outFields containing the geometry property "${geometryProperty}"`);
|
|
348
|
+
}
|
|
349
|
+
if (query.returnGeometry !== false && !fields.includes(geometryProperty)) {
|
|
350
|
+
fields.push(geometryProperty);
|
|
351
|
+
}
|
|
352
|
+
return fields;
|
|
353
|
+
}
|
|
354
|
+
if (query.returnGeometry === false) {
|
|
355
|
+
throw new HonuaQueryPlanningError("unsupported-query", "WFS returnGeometry=false requires explicit outFields because propertyName cannot otherwise suppress geometry exactly");
|
|
356
|
+
}
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
function containsControlCharacter(value) {
|
|
360
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
361
|
+
const code = value.charCodeAt(index);
|
|
362
|
+
if (code <= 0x1f || code === 0x7f)
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
return false;
|
|
366
|
+
}
|
package/query-planner/wfs.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export { compileWfsQuery } from "./wfs-v1.js";
|
|
2
2
|
export { compileSemanticWfsQuery } from "./wfs-semantic.js";
|
|
3
3
|
export type { SemanticWfsCompileOptions, SemanticWfsCompiledQueryV1, SemanticWfsSourceIdentity, Wfs20FilterCapabilitiesEvidence, } from "./wfs-semantic.js";
|
|
4
|
-
/** Compile canonical query IR to a deterministic WFS 2.0 GetFeature request. */
|
|
5
|
-
export declare function compileWfsQuery(source: QueryIrSourceIdentity, query: CanonicalQuery): WfsCompiledQueryV1;
|
|
6
4
|
//# sourceMappingURL=wfs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wfs.d.ts","sourceRoot":"","sources":["../../../src/query-planner/wfs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wfs.d.ts","sourceRoot":"","sources":["../../../src/query-planner/wfs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC"}
|
package/query-planner/wfs.js
CHANGED
|
@@ -1,71 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { HonuaQueryPlanningError } from "./types.js";
|
|
1
|
+
export { compileWfsQuery } from "./wfs-v1.js";
|
|
3
2
|
export { compileSemanticWfsQuery } from "./wfs-semantic.js";
|
|
4
|
-
/** Compile canonical query IR to a deterministic WFS 2.0 GetFeature request. */
|
|
5
|
-
export function compileWfsQuery(source, query) {
|
|
6
|
-
if (source.protocol !== "wfs") {
|
|
7
|
-
throw new HonuaQueryPlanningError("unsupported-compiler", `wfs-2.0-get-feature-v1 does not compile protocol "${source.protocol}"`);
|
|
8
|
-
}
|
|
9
|
-
if (!source.typeName) {
|
|
10
|
-
throw new HonuaQueryPlanningError("invalid-query", `Source "${source.id}" requires locator.typeName for WFS planning`);
|
|
11
|
-
}
|
|
12
|
-
if (query.aggregation) {
|
|
13
|
-
throw new HonuaQueryPlanningError("unsupported-query", "WFS 2.0 has no portable remote aggregation; use degraded policy with an explicit bounded-local fallback");
|
|
14
|
-
}
|
|
15
|
-
if (query.spatialFilter && query.outSr !== undefined) {
|
|
16
|
-
throw new HonuaQueryPlanningError("unsupported-query", "WFS planning cannot use outSr to label input filter coordinates; stamp the input geometry through the typed WFS escape hatch");
|
|
17
|
-
}
|
|
18
|
-
// Keep this aligned with the current WFS adapter's reviewed default. A
|
|
19
|
-
// vendor-specific geometry property requires the typed WFS escape hatch
|
|
20
|
-
// until discovery carries that binding into both planner and executor.
|
|
21
|
-
const geometryProperty = "the_geom";
|
|
22
|
-
const filters = [];
|
|
23
|
-
if (query.where) {
|
|
24
|
-
const where = compileWhere(query.where.expression);
|
|
25
|
-
if (where === UNSUPPORTED_FES) {
|
|
26
|
-
throw new HonuaQueryPlanningError("unsupported-query", "The where clause is not expressible as FES 2.0");
|
|
27
|
-
}
|
|
28
|
-
if (where.kind !== "and" || where.operands.length > 0)
|
|
29
|
-
filters.push(where);
|
|
30
|
-
}
|
|
31
|
-
if (query.spatialFilter) {
|
|
32
|
-
const spatial = compileSpatialFilter({
|
|
33
|
-
geometry: query.spatialFilter.geometry,
|
|
34
|
-
geometryType: query.spatialFilter.geometryType,
|
|
35
|
-
...(query.spatialFilter.spatialRel ? { spatialRel: query.spatialFilter.spatialRel } : {}),
|
|
36
|
-
}, {
|
|
37
|
-
geometryProperty,
|
|
38
|
-
});
|
|
39
|
-
if (spatial === UNSUPPORTED_FES) {
|
|
40
|
-
throw new HonuaQueryPlanningError("unsupported-query", "The spatial predicate is not expressible as FES 2.0");
|
|
41
|
-
}
|
|
42
|
-
filters.push(spatial);
|
|
43
|
-
}
|
|
44
|
-
let propertyName;
|
|
45
|
-
if (query.outFields && query.outFields.length > 0) {
|
|
46
|
-
const fields = [...query.outFields];
|
|
47
|
-
if (query.returnGeometry === false && fields.includes(geometryProperty)) {
|
|
48
|
-
throw new HonuaQueryPlanningError("unsupported-query", `WFS returnGeometry=false conflicts with outFields containing the geometry property "${geometryProperty}"`);
|
|
49
|
-
}
|
|
50
|
-
if (query.returnGeometry !== false && !fields.includes(geometryProperty))
|
|
51
|
-
fields.push(geometryProperty);
|
|
52
|
-
propertyName = fields;
|
|
53
|
-
}
|
|
54
|
-
else if (query.returnGeometry === false) {
|
|
55
|
-
throw new HonuaQueryPlanningError("unsupported-query", "WFS returnGeometry=false requires explicit outFields because propertyName cannot otherwise suppress geometry exactly");
|
|
56
|
-
}
|
|
57
|
-
return {
|
|
58
|
-
compiler: "wfs-2.0-get-feature-v1",
|
|
59
|
-
typeName: source.typeName,
|
|
60
|
-
...(filters.length > 0 ? { filter: serializeFes(filters, { typeName: source.typeName }) } : {}),
|
|
61
|
-
...(propertyName ? { propertyName } : {}),
|
|
62
|
-
...(query.orderBy && query.orderBy.length > 0
|
|
63
|
-
? {
|
|
64
|
-
sortBy: query.orderBy.map((sort) => `${sort.field} ${sort.direction === "desc" ? "DESC" : "ASC"}`).join(","),
|
|
65
|
-
}
|
|
66
|
-
: {}),
|
|
67
|
-
...(query.pagination?.offset !== undefined ? { startIndex: query.pagination.offset } : {}),
|
|
68
|
-
...(query.pagination?.limit !== undefined ? { count: query.pagination.limit } : {}),
|
|
69
|
-
...(query.outSr !== undefined ? { srsName: String(query.outSr) } : {}),
|
|
70
|
-
};
|
|
71
|
-
}
|
package/react/honua-map.d.ts
CHANGED
|
@@ -45,7 +45,9 @@ export interface HonuaMapProps {
|
|
|
45
45
|
map?: MaplibreMap;
|
|
46
46
|
/**
|
|
47
47
|
* The `maplibre-gl` module. Provide it to avoid a dynamic import (and to pin
|
|
48
|
-
* the exact version).
|
|
48
|
+
* the exact version). MapLibre 6 bundler hosts must call the module's
|
|
49
|
+
* `setWorkerUrl` before rendering; see `docs/react.md`. Ignored when
|
|
50
|
+
* {@link map} is supplied.
|
|
49
51
|
*/
|
|
50
52
|
mapLibre?: MapLibreGlModule;
|
|
51
53
|
/**
|
package/react/honua-map.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"honua-map.d.ts","sourceRoot":"","sources":["../../../src/react/honua-map.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOhH,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,KAAK,OAAO,EAAE,kBAAkB,KAAK,WAAW,GAAG;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,CAAC;IAC3E,KAAK,EAAE,KAAK,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;CAC3D;
|
|
1
|
+
{"version":3,"file":"honua-map.d.ts","sourceRoot":"","sources":["../../../src/react/honua-map.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOhH,oFAAoF;AACpF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,KAAK,OAAO,EAAE,kBAAkB,KAAK,WAAW,GAAG;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,CAAC;IAC3E,KAAK,EAAE,KAAK,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;CAC3D;AAiBD,kCAAkC;AAClC,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,OAAO,EAAE,eAAe,CAAC;IACzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5D;;;;OAIG;IACH,WAAW,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IACpD,wCAAwC;IACxC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC/C,uDAAuD;IACvD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAwGxD"}
|
package/react/honua-map.js
CHANGED
|
@@ -18,6 +18,16 @@ import { loadMapPackage } from "../runtime/index.js";
|
|
|
18
18
|
import { HonuaMapContext } from "./context.js";
|
|
19
19
|
import { HonuaExternalMapContext } from "./external-map.js";
|
|
20
20
|
import { useHonuaClient } from "./hooks.js";
|
|
21
|
+
function normalizeMapLibreGlModule(imported) {
|
|
22
|
+
const module = imported;
|
|
23
|
+
if (typeof module.Map === "function" && typeof module.Popup === "function") {
|
|
24
|
+
return module;
|
|
25
|
+
}
|
|
26
|
+
if (typeof module.default?.Map === "function" && typeof module.default.Popup === "function") {
|
|
27
|
+
return module.default;
|
|
28
|
+
}
|
|
29
|
+
throw new Error("maplibre-gl does not expose Map and Popup constructors; install maplibre-gl 5.x or 6.x.");
|
|
30
|
+
}
|
|
21
31
|
const EMPTY_STYLE = { version: 8, sources: {}, layers: [] };
|
|
22
32
|
/**
|
|
23
33
|
* Render a Honua-composed MapLibre map.
|
|
@@ -50,7 +60,7 @@ export function HonuaMap(props) {
|
|
|
50
60
|
const container = containerRef.current;
|
|
51
61
|
if (!container)
|
|
52
62
|
return;
|
|
53
|
-
gl = mapLibre ?? (await import("maplibre-gl"))
|
|
63
|
+
gl = mapLibre ?? normalizeMapLibreGlModule(await import("maplibre-gl"));
|
|
54
64
|
if (cancelled)
|
|
55
65
|
return;
|
|
56
66
|
ownedMap = new gl.Map({
|
package/react/hooks.d.ts
CHANGED
|
@@ -101,7 +101,7 @@ export interface UseQueryResult<T> extends QuerySnapshot<Result<T>> {
|
|
|
101
101
|
* ```tsx
|
|
102
102
|
* const { data, isLoading, error, refetch } = useQuery(
|
|
103
103
|
* dataset.source("incidents"),
|
|
104
|
-
* {
|
|
104
|
+
* { pagination: { limit: 100 }, returnGeometry: true },
|
|
105
105
|
* );
|
|
106
106
|
* ```
|
|
107
107
|
*/
|
package/react/hooks.js
CHANGED
|
@@ -91,7 +91,7 @@ export function useDataset(options) {
|
|
|
91
91
|
* ```tsx
|
|
92
92
|
* const { data, isLoading, error, refetch } = useQuery(
|
|
93
93
|
* dataset.source("incidents"),
|
|
94
|
-
* {
|
|
94
|
+
* { pagination: { limit: 100 }, returnGeometry: true },
|
|
95
95
|
* );
|
|
96
96
|
* ```
|
|
97
97
|
*/
|
package/react/selection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/react/selection.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/react/selection.tsx"],"names":[],"mappings":"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"}
|
package/react/selection.js
CHANGED
|
Binary file
|
|
@@ -57,7 +57,7 @@ export interface UseMountedSourceResult<T = Record<string, unknown>> {
|
|
|
57
57
|
* @example
|
|
58
58
|
* ```tsx
|
|
59
59
|
* const { diagnostics, error } = useMountedSource(map, source, {
|
|
60
|
-
* query: {
|
|
60
|
+
* query: { pagination: { limit: 500 } },
|
|
61
61
|
* hover: true,
|
|
62
62
|
* onDiagnostics: (d) => console.log(d.strategy, d.featureCount),
|
|
63
63
|
* });
|
|
@@ -161,7 +161,7 @@ function applyRendererDiff(map, handle, previous, next) {
|
|
|
161
161
|
* @example
|
|
162
162
|
* ```tsx
|
|
163
163
|
* const { diagnostics, error } = useMountedSource(map, source, {
|
|
164
|
-
* query: {
|
|
164
|
+
* query: { pagination: { limit: 500 } },
|
|
165
165
|
* hover: true,
|
|
166
166
|
* onDiagnostics: (d) => console.log(d.strategy, d.featureCount),
|
|
167
167
|
* });
|