@honua/react 0.1.2-beta.0 → 0.1.7-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 +88 -19
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +4 -0
- package/contract/widget-source.d.ts.map +1 -1
- package/core/client.d.ts +51 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +234 -54
- package/core/error-classifications.d.ts +23 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +23 -0
- package/core/error-code-registry.d.ts +24 -1
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +23 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +2 -2
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +69 -5
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +327 -10
- 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 +32 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +158 -23
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +138 -11
- 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/interactions/declarative-contract.d.ts +149 -0
- package/interactions/declarative-contract.d.ts.map +1 -0
- package/interactions/declarative-contract.js +293 -0
- package/interactions/declarative.d.ts +198 -0
- package/interactions/declarative.d.ts.map +1 -0
- package/interactions/declarative.js +470 -0
- package/interactions/feature-state.d.ts +7 -0
- package/interactions/feature-state.d.ts.map +1 -1
- package/interactions/feature-state.js +10 -2
- 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/maplibre-target.js +1 -1
- 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 +153 -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/runtime/style-compose.d.ts.map +1 -1
- package/runtime/style-compose.js +78 -9
- 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
package/core/surfaces.js
CHANGED
|
@@ -774,33 +774,15 @@ export class HonuaOgcFeatures {
|
|
|
774
774
|
return this.client.listOgcItems({ ...request, ...(layout ? { layout } : {}) });
|
|
775
775
|
}
|
|
776
776
|
async itemsAll(request) {
|
|
777
|
-
const pageSize = normalizePageSize(request.pageSize, request.limit);
|
|
778
|
-
const maxPages = normalizeMaxPages(request.maxPages);
|
|
779
|
-
const offset = normalizeOffset(request.offset);
|
|
780
777
|
const totalLimit = normalizeTotalLimit(request.limit);
|
|
781
778
|
const features = [];
|
|
782
|
-
for (
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
const limit = Math.min(pageSize, remainingLimit);
|
|
791
|
-
const response = await this.items({
|
|
792
|
-
...request,
|
|
793
|
-
limit,
|
|
794
|
-
offset: offset + page * pageSize,
|
|
795
|
-
});
|
|
796
|
-
const pageFeatures = extractOgcFeatures(response);
|
|
797
|
-
if (pageFeatures.length === 0) {
|
|
798
|
-
break;
|
|
799
|
-
}
|
|
800
|
-
features.push(...pageFeatures);
|
|
801
|
-
if (pageFeatures.length < limit) {
|
|
802
|
-
break;
|
|
803
|
-
}
|
|
779
|
+
for await (const page of drainOgcItemPages((pageRequest) => this.items(withOgcItemsPage(request, pageRequest)), {
|
|
780
|
+
pageSize: normalizePageSize(request.pageSize, request.limit),
|
|
781
|
+
maxPages: normalizeMaxPages(request.maxPages),
|
|
782
|
+
startOffset: normalizeOffset(request.offset),
|
|
783
|
+
...(totalLimit !== undefined ? { totalLimit } : {}),
|
|
784
|
+
})) {
|
|
785
|
+
features.push(...page);
|
|
804
786
|
}
|
|
805
787
|
if (totalLimit !== undefined && features.length > totalLimit) {
|
|
806
788
|
return features.slice(0, totalLimit);
|
|
@@ -865,33 +847,15 @@ export class HonuaOgcFeatureCollection {
|
|
|
865
847
|
});
|
|
866
848
|
}
|
|
867
849
|
async itemsAll(request = {}) {
|
|
868
|
-
const pageSize = normalizePageSize(request.pageSize, request.limit);
|
|
869
|
-
const maxPages = normalizeMaxPages(request.maxPages);
|
|
870
|
-
const offset = normalizeOffset(request.offset);
|
|
871
850
|
const totalLimit = normalizeTotalLimit(request.limit);
|
|
872
851
|
const features = [];
|
|
873
|
-
for (
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
}
|
|
881
|
-
const limit = Math.min(pageSize, remainingLimit);
|
|
882
|
-
const response = await this.items({
|
|
883
|
-
...request,
|
|
884
|
-
limit,
|
|
885
|
-
offset: offset + page * pageSize,
|
|
886
|
-
});
|
|
887
|
-
const pageFeatures = extractOgcFeatures(response);
|
|
888
|
-
if (pageFeatures.length === 0) {
|
|
889
|
-
break;
|
|
890
|
-
}
|
|
891
|
-
features.push(...pageFeatures);
|
|
892
|
-
if (pageFeatures.length < limit) {
|
|
893
|
-
break;
|
|
894
|
-
}
|
|
852
|
+
for await (const page of drainOgcItemPages((pageRequest) => this.items(withOgcItemsPage(request, pageRequest)), {
|
|
853
|
+
pageSize: normalizePageSize(request.pageSize, request.limit),
|
|
854
|
+
maxPages: normalizeMaxPages(request.maxPages),
|
|
855
|
+
startOffset: normalizeOffset(request.offset),
|
|
856
|
+
...(totalLimit !== undefined ? { totalLimit } : {}),
|
|
857
|
+
})) {
|
|
858
|
+
features.push(...page);
|
|
895
859
|
}
|
|
896
860
|
if (totalLimit !== undefined && features.length > totalLimit) {
|
|
897
861
|
return features.slice(0, totalLimit);
|
|
@@ -899,24 +863,13 @@ export class HonuaOgcFeatureCollection {
|
|
|
899
863
|
return features;
|
|
900
864
|
}
|
|
901
865
|
async *itemsStream(request = {}) {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
offset: offset + page * pageSize,
|
|
910
|
-
});
|
|
911
|
-
const pageFeatures = extractOgcFeatures(response);
|
|
912
|
-
if (pageFeatures.length === 0) {
|
|
913
|
-
break;
|
|
914
|
-
}
|
|
915
|
-
yield pageFeatures;
|
|
916
|
-
if (pageFeatures.length < pageSize) {
|
|
917
|
-
break;
|
|
918
|
-
}
|
|
919
|
-
}
|
|
866
|
+
// The stream yields every page the drain produces; `limit` selects the
|
|
867
|
+
// page size here (as it always has) rather than capping the total.
|
|
868
|
+
yield* drainOgcItemPages((pageRequest) => this.items(withOgcItemsPage(request, pageRequest)), {
|
|
869
|
+
pageSize: normalizePageSize(request.pageSize, request.limit),
|
|
870
|
+
maxPages: normalizeMaxPages(request.maxPages),
|
|
871
|
+
startOffset: normalizeOffset(request.offset),
|
|
872
|
+
});
|
|
920
873
|
}
|
|
921
874
|
async item(request) {
|
|
922
875
|
const layout = await this.layout();
|
|
@@ -1974,6 +1927,258 @@ function normalizeTotalLimit(limit) {
|
|
|
1974
1927
|
}
|
|
1975
1928
|
return limit;
|
|
1976
1929
|
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Query-string keys on an OGC API Features `rel="next"` link that must not be
|
|
1932
|
+
* replayed on the follow-up request: the drain owns the page size (`limit`)
|
|
1933
|
+
* and the caller owns the response format (`f`). Every other param on the
|
|
1934
|
+
* link — `offset` / `startindex` on an offset server, an opaque
|
|
1935
|
+
* `token` / `cursor` / `next` on a cursor server — is the server's own paging
|
|
1936
|
+
* state and is echoed back verbatim, subject to the stale-offset rules in
|
|
1937
|
+
* {@link ogcCursorFromHref}.
|
|
1938
|
+
*/
|
|
1939
|
+
const OGC_NEXT_LINK_RESERVED_PARAMS = new Set(["f", "limit"]);
|
|
1940
|
+
/**
|
|
1941
|
+
* Params that express a numeric start position. Compared case-insensitively:
|
|
1942
|
+
* `offset` is Honua Server's spelling, `startindex` / `startIndex` the OGC API
|
|
1943
|
+
* spelling servers vary the casing of.
|
|
1944
|
+
*/
|
|
1945
|
+
const OGC_OFFSET_PARAM_NAMES = new Set(["offset", "startindex"]);
|
|
1946
|
+
/**
|
|
1947
|
+
* Params that express an opaque paging cursor. Matched case-insensitively with
|
|
1948
|
+
* `-` / `_` stripped, so `page_token` and `pageToken` both hit. When one of
|
|
1949
|
+
* these drives the next link, the token owns the read position and any
|
|
1950
|
+
* `offset` / `startindex` on the same link is a stale echo of the request the
|
|
1951
|
+
* server just answered.
|
|
1952
|
+
*/
|
|
1953
|
+
const OGC_CURSOR_PARAM_NAMES = new Set([
|
|
1954
|
+
"token",
|
|
1955
|
+
"nexttoken",
|
|
1956
|
+
"pagetoken",
|
|
1957
|
+
"continuationtoken",
|
|
1958
|
+
"resumptiontoken",
|
|
1959
|
+
"cursor",
|
|
1960
|
+
"next",
|
|
1961
|
+
"page",
|
|
1962
|
+
"searchafter",
|
|
1963
|
+
"scroll",
|
|
1964
|
+
"scrollid",
|
|
1965
|
+
]);
|
|
1966
|
+
/** Base used only to parse relative `rel="next"` hrefs; never requested. */
|
|
1967
|
+
const OGC_NEXT_LINK_PARSE_BASE = "https://placeholder.test";
|
|
1968
|
+
/**
|
|
1969
|
+
* Page `/items` the way OGC API Features Core specifies: follow the
|
|
1970
|
+
* `rel="next"` link the server returns, and only fall back to `limit`/`offset`
|
|
1971
|
+
* arithmetic when the response advertises no usable next link. Offset
|
|
1972
|
+
* arithmetic alone silently mis-pages every server that pages by opaque token
|
|
1973
|
+
* or cursor (pgstac-backed APIs, several pygeoapi deployments): the cursor is
|
|
1974
|
+
* dropped, so pages repeat or skip with no error.
|
|
1975
|
+
*
|
|
1976
|
+
* Anti-corruption invariants, preserved on both paths:
|
|
1977
|
+
* - an empty page ends the drain;
|
|
1978
|
+
* - a page whose feature identity repeats an already-yielded page is dropped
|
|
1979
|
+
* and ends the drain, so a looping server can never duplicate features;
|
|
1980
|
+
* - a `rel="next"` link that repeats a cursor already followed is treated as
|
|
1981
|
+
* a stalled pager and ends the drain;
|
|
1982
|
+
* - a stale `offset` / `startindex` echoed on a cursor link never reaches the
|
|
1983
|
+
* wire beside the cursor (see {@link ogcCursorFromHref});
|
|
1984
|
+
* - `maxPages` still caps the total number of requests.
|
|
1985
|
+
*
|
|
1986
|
+
* On the link-driven path a short page is deliberately *not* a stop signal:
|
|
1987
|
+
* OGC API Features permits a server to return fewer than `limit` items on a
|
|
1988
|
+
* non-final page while still advertising `rel="next"` (the same tolerance the
|
|
1989
|
+
* Records drain applies). On the offset path a short page still ends the
|
|
1990
|
+
* drain, as it always has.
|
|
1991
|
+
*/
|
|
1992
|
+
async function* drainOgcItemPages(fetchPage, options) {
|
|
1993
|
+
const { pageSize, maxPages, startOffset, totalLimit } = options;
|
|
1994
|
+
const seenCursorKeys = new Set();
|
|
1995
|
+
const seenPageKeys = new Set();
|
|
1996
|
+
let cursor;
|
|
1997
|
+
let emitted = 0;
|
|
1998
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
1999
|
+
const remaining = totalLimit === undefined ? pageSize : Math.max(0, totalLimit - emitted);
|
|
2000
|
+
if (remaining < 1) {
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
const limit = Math.min(pageSize, remaining);
|
|
2004
|
+
// A server cursor carries its own position; re-sending the computed offset
|
|
2005
|
+
// alongside it is what makes token pagers skip rows.
|
|
2006
|
+
const sentOffset = cursor === undefined ? startOffset + page * pageSize : undefined;
|
|
2007
|
+
const response = await fetchPage({
|
|
2008
|
+
limit,
|
|
2009
|
+
offset: sentOffset,
|
|
2010
|
+
cursorParams: cursor?.params,
|
|
2011
|
+
});
|
|
2012
|
+
const pageFeatures = extractOgcFeatures(response);
|
|
2013
|
+
if (pageFeatures.length === 0) {
|
|
2014
|
+
break;
|
|
2015
|
+
}
|
|
2016
|
+
const pageKey = ogcPageIdentityKey(pageFeatures);
|
|
2017
|
+
if (pageKey !== undefined) {
|
|
2018
|
+
if (seenPageKeys.has(pageKey)) {
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
seenPageKeys.add(pageKey);
|
|
2022
|
+
}
|
|
2023
|
+
yield pageFeatures;
|
|
2024
|
+
emitted += pageFeatures.length;
|
|
2025
|
+
const next = ogcNextItemsCursor(response.links, sentOffset);
|
|
2026
|
+
if (next !== undefined) {
|
|
2027
|
+
if (seenCursorKeys.has(next.key)) {
|
|
2028
|
+
break;
|
|
2029
|
+
}
|
|
2030
|
+
seenCursorKeys.add(next.key);
|
|
2031
|
+
cursor = next;
|
|
2032
|
+
continue;
|
|
2033
|
+
}
|
|
2034
|
+
if (cursor !== undefined) {
|
|
2035
|
+
// Link-driven drain and the server stopped advertising a next link:
|
|
2036
|
+
// that is the spec's end-of-results signal.
|
|
2037
|
+
break;
|
|
2038
|
+
}
|
|
2039
|
+
if (pageFeatures.length < limit) {
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
/**
|
|
2045
|
+
* Merge one {@link drainOgcItemPages} page request onto the caller's request.
|
|
2046
|
+
* Cursor params ride on `extraParams`, which the OGC wire layer serializes
|
|
2047
|
+
* before the typed fields, so the caller's `filter` / `bbox` / `crs` still win
|
|
2048
|
+
* and only the paging state comes from the server.
|
|
2049
|
+
*/
|
|
2050
|
+
function withOgcItemsPage(request, page) {
|
|
2051
|
+
return {
|
|
2052
|
+
...request,
|
|
2053
|
+
limit: page.limit,
|
|
2054
|
+
offset: page.offset,
|
|
2055
|
+
...(page.cursorParams ? { extraParams: { ...request.extraParams, ...page.cursorParams } } : {}),
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Resolve the server's next-page cursor from an `/items` response. Only the
|
|
2060
|
+
* link's query params are replayed (not its host or path), so a next link
|
|
2061
|
+
* rewritten by a proxy — or emitted with the server's internal hostname —
|
|
2062
|
+
* still pages correctly. Returns `undefined` when no `rel="next"` link carries
|
|
2063
|
+
* usable paging state, which is what selects the offset fallback.
|
|
2064
|
+
*
|
|
2065
|
+
* @param sentOffset the `offset` sent for the page that produced these links,
|
|
2066
|
+
* or `undefined` when a cursor already drove that request. Used to spot an
|
|
2067
|
+
* `offset` on the link that merely echoes the request just answered.
|
|
2068
|
+
*/
|
|
2069
|
+
function ogcNextItemsCursor(links, sentOffset) {
|
|
2070
|
+
if (!links) {
|
|
2071
|
+
return undefined;
|
|
2072
|
+
}
|
|
2073
|
+
for (const link of links) {
|
|
2074
|
+
if (link.rel !== "next" || typeof link.href !== "string") {
|
|
2075
|
+
continue;
|
|
2076
|
+
}
|
|
2077
|
+
// An HTML alternate of the next page carries the same cursor but is not
|
|
2078
|
+
// the representation we are draining; prefer a data link when both exist.
|
|
2079
|
+
if (typeof link.type === "string" && link.type.includes("html")) {
|
|
2080
|
+
continue;
|
|
2081
|
+
}
|
|
2082
|
+
const cursor = ogcCursorFromHref(link.href, sentOffset);
|
|
2083
|
+
if (cursor !== undefined) {
|
|
2084
|
+
return cursor;
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
return undefined;
|
|
2088
|
+
}
|
|
2089
|
+
/** Fold a query-param name to its comparison form (case / `-` / `_` insensitive). */
|
|
2090
|
+
function ogcParamKey(name) {
|
|
2091
|
+
let folded = "";
|
|
2092
|
+
for (const char of name) {
|
|
2093
|
+
if (char === "-" || char === "_")
|
|
2094
|
+
continue;
|
|
2095
|
+
folded += char.toLowerCase();
|
|
2096
|
+
}
|
|
2097
|
+
return folded;
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Lift the paging state off one `rel="next"` href.
|
|
2101
|
+
*
|
|
2102
|
+
* Servers routinely build the next link by preserving the query string of the
|
|
2103
|
+
* request they just answered and appending their cursor, so the link can carry
|
|
2104
|
+
* both a stale `offset=0` and a live `token=…`. Replaying both is exactly the
|
|
2105
|
+
* mis-paging this drain exists to prevent — a server that honors `offset`
|
|
2106
|
+
* alongside its own token re-reads or skips a page. Two rules keep the two
|
|
2107
|
+
* paging styles apart:
|
|
2108
|
+
*
|
|
2109
|
+
* 1. an opaque cursor on the link (`token`, `cursor`, `next`, `page`, …) owns
|
|
2110
|
+
* the read position, so every `offset` / `startindex` on that link is
|
|
2111
|
+
* dropped;
|
|
2112
|
+
* 2. otherwise an `offset` / `startindex` that merely repeats the offset just
|
|
2113
|
+
* sent cannot advance the drain, so it is dropped too — and if that leaves
|
|
2114
|
+
* the link with nothing, the drain falls back to offset arithmetic.
|
|
2115
|
+
*
|
|
2116
|
+
* A genuine offset link (`offset=10` after requesting `offset=0`) is kept and
|
|
2117
|
+
* drives the next page, which is what pygeoapi / ldproxy deployments emit.
|
|
2118
|
+
*/
|
|
2119
|
+
function ogcCursorFromHref(href, sentOffset) {
|
|
2120
|
+
let url;
|
|
2121
|
+
try {
|
|
2122
|
+
url = new URL(href, OGC_NEXT_LINK_PARSE_BASE);
|
|
2123
|
+
}
|
|
2124
|
+
catch {
|
|
2125
|
+
return undefined;
|
|
2126
|
+
}
|
|
2127
|
+
const candidates = [];
|
|
2128
|
+
let hasOpaqueCursor = false;
|
|
2129
|
+
for (const [key, value] of url.searchParams) {
|
|
2130
|
+
if (OGC_NEXT_LINK_RESERVED_PARAMS.has(key)) {
|
|
2131
|
+
continue;
|
|
2132
|
+
}
|
|
2133
|
+
if (OGC_CURSOR_PARAM_NAMES.has(ogcParamKey(key))) {
|
|
2134
|
+
hasOpaqueCursor = true;
|
|
2135
|
+
}
|
|
2136
|
+
candidates.push([key, value]);
|
|
2137
|
+
}
|
|
2138
|
+
const params = {};
|
|
2139
|
+
let hasPagingState = false;
|
|
2140
|
+
for (const [key, value] of candidates) {
|
|
2141
|
+
const folded = ogcParamKey(key);
|
|
2142
|
+
if (OGC_OFFSET_PARAM_NAMES.has(folded)) {
|
|
2143
|
+
if (hasOpaqueCursor) {
|
|
2144
|
+
continue;
|
|
2145
|
+
}
|
|
2146
|
+
if (sentOffset !== undefined && Number(value) === sentOffset) {
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
hasPagingState = true;
|
|
2150
|
+
}
|
|
2151
|
+
else if (OGC_CURSOR_PARAM_NAMES.has(folded)) {
|
|
2152
|
+
hasPagingState = true;
|
|
2153
|
+
}
|
|
2154
|
+
params[key] = value;
|
|
2155
|
+
}
|
|
2156
|
+
// Everything that survived is an echo of the query we just sent (`bbox`,
|
|
2157
|
+
// `filter`, `sortby`, …): the link advertises no forward progress, so the
|
|
2158
|
+
// offset arithmetic below stays in charge rather than re-reading this page.
|
|
2159
|
+
if (!hasPagingState) {
|
|
2160
|
+
return undefined;
|
|
2161
|
+
}
|
|
2162
|
+
const entries = Object.entries(params).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
2163
|
+
return { key: entries.map(([key, value]) => `${key}=${value}`).join("&"), params };
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* Cheap identity signature for one `/items` page, used to detect a server that
|
|
2167
|
+
* replays a page it already returned. Returns `undefined` when any feature
|
|
2168
|
+
* lacks a GeoJSON `id`, in which case the drain simply skips the check rather
|
|
2169
|
+
* than serializing whole geometries.
|
|
2170
|
+
*/
|
|
2171
|
+
function ogcPageIdentityKey(features) {
|
|
2172
|
+
const ids = [];
|
|
2173
|
+
for (const feature of features) {
|
|
2174
|
+
const id = feature?.id;
|
|
2175
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
2176
|
+
return undefined;
|
|
2177
|
+
}
|
|
2178
|
+
ids.push(String(id));
|
|
2179
|
+
}
|
|
2180
|
+
return JSON.stringify(ids);
|
|
2181
|
+
}
|
|
1977
2182
|
function isFinitePositiveInteger(value) {
|
|
1978
2183
|
return typeof value === "number" && Number.isFinite(value) && Math.trunc(value) > 0;
|
|
1979
2184
|
}
|
package/core/types.d.ts
CHANGED
|
@@ -540,9 +540,33 @@ export interface HonuaClientOptions {
|
|
|
540
540
|
transport?: HonuaTransport;
|
|
541
541
|
}
|
|
542
542
|
export interface HonuaRetryOptions {
|
|
543
|
+
/**
|
|
544
|
+
* Maximum number of transient-failure retry attempts after the initial
|
|
545
|
+
* request. Retry is entirely opt-in: values below `1` (including the default
|
|
546
|
+
* `0`) disable the retry loop, so no status, network, or timeout failure is
|
|
547
|
+
* replayed.
|
|
548
|
+
*
|
|
549
|
+
* This option does not govern the authentication replay. When an
|
|
550
|
+
* {@link HonuaClientOptions.auth} provider is configured, a replay-safe
|
|
551
|
+
* request (`GET` / `HEAD` / `PUT` / `DELETE`) answered with `401` or `403` is
|
|
552
|
+
* still reissued once after a forced credential refresh, even with retries
|
|
553
|
+
* disabled. Instrumentation that counts requests should expect that one extra
|
|
554
|
+
* attempt.
|
|
555
|
+
*/
|
|
543
556
|
maxRetries?: number;
|
|
557
|
+
/** First backoff delay in milliseconds; doubles per attempt. Default: `100`. */
|
|
544
558
|
baseDelayMs?: number;
|
|
559
|
+
/** Upper bound on any single backoff delay, including a server `Retry-After`. Default: `2000`. */
|
|
545
560
|
maxDelayMs?: number;
|
|
561
|
+
/**
|
|
562
|
+
* HTTP statuses the loop replays on replay-safe methods
|
|
563
|
+
* (`GET` / `HEAD` / `PUT` / `DELETE`). Default: `[429, 502, 503, 504]` — the
|
|
564
|
+
* statuses that explicitly invite the same request again. This is
|
|
565
|
+
* intentionally narrower than the broader `408, 429, 500, 502, 503, 504` set
|
|
566
|
+
* that {@link HonuaHttpError} classifies as transient `retryable` metadata:
|
|
567
|
+
* that classification is descriptive and never initiates a retry. Pass the
|
|
568
|
+
* broader set here to opt into replaying `408` / `500`.
|
|
569
|
+
*/
|
|
546
570
|
retryStatuses?: readonly number[];
|
|
547
571
|
}
|
|
548
572
|
export interface HonuaCompatibilityRequest {
|
|
@@ -997,6 +1021,8 @@ export interface HonuaLayerMetadata {
|
|
|
997
1021
|
/** Whether GeoServices coordinates include a measure ordinate. */
|
|
998
1022
|
hasM?: boolean;
|
|
999
1023
|
description?: string;
|
|
1024
|
+
/** Attribution text advertised by the GeoServices layer. */
|
|
1025
|
+
copyrightText?: string;
|
|
1000
1026
|
fields?: HonuaFieldInfo[];
|
|
1001
1027
|
objectIdField?: string;
|
|
1002
1028
|
globalIdField?: string;
|
|
@@ -1118,6 +1144,17 @@ export interface HonuaOgcLink {
|
|
|
1118
1144
|
rel?: string;
|
|
1119
1145
|
type?: string;
|
|
1120
1146
|
title?: string;
|
|
1147
|
+
/**
|
|
1148
|
+
* HTTP method the link target expects. STAC API uses it on the landing
|
|
1149
|
+
* page (`rel="search"` advertised for `GET` and/or `POST`) and on
|
|
1150
|
+
* pagination links (a `POST` `rel="next"` carries its cursor in `body`
|
|
1151
|
+
* rather than on the href query string).
|
|
1152
|
+
*/
|
|
1153
|
+
method?: string;
|
|
1154
|
+
/** Request-body members a `POST` link contributes to the next request. */
|
|
1155
|
+
body?: Record<string, unknown>;
|
|
1156
|
+
/** When true, `body` merges over the originating request body. */
|
|
1157
|
+
merge?: boolean;
|
|
1121
1158
|
}
|
|
1122
1159
|
/** Response from the OGC API landing page (`/ogc/features`). */
|
|
1123
1160
|
export interface HonuaOgcLandingResponse {
|
|
@@ -1363,12 +1400,21 @@ export interface HonuaOgcProcessJobStatus {
|
|
|
1363
1400
|
};
|
|
1364
1401
|
}
|
|
1365
1402
|
/**
|
|
1366
|
-
* Process-execution request envelope
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1403
|
+
* Process-execution request envelope for `POST /processes/{id}/execution`
|
|
1404
|
+
* (OGC API — Processes Part 1: Core §7.11).
|
|
1405
|
+
*
|
|
1406
|
+
* `mode` selects the RFC 7240 preference the SDK sends:
|
|
1407
|
+
*
|
|
1408
|
+
* - `"async"` → `Prefer: respond-async`. A conformant server answers `201` with
|
|
1409
|
+
* a `Location` header and a `statusInfo` body.
|
|
1410
|
+
* - `"sync"` → no `Prefer` header, and the caller asserts the process declares
|
|
1411
|
+
* `sync-execute`. A conformant server answers `200` with the results document.
|
|
1412
|
+
* - `"auto"` (default) → no `Prefer` header; whichever shape the server returns
|
|
1413
|
+
* is adapted onto the same `IJobRun` surface.
|
|
1414
|
+
*
|
|
1415
|
+
* Core defines no header that *forces* synchronous execution, so `"sync"` is a
|
|
1416
|
+
* preference plus a capability assertion, never a guarantee: a server that
|
|
1417
|
+
* answers a `"sync"` request with a job still yields a pollable `IJobRun`.
|
|
1372
1418
|
*/
|
|
1373
1419
|
export interface OgcProcessExecuteRequest {
|
|
1374
1420
|
processId: string;
|
|
@@ -1379,19 +1425,76 @@ export interface OgcProcessExecuteRequest {
|
|
|
1379
1425
|
mediaType?: string;
|
|
1380
1426
|
};
|
|
1381
1427
|
}>;
|
|
1382
|
-
/**
|
|
1383
|
-
mode?: "async" | "auto";
|
|
1428
|
+
/** Execution preference; see the interface docs. Defaults to `"auto"`. */
|
|
1429
|
+
mode?: "sync" | "async" | "auto";
|
|
1430
|
+
/**
|
|
1431
|
+
* The process's advertised `jobControlOptions` (from `describe()` or a
|
|
1432
|
+
* discovery snapshot). Supplied — or already memoized from a `describe()` on
|
|
1433
|
+
* the same handle — it lets `mode` be gated against what the process actually
|
|
1434
|
+
* declares, so an undeclared `sync-execute` / `async-execute` fails closed with
|
|
1435
|
+
* `HonuaCapabilityNotSupportedError` instead of being posted blindly.
|
|
1436
|
+
*/
|
|
1437
|
+
jobControlOptions?: readonly string[];
|
|
1384
1438
|
headers?: HeadersInit;
|
|
1385
1439
|
signal?: AbortSignal;
|
|
1440
|
+
/**
|
|
1441
|
+
* Raw endpoint path prefix (defaults to the Honua facade `/ogc/processes`). A
|
|
1442
|
+
* raw third-party Processes service root discovered by `discoverOgcProcesses()`
|
|
1443
|
+
* threads its service-root path here so the execution route resolves against
|
|
1444
|
+
* the advertised layout instead of the facade.
|
|
1445
|
+
*/
|
|
1446
|
+
basePath?: string;
|
|
1386
1447
|
}
|
|
1387
|
-
/**
|
|
1448
|
+
/**
|
|
1449
|
+
* Request envelope for the OGC API Processes job routes (status, results,
|
|
1450
|
+
* dismiss). Carries the same `basePath` seam as the metadata requests so a job
|
|
1451
|
+
* created against a raw service root keeps polling that root.
|
|
1452
|
+
*/
|
|
1453
|
+
export interface OgcProcessJobRequest {
|
|
1454
|
+
jobId: string;
|
|
1455
|
+
signal?: AbortSignal;
|
|
1456
|
+
responseFormat?: string;
|
|
1457
|
+
extraParams?: Record<string, string | number | boolean>;
|
|
1458
|
+
/** Raw endpoint path prefix (defaults to the Honua facade `/ogc/processes`). */
|
|
1459
|
+
basePath?: string;
|
|
1460
|
+
/**
|
|
1461
|
+
* Server-advertised route for this job resource, already reduced to a
|
|
1462
|
+
* same-origin request path. When present it replaces the Core-templated
|
|
1463
|
+
* `{basePath}/jobs/{jobId}[/results]` route so the lifecycle follows the
|
|
1464
|
+
* server's own `Location` header and `links[]` rather than a guessed path.
|
|
1465
|
+
*/
|
|
1466
|
+
routePath?: string;
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Outcome of `POST /processes/{id}/execution`.
|
|
1470
|
+
*
|
|
1471
|
+
* The same envelope carries both Core response shapes so one typed surface
|
|
1472
|
+
* covers a raw third-party server and the Honua facade:
|
|
1473
|
+
*
|
|
1474
|
+
* - asynchronous — `jobID` names the created job and `synchronous` is `false`.
|
|
1475
|
+
* - synchronous — the server answered `200` with the results document inline.
|
|
1476
|
+
* `jobID` is `""` (Core assigns no job identifier to a synchronous
|
|
1477
|
+
* execution), `status` is `"successful"`, `synchronous` is `true`, and
|
|
1478
|
+
* `results` holds the document.
|
|
1479
|
+
*/
|
|
1388
1480
|
export interface HonuaOgcProcessJobAccepted {
|
|
1481
|
+
/** Server-assigned job id; `""` for a synchronous execution (no job exists). */
|
|
1389
1482
|
jobID: string;
|
|
1390
1483
|
status: OgcProcessStatus;
|
|
1391
1484
|
processID?: string;
|
|
1392
1485
|
links?: HonuaOgcLink[];
|
|
1393
1486
|
/** Initial (often `accepted` or `running`) status payload, when reported. */
|
|
1394
1487
|
statusInfo?: HonuaOgcProcessJobStatus;
|
|
1488
|
+
/**
|
|
1489
|
+
* Same-origin request path derived from the async `Location` header (or the
|
|
1490
|
+
* accepted document's `self` link). Polling follows it instead of templating
|
|
1491
|
+
* `{basePath}/jobs/{jobId}`.
|
|
1492
|
+
*/
|
|
1493
|
+
statusPath?: string;
|
|
1494
|
+
/** Results document, populated only when `synchronous` is `true`. */
|
|
1495
|
+
results?: HonuaOgcProcessJobResults;
|
|
1496
|
+
/** `true` when the server answered inline with the results document. */
|
|
1497
|
+
synchronous?: boolean;
|
|
1395
1498
|
}
|
|
1396
1499
|
/**
|
|
1397
1500
|
* Result document returned from `/jobs/{jobId}/results`. OGC API Processes
|
|
@@ -1408,7 +1511,7 @@ export interface StacSearchRequest {
|
|
|
1408
1511
|
intersects?: Record<string, unknown>;
|
|
1409
1512
|
ids?: readonly string[];
|
|
1410
1513
|
collections?: readonly string[];
|
|
1411
|
-
filter?: string
|
|
1514
|
+
filter?: string | Readonly<Record<string, unknown>>;
|
|
1412
1515
|
filterLang?: "cql2-text" | "cql2-json";
|
|
1413
1516
|
limit?: number;
|
|
1414
1517
|
/**
|
|
@@ -1422,15 +1525,34 @@ export interface StacSearchRequest {
|
|
|
1422
1525
|
* advertise an opaque `?next=…` token instead of `offset`.
|
|
1423
1526
|
*/
|
|
1424
1527
|
next?: string;
|
|
1528
|
+
/**
|
|
1529
|
+
* Opaque continuation query params captured verbatim from a server
|
|
1530
|
+
* `rel="next"` link whose cursor is neither `offset` nor `next` (pgstac /
|
|
1531
|
+
* stac-fastapi emit `?token=next:…`). Merged over the serialized search
|
|
1532
|
+
* params so the next page is requested exactly the way the server asked.
|
|
1533
|
+
*/
|
|
1534
|
+
nextParams?: Readonly<Record<string, string>>;
|
|
1535
|
+
/**
|
|
1536
|
+
* Opaque continuation body members captured from a `POST` `rel="next"`
|
|
1537
|
+
* link (`{ "method": "POST", "body": { "token": "next:…" }, "merge": true }`).
|
|
1538
|
+
* Merged over the serialized `POST /search` body.
|
|
1539
|
+
*/
|
|
1540
|
+
nextBody?: Readonly<Record<string, unknown>>;
|
|
1425
1541
|
/** Subset of asset / item properties to return. */
|
|
1426
1542
|
fields?: {
|
|
1427
1543
|
include?: readonly string[];
|
|
1428
1544
|
exclude?: readonly string[];
|
|
1429
1545
|
};
|
|
1430
|
-
sortby?: string;
|
|
1546
|
+
sortby?: string | readonly StacSortField[];
|
|
1431
1547
|
signal?: AbortSignal;
|
|
1432
1548
|
/** When `true`, the adapter posts the body to `/search`. */
|
|
1433
1549
|
usePost?: boolean;
|
|
1550
|
+
/**
|
|
1551
|
+
* When `false`, a failed first POST is surfaced instead of replayed as GET.
|
|
1552
|
+
* Dynamic workflow callers use this for an explicitly requested POST;
|
|
1553
|
+
* discovered `auto` POST support leaves fallback enabled.
|
|
1554
|
+
*/
|
|
1555
|
+
allowPostFallback?: boolean;
|
|
1434
1556
|
/**
|
|
1435
1557
|
* Path prefix the STAC endpoints are mounted under. Defaults to `/stac`
|
|
1436
1558
|
* (the Honua Server facade). Backend-agnostic callers pointing at a raw
|
|
@@ -1439,6 +1561,11 @@ export interface StacSearchRequest {
|
|
|
1439
1561
|
*/
|
|
1440
1562
|
stacBasePath?: string;
|
|
1441
1563
|
}
|
|
1564
|
+
/** Structured STAC Item Search sort expression, primarily for POST requests. */
|
|
1565
|
+
export interface StacSortField {
|
|
1566
|
+
readonly field: string;
|
|
1567
|
+
readonly direction: "asc" | "desc";
|
|
1568
|
+
}
|
|
1442
1569
|
/** One band declaration from the STAC Raster extension. */
|
|
1443
1570
|
export interface HonuaStacRasterBand extends Record<string, unknown> {
|
|
1444
1571
|
name?: string;
|