@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/surfaces.js
ADDED
|
@@ -0,0 +1,1322 @@
|
|
|
1
|
+
export class HonuaService {
|
|
2
|
+
client;
|
|
3
|
+
serviceId;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.client = options.client;
|
|
6
|
+
this.serviceId = options.serviceId;
|
|
7
|
+
}
|
|
8
|
+
featureLayer(layerId) {
|
|
9
|
+
return new HonuaFeatureLayer({
|
|
10
|
+
client: this.client,
|
|
11
|
+
serviceId: this.serviceId,
|
|
12
|
+
layerId,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
layer(layerId) {
|
|
16
|
+
return this.featureLayer(layerId);
|
|
17
|
+
}
|
|
18
|
+
async featureServiceMetadata(options = {}) {
|
|
19
|
+
return this.client.getFeatureServiceMetadata(this.serviceId, options);
|
|
20
|
+
}
|
|
21
|
+
async mapServiceMetadata(options = {}) {
|
|
22
|
+
return this.client.getMapServiceMetadata(this.serviceId, options);
|
|
23
|
+
}
|
|
24
|
+
async featureLayerIds() {
|
|
25
|
+
const metadata = await this.featureServiceMetadata();
|
|
26
|
+
return extractLayerIds(metadata);
|
|
27
|
+
}
|
|
28
|
+
async featureLayers() {
|
|
29
|
+
const ids = await this.featureLayerIds();
|
|
30
|
+
return ids.map((layerId) => new HonuaFeatureLayer({
|
|
31
|
+
client: this.client,
|
|
32
|
+
serviceId: this.serviceId,
|
|
33
|
+
layerId,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
async mapLayerIds() {
|
|
37
|
+
const metadata = await this.mapServiceMetadata();
|
|
38
|
+
return extractLayerIds(metadata);
|
|
39
|
+
}
|
|
40
|
+
async mapLayers() {
|
|
41
|
+
const ids = await this.mapLayerIds();
|
|
42
|
+
return ids.map((layerId) => new HonuaMapLayer({
|
|
43
|
+
client: this.client,
|
|
44
|
+
serviceId: this.serviceId,
|
|
45
|
+
layerId,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
async request(request) {
|
|
49
|
+
return this.client.request({
|
|
50
|
+
...request,
|
|
51
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}/${normalizeServicePath(request.path)}`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
mapService() {
|
|
55
|
+
return new HonuaMapService({
|
|
56
|
+
client: this.client,
|
|
57
|
+
serviceId: this.serviceId,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
mapLayer(layerId) {
|
|
61
|
+
return new HonuaMapLayer({
|
|
62
|
+
client: this.client,
|
|
63
|
+
serviceId: this.serviceId,
|
|
64
|
+
layerId,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export class HonuaFeatureLayer {
|
|
69
|
+
client;
|
|
70
|
+
serviceId;
|
|
71
|
+
layerId;
|
|
72
|
+
constructor(options) {
|
|
73
|
+
this.client = options.client;
|
|
74
|
+
this.serviceId = options.serviceId;
|
|
75
|
+
this.layerId = options.layerId;
|
|
76
|
+
}
|
|
77
|
+
async metadata(options = {}) {
|
|
78
|
+
return this.client.getLayerMetadata(this.serviceId, this.layerId, options);
|
|
79
|
+
}
|
|
80
|
+
createQuery() {
|
|
81
|
+
return {
|
|
82
|
+
where: "1=1",
|
|
83
|
+
outFields: ["*"],
|
|
84
|
+
returnGeometry: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async queryFeatures(request = {}) {
|
|
88
|
+
return this.client.queryFeatures({
|
|
89
|
+
serviceId: this.serviceId,
|
|
90
|
+
layerId: this.layerId,
|
|
91
|
+
...request,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async queryFeaturesAll(request = {}) {
|
|
95
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
96
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
97
|
+
: 2000;
|
|
98
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
99
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
100
|
+
: 100;
|
|
101
|
+
const startingOffset = normalizeOffset(request.resultOffset);
|
|
102
|
+
const features = [];
|
|
103
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
104
|
+
const response = await this.queryFeatures({
|
|
105
|
+
...request,
|
|
106
|
+
extraParams: {
|
|
107
|
+
...(request.extraParams ?? {}),
|
|
108
|
+
resultOffset: startingOffset + page * pageSize,
|
|
109
|
+
resultRecordCount: pageSize,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
const pageFeatures = response.features ?? [];
|
|
113
|
+
if (pageFeatures.length === 0) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
features.push(...pageFeatures);
|
|
117
|
+
if (pageFeatures.length < pageSize) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return features;
|
|
122
|
+
}
|
|
123
|
+
async *queryFeaturesStream(request = {}) {
|
|
124
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
125
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
126
|
+
: 2000;
|
|
127
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
128
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
129
|
+
: 100;
|
|
130
|
+
const startingOffset = normalizeOffset(request.resultOffset);
|
|
131
|
+
// Use server streaming RPC when gRPC-Web transport is active
|
|
132
|
+
if (this.client.isGrpcWeb) {
|
|
133
|
+
const { pageSize: _pageSize, maxPages: _maxPages, ...queryRequest } = request;
|
|
134
|
+
let pageCount = 0;
|
|
135
|
+
const stream = this.client.queryFeaturesStream({
|
|
136
|
+
serviceId: this.serviceId,
|
|
137
|
+
layerId: this.layerId,
|
|
138
|
+
...queryRequest,
|
|
139
|
+
resultRecordCount: queryRequest.resultRecordCount ?? pageSize,
|
|
140
|
+
});
|
|
141
|
+
for await (const page of stream) {
|
|
142
|
+
yield page;
|
|
143
|
+
pageCount += 1;
|
|
144
|
+
if (pageCount >= maxPages) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
151
|
+
const response = await this.queryFeatures({
|
|
152
|
+
...request,
|
|
153
|
+
extraParams: {
|
|
154
|
+
...(request.extraParams ?? {}),
|
|
155
|
+
resultOffset: startingOffset + page * pageSize,
|
|
156
|
+
resultRecordCount: pageSize,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
const pageFeatures = response.features ?? [];
|
|
160
|
+
if (pageFeatures.length === 0) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
yield pageFeatures;
|
|
164
|
+
if (pageFeatures.length < pageSize) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async queryFeatureCount(request = {}) {
|
|
170
|
+
const response = await this.client.queryFeatures({
|
|
171
|
+
serviceId: this.serviceId,
|
|
172
|
+
layerId: this.layerId,
|
|
173
|
+
where: request.where ?? "1=1",
|
|
174
|
+
returnGeometry: false,
|
|
175
|
+
outFields: "OBJECTID",
|
|
176
|
+
method: request.method,
|
|
177
|
+
extraParams: {
|
|
178
|
+
returnCountOnly: true,
|
|
179
|
+
...request.extraParams,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
if (isObject(response) && typeof response.count === "number" && Number.isFinite(response.count)) {
|
|
183
|
+
return response.count;
|
|
184
|
+
}
|
|
185
|
+
if (isObject(response) && Array.isArray(response.features)) {
|
|
186
|
+
return response.features.length;
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
async queryObjectIds(request = {}) {
|
|
191
|
+
const response = await this.client.queryFeatures({
|
|
192
|
+
...request,
|
|
193
|
+
serviceId: this.serviceId,
|
|
194
|
+
layerId: this.layerId,
|
|
195
|
+
where: request.where ?? "1=1",
|
|
196
|
+
returnGeometry: false,
|
|
197
|
+
outFields: request.outFields ?? "OBJECTID",
|
|
198
|
+
extraParams: {
|
|
199
|
+
returnIdsOnly: true,
|
|
200
|
+
...request.extraParams,
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
if (isObject(response) && Array.isArray(response.objectIds)) {
|
|
204
|
+
return response.objectIds
|
|
205
|
+
.map((value) => Number(value))
|
|
206
|
+
.filter((value) => Number.isFinite(value));
|
|
207
|
+
}
|
|
208
|
+
return [];
|
|
209
|
+
}
|
|
210
|
+
async queryExtent(request = {}) {
|
|
211
|
+
const response = await this.client.queryFeatures({
|
|
212
|
+
serviceId: this.serviceId,
|
|
213
|
+
layerId: this.layerId,
|
|
214
|
+
where: request.where ?? "1=1",
|
|
215
|
+
returnGeometry: false,
|
|
216
|
+
method: request.method,
|
|
217
|
+
extraParams: {
|
|
218
|
+
returnExtentOnly: true,
|
|
219
|
+
...request.extraParams,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
return extractExtentFromResponse(response);
|
|
223
|
+
}
|
|
224
|
+
async queryRelatedRecords(request) {
|
|
225
|
+
return this.client.queryRelatedRecords({
|
|
226
|
+
serviceId: this.serviceId,
|
|
227
|
+
layerId: this.layerId,
|
|
228
|
+
...request,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
async queryRelatedFeatures(request) {
|
|
232
|
+
return this.queryRelatedRecords(request);
|
|
233
|
+
}
|
|
234
|
+
async applyEdits(request) {
|
|
235
|
+
return this.client.applyEdits({
|
|
236
|
+
serviceId: this.serviceId,
|
|
237
|
+
layerId: this.layerId,
|
|
238
|
+
...request,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async queryAttachments(request = {}) {
|
|
242
|
+
const method = request.method ?? "GET";
|
|
243
|
+
const path = `/rest/services/${encodeURIComponent(this.serviceId)}` + `/FeatureServer/${this.layerId}/queryAttachments`;
|
|
244
|
+
const query = {
|
|
245
|
+
...(request.objectIds === undefined
|
|
246
|
+
? {}
|
|
247
|
+
: {
|
|
248
|
+
objectIds: normalizeObjectIds(request.objectIds),
|
|
249
|
+
}),
|
|
250
|
+
...(request.where === undefined ? {} : { where: request.where }),
|
|
251
|
+
...(request.extraParams ?? {}),
|
|
252
|
+
};
|
|
253
|
+
if (method === "GET") {
|
|
254
|
+
return this.client.request({
|
|
255
|
+
method: "GET",
|
|
256
|
+
path,
|
|
257
|
+
responseFormat: request.responseFormat ?? "json",
|
|
258
|
+
query,
|
|
259
|
+
signal: request.signal,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
const body = toFormBody({
|
|
263
|
+
f: request.responseFormat ?? "json",
|
|
264
|
+
...query,
|
|
265
|
+
});
|
|
266
|
+
return this.client.request({
|
|
267
|
+
method: "POST",
|
|
268
|
+
path,
|
|
269
|
+
headers: {
|
|
270
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
271
|
+
},
|
|
272
|
+
body,
|
|
273
|
+
signal: request.signal,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
async listAttachments(request) {
|
|
277
|
+
return this.client.request({
|
|
278
|
+
method: "GET",
|
|
279
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
280
|
+
`/FeatureServer/${this.layerId}/${request.objectId}/attachments`,
|
|
281
|
+
responseFormat: request.responseFormat ?? "json",
|
|
282
|
+
query: request.extraParams,
|
|
283
|
+
signal: request.signal,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
async deleteAttachments(request) {
|
|
287
|
+
const body = toFormBody({
|
|
288
|
+
f: request.responseFormat ?? "json",
|
|
289
|
+
attachmentIds: normalizeObjectIds(request.attachmentIds),
|
|
290
|
+
...(request.extraParams ?? {}),
|
|
291
|
+
});
|
|
292
|
+
return this.client.request({
|
|
293
|
+
method: "POST",
|
|
294
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
295
|
+
`/FeatureServer/${this.layerId}/${request.objectId}/deleteAttachments`,
|
|
296
|
+
headers: {
|
|
297
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
298
|
+
},
|
|
299
|
+
body,
|
|
300
|
+
signal: request.signal,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async addAttachment(request) {
|
|
304
|
+
const form = buildAttachmentFormData(request);
|
|
305
|
+
return this.client.request({
|
|
306
|
+
method: "POST",
|
|
307
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
308
|
+
`/FeatureServer/${this.layerId}/${request.objectId}/addAttachment`,
|
|
309
|
+
responseFormat: request.responseFormat ?? "json",
|
|
310
|
+
query: request.extraParams,
|
|
311
|
+
body: form,
|
|
312
|
+
signal: request.signal,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async updateAttachment(request) {
|
|
316
|
+
const form = buildAttachmentFormData(request);
|
|
317
|
+
form.set("attachmentId", String(request.attachmentId));
|
|
318
|
+
return this.client.request({
|
|
319
|
+
method: "POST",
|
|
320
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
321
|
+
`/FeatureServer/${this.layerId}/${request.objectId}/updateAttachment`,
|
|
322
|
+
responseFormat: request.responseFormat ?? "json",
|
|
323
|
+
query: request.extraParams,
|
|
324
|
+
body: form,
|
|
325
|
+
signal: request.signal,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
async request(request) {
|
|
329
|
+
return this.client.request({
|
|
330
|
+
...request,
|
|
331
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
332
|
+
`/FeatureServer/${this.layerId}/${normalizeLayerPath(request.path)}`,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
export class HonuaMapService {
|
|
337
|
+
client;
|
|
338
|
+
serviceId;
|
|
339
|
+
constructor(options) {
|
|
340
|
+
this.client = options.client;
|
|
341
|
+
this.serviceId = options.serviceId;
|
|
342
|
+
}
|
|
343
|
+
async metadata(options = {}) {
|
|
344
|
+
return this.client.getMapServiceMetadata(this.serviceId, options);
|
|
345
|
+
}
|
|
346
|
+
layer(layerId) {
|
|
347
|
+
return new HonuaMapLayer({
|
|
348
|
+
client: this.client,
|
|
349
|
+
serviceId: this.serviceId,
|
|
350
|
+
layerId,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
async layerIds() {
|
|
354
|
+
const metadata = await this.metadata();
|
|
355
|
+
return extractLayerIds(metadata);
|
|
356
|
+
}
|
|
357
|
+
async layers() {
|
|
358
|
+
const ids = await this.layerIds();
|
|
359
|
+
return ids.map((layerId) => new HonuaMapLayer({
|
|
360
|
+
client: this.client,
|
|
361
|
+
serviceId: this.serviceId,
|
|
362
|
+
layerId,
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
async exportMap(request) {
|
|
366
|
+
return this.client.exportMap({
|
|
367
|
+
serviceId: this.serviceId,
|
|
368
|
+
...request,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
async legend(request = {}) {
|
|
372
|
+
return this.client.getMapLegend({
|
|
373
|
+
serviceId: this.serviceId,
|
|
374
|
+
...request,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
async getLegend(request = {}) {
|
|
378
|
+
return this.legend(request);
|
|
379
|
+
}
|
|
380
|
+
async identify(request) {
|
|
381
|
+
return this.client.identifyMap({
|
|
382
|
+
serviceId: this.serviceId,
|
|
383
|
+
...request,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
async find(request) {
|
|
387
|
+
return this.client.findMap({
|
|
388
|
+
serviceId: this.serviceId,
|
|
389
|
+
...request,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
async queryLayer(request) {
|
|
393
|
+
return this.client.queryMapLayer({
|
|
394
|
+
serviceId: this.serviceId,
|
|
395
|
+
...request,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
async queryLayerRelatedRecords(request) {
|
|
399
|
+
return this.client.queryMapRelatedRecords({
|
|
400
|
+
serviceId: this.serviceId,
|
|
401
|
+
...request,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
async queryLayerRelatedFeatures(request) {
|
|
405
|
+
return this.queryLayerRelatedRecords(request);
|
|
406
|
+
}
|
|
407
|
+
async queryLayerFeaturesAll(request) {
|
|
408
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
409
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
410
|
+
: 2000;
|
|
411
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
412
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
413
|
+
: 100;
|
|
414
|
+
const features = [];
|
|
415
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
416
|
+
const response = await this.queryLayer({
|
|
417
|
+
...request,
|
|
418
|
+
extraParams: {
|
|
419
|
+
...(request.extraParams ?? {}),
|
|
420
|
+
resultOffset: page * pageSize,
|
|
421
|
+
resultRecordCount: pageSize,
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
const pageFeatures = extractFeaturesFromResponse(response);
|
|
425
|
+
if (pageFeatures.length === 0) {
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
features.push(...pageFeatures);
|
|
429
|
+
if (pageFeatures.length < pageSize) {
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return features;
|
|
434
|
+
}
|
|
435
|
+
async *queryLayerFeaturesStream(request) {
|
|
436
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
437
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
438
|
+
: 2000;
|
|
439
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
440
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
441
|
+
: 100;
|
|
442
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
443
|
+
const response = await this.queryLayer({
|
|
444
|
+
...request,
|
|
445
|
+
extraParams: {
|
|
446
|
+
...(request.extraParams ?? {}),
|
|
447
|
+
resultOffset: page * pageSize,
|
|
448
|
+
resultRecordCount: pageSize,
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
const pageFeatures = extractFeaturesFromResponse(response);
|
|
452
|
+
if (pageFeatures.length === 0) {
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
yield pageFeatures;
|
|
456
|
+
if (pageFeatures.length < pageSize) {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
async queryLayerFeatureCount(request) {
|
|
462
|
+
const response = await this.queryLayer({
|
|
463
|
+
layerId: request.layerId,
|
|
464
|
+
where: request.where ?? "1=1",
|
|
465
|
+
returnGeometry: false,
|
|
466
|
+
outFields: "OBJECTID",
|
|
467
|
+
method: request.method,
|
|
468
|
+
extraParams: {
|
|
469
|
+
returnCountOnly: true,
|
|
470
|
+
...request.extraParams,
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
return extractFeatureCountFromResponse(response);
|
|
474
|
+
}
|
|
475
|
+
async queryLayerObjectIds(request) {
|
|
476
|
+
const response = await this.queryLayer({
|
|
477
|
+
layerId: request.layerId,
|
|
478
|
+
where: request.where ?? "1=1",
|
|
479
|
+
returnGeometry: false,
|
|
480
|
+
outFields: "OBJECTID",
|
|
481
|
+
method: request.method,
|
|
482
|
+
extraParams: {
|
|
483
|
+
returnIdsOnly: true,
|
|
484
|
+
...request.extraParams,
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
return extractObjectIdsFromResponse(response);
|
|
488
|
+
}
|
|
489
|
+
async queryLayerExtent(request) {
|
|
490
|
+
const response = await this.queryLayer({
|
|
491
|
+
layerId: request.layerId,
|
|
492
|
+
where: request.where ?? "1=1",
|
|
493
|
+
returnGeometry: false,
|
|
494
|
+
method: request.method,
|
|
495
|
+
extraParams: {
|
|
496
|
+
returnExtentOnly: true,
|
|
497
|
+
...request.extraParams,
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
return extractExtentFromResponse(response);
|
|
501
|
+
}
|
|
502
|
+
async exportImage(request) {
|
|
503
|
+
return this.exportMap(request);
|
|
504
|
+
}
|
|
505
|
+
async request(request) {
|
|
506
|
+
return this.client.request({
|
|
507
|
+
...request,
|
|
508
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` + `/MapServer/${normalizeServicePath(request.path)}`,
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
export class HonuaMapLayer {
|
|
513
|
+
client;
|
|
514
|
+
serviceId;
|
|
515
|
+
layerId;
|
|
516
|
+
constructor(options) {
|
|
517
|
+
this.client = options.client;
|
|
518
|
+
this.serviceId = options.serviceId;
|
|
519
|
+
this.layerId = options.layerId;
|
|
520
|
+
}
|
|
521
|
+
async metadata(options = {}) {
|
|
522
|
+
return this.client.getMapLayerMetadata(this.serviceId, this.layerId, options);
|
|
523
|
+
}
|
|
524
|
+
createQuery() {
|
|
525
|
+
return {
|
|
526
|
+
where: "1=1",
|
|
527
|
+
outFields: ["*"],
|
|
528
|
+
returnGeometry: true,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
async queryFeatures(request = {}) {
|
|
532
|
+
return this.client.queryMapLayer({
|
|
533
|
+
serviceId: this.serviceId,
|
|
534
|
+
layerId: this.layerId,
|
|
535
|
+
...request,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
async queryRelatedRecords(request) {
|
|
539
|
+
return this.client.queryMapRelatedRecords({
|
|
540
|
+
serviceId: this.serviceId,
|
|
541
|
+
layerId: this.layerId,
|
|
542
|
+
...request,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
async queryRelatedFeatures(request) {
|
|
546
|
+
return this.queryRelatedRecords(request);
|
|
547
|
+
}
|
|
548
|
+
async queryFeaturesAll(request = {}) {
|
|
549
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
550
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
551
|
+
: 2000;
|
|
552
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
553
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
554
|
+
: 100;
|
|
555
|
+
const startingOffset = normalizeOffset(request.resultOffset);
|
|
556
|
+
const features = [];
|
|
557
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
558
|
+
const response = await this.queryFeatures({
|
|
559
|
+
...request,
|
|
560
|
+
extraParams: {
|
|
561
|
+
...(request.extraParams ?? {}),
|
|
562
|
+
resultOffset: startingOffset + page * pageSize,
|
|
563
|
+
resultRecordCount: pageSize,
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
const pageFeatures = extractFeaturesFromResponse(response);
|
|
567
|
+
if (pageFeatures.length === 0) {
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
features.push(...pageFeatures);
|
|
571
|
+
if (pageFeatures.length < pageSize) {
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return features;
|
|
576
|
+
}
|
|
577
|
+
async *queryFeaturesStream(request = {}) {
|
|
578
|
+
const pageSize = typeof request.pageSize === "number" && Number.isFinite(request.pageSize)
|
|
579
|
+
? Math.max(1, Math.trunc(request.pageSize))
|
|
580
|
+
: 2000;
|
|
581
|
+
const maxPages = typeof request.maxPages === "number" && Number.isFinite(request.maxPages)
|
|
582
|
+
? Math.max(1, Math.trunc(request.maxPages))
|
|
583
|
+
: 100;
|
|
584
|
+
const startingOffset = normalizeOffset(request.resultOffset);
|
|
585
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
586
|
+
const response = await this.queryFeatures({
|
|
587
|
+
...request,
|
|
588
|
+
extraParams: {
|
|
589
|
+
...(request.extraParams ?? {}),
|
|
590
|
+
resultOffset: startingOffset + page * pageSize,
|
|
591
|
+
resultRecordCount: pageSize,
|
|
592
|
+
},
|
|
593
|
+
});
|
|
594
|
+
const pageFeatures = extractFeaturesFromResponse(response);
|
|
595
|
+
if (pageFeatures.length === 0) {
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
yield pageFeatures;
|
|
599
|
+
if (pageFeatures.length < pageSize) {
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
async queryFeatureCount(request = {}) {
|
|
605
|
+
const response = await this.queryFeatures({
|
|
606
|
+
where: request.where ?? "1=1",
|
|
607
|
+
returnGeometry: false,
|
|
608
|
+
outFields: "OBJECTID",
|
|
609
|
+
method: request.method,
|
|
610
|
+
extraParams: {
|
|
611
|
+
returnCountOnly: true,
|
|
612
|
+
...request.extraParams,
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
return extractFeatureCountFromResponse(response);
|
|
616
|
+
}
|
|
617
|
+
async queryObjectIds(request = {}) {
|
|
618
|
+
const response = await this.queryFeatures({
|
|
619
|
+
...request,
|
|
620
|
+
where: request.where ?? "1=1",
|
|
621
|
+
returnGeometry: false,
|
|
622
|
+
outFields: request.outFields ?? "OBJECTID",
|
|
623
|
+
extraParams: {
|
|
624
|
+
returnIdsOnly: true,
|
|
625
|
+
...request.extraParams,
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
|
+
return extractObjectIdsFromResponse(response);
|
|
629
|
+
}
|
|
630
|
+
async queryExtent(request = {}) {
|
|
631
|
+
const response = await this.queryFeatures({
|
|
632
|
+
where: request.where ?? "1=1",
|
|
633
|
+
returnGeometry: false,
|
|
634
|
+
method: request.method,
|
|
635
|
+
extraParams: {
|
|
636
|
+
returnExtentOnly: true,
|
|
637
|
+
...request.extraParams,
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
return extractExtentFromResponse(response);
|
|
641
|
+
}
|
|
642
|
+
async request(request) {
|
|
643
|
+
return this.client.request({
|
|
644
|
+
...request,
|
|
645
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}` +
|
|
646
|
+
`/MapServer/${this.layerId}/${normalizeLayerPath(request.path)}`,
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
export class HonuaOgcFeatures {
|
|
651
|
+
client;
|
|
652
|
+
constructor(options) {
|
|
653
|
+
this.client = options.client;
|
|
654
|
+
}
|
|
655
|
+
collection(collectionId) {
|
|
656
|
+
return new HonuaOgcFeatureCollection({
|
|
657
|
+
client: this.client,
|
|
658
|
+
collectionId,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
async landing(request = {}) {
|
|
662
|
+
return this.client.getOgcFeaturesLanding(request);
|
|
663
|
+
}
|
|
664
|
+
async conformance(request = {}) {
|
|
665
|
+
return this.client.getOgcFeaturesConformance(request);
|
|
666
|
+
}
|
|
667
|
+
async collections(request = {}) {
|
|
668
|
+
return this.client.listOgcCollections(request);
|
|
669
|
+
}
|
|
670
|
+
async getCollection(request) {
|
|
671
|
+
return this.client.getOgcCollection(request);
|
|
672
|
+
}
|
|
673
|
+
async queryables(request) {
|
|
674
|
+
return this.client.getOgcQueryables(request);
|
|
675
|
+
}
|
|
676
|
+
async items(request) {
|
|
677
|
+
return this.client.listOgcItems(request);
|
|
678
|
+
}
|
|
679
|
+
async itemsAll(request) {
|
|
680
|
+
const pageSize = normalizePageSize(request.pageSize, request.limit);
|
|
681
|
+
const maxPages = normalizeMaxPages(request.maxPages);
|
|
682
|
+
const offset = normalizeOffset(request.offset);
|
|
683
|
+
const totalLimit = normalizeTotalLimit(request.limit);
|
|
684
|
+
const features = [];
|
|
685
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
686
|
+
if (totalLimit !== undefined && features.length >= totalLimit) {
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
const remainingLimit = totalLimit === undefined ? pageSize : Math.max(0, totalLimit - features.length);
|
|
690
|
+
if (remainingLimit < 1) {
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
const limit = Math.min(pageSize, remainingLimit);
|
|
694
|
+
const response = await this.items({
|
|
695
|
+
...request,
|
|
696
|
+
limit,
|
|
697
|
+
offset: offset + page * pageSize,
|
|
698
|
+
});
|
|
699
|
+
const pageFeatures = extractOgcFeatures(response);
|
|
700
|
+
if (pageFeatures.length === 0) {
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
features.push(...pageFeatures);
|
|
704
|
+
if (pageFeatures.length < limit) {
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (totalLimit !== undefined && features.length > totalLimit) {
|
|
709
|
+
return features.slice(0, totalLimit);
|
|
710
|
+
}
|
|
711
|
+
return features;
|
|
712
|
+
}
|
|
713
|
+
async item(request) {
|
|
714
|
+
return this.client.getOgcItem(request);
|
|
715
|
+
}
|
|
716
|
+
async createItem(request) {
|
|
717
|
+
return this.client.createOgcItem(request);
|
|
718
|
+
}
|
|
719
|
+
async replaceItem(request) {
|
|
720
|
+
return this.client.replaceOgcItem(request);
|
|
721
|
+
}
|
|
722
|
+
async patchItem(request) {
|
|
723
|
+
return this.client.patchOgcItem(request);
|
|
724
|
+
}
|
|
725
|
+
async deleteItem(request) {
|
|
726
|
+
return this.client.deleteOgcItem(request);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
export class HonuaOgcFeatureCollection {
|
|
730
|
+
client;
|
|
731
|
+
collectionId;
|
|
732
|
+
constructor(options) {
|
|
733
|
+
this.client = options.client;
|
|
734
|
+
this.collectionId = options.collectionId;
|
|
735
|
+
}
|
|
736
|
+
async metadata(request = {}) {
|
|
737
|
+
return this.client.getOgcCollection({
|
|
738
|
+
...request,
|
|
739
|
+
collectionId: this.collectionId,
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
async queryables(request = {}) {
|
|
743
|
+
return this.client.getOgcQueryables({
|
|
744
|
+
...request,
|
|
745
|
+
collectionId: this.collectionId,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
async items(request = {}) {
|
|
749
|
+
return this.client.listOgcItems({
|
|
750
|
+
...request,
|
|
751
|
+
collectionId: this.collectionId,
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
async itemsAll(request = {}) {
|
|
755
|
+
const pageSize = normalizePageSize(request.pageSize, request.limit);
|
|
756
|
+
const maxPages = normalizeMaxPages(request.maxPages);
|
|
757
|
+
const offset = normalizeOffset(request.offset);
|
|
758
|
+
const totalLimit = normalizeTotalLimit(request.limit);
|
|
759
|
+
const features = [];
|
|
760
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
761
|
+
if (totalLimit !== undefined && features.length >= totalLimit) {
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
const remainingLimit = totalLimit === undefined ? pageSize : Math.max(0, totalLimit - features.length);
|
|
765
|
+
if (remainingLimit < 1) {
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
const limit = Math.min(pageSize, remainingLimit);
|
|
769
|
+
const response = await this.items({
|
|
770
|
+
...request,
|
|
771
|
+
limit,
|
|
772
|
+
offset: offset + page * pageSize,
|
|
773
|
+
});
|
|
774
|
+
const pageFeatures = extractOgcFeatures(response);
|
|
775
|
+
if (pageFeatures.length === 0) {
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
features.push(...pageFeatures);
|
|
779
|
+
if (pageFeatures.length < limit) {
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (totalLimit !== undefined && features.length > totalLimit) {
|
|
784
|
+
return features.slice(0, totalLimit);
|
|
785
|
+
}
|
|
786
|
+
return features;
|
|
787
|
+
}
|
|
788
|
+
async *itemsStream(request = {}) {
|
|
789
|
+
const pageSize = normalizePageSize(request.pageSize, request.limit);
|
|
790
|
+
const maxPages = normalizeMaxPages(request.maxPages);
|
|
791
|
+
const offset = normalizeOffset(request.offset);
|
|
792
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
793
|
+
const response = await this.items({
|
|
794
|
+
...request,
|
|
795
|
+
limit: pageSize,
|
|
796
|
+
offset: offset + page * pageSize,
|
|
797
|
+
});
|
|
798
|
+
const pageFeatures = extractOgcFeatures(response);
|
|
799
|
+
if (pageFeatures.length === 0) {
|
|
800
|
+
break;
|
|
801
|
+
}
|
|
802
|
+
yield pageFeatures;
|
|
803
|
+
if (pageFeatures.length < pageSize) {
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
async item(request) {
|
|
809
|
+
return this.client.getOgcItem({
|
|
810
|
+
...request,
|
|
811
|
+
collectionId: this.collectionId,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
async createItem(request) {
|
|
815
|
+
return this.client.createOgcItem({
|
|
816
|
+
...request,
|
|
817
|
+
collectionId: this.collectionId,
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async replaceItem(request) {
|
|
821
|
+
return this.client.replaceOgcItem({
|
|
822
|
+
...request,
|
|
823
|
+
collectionId: this.collectionId,
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
async patchItem(request) {
|
|
827
|
+
return this.client.patchOgcItem({
|
|
828
|
+
...request,
|
|
829
|
+
collectionId: this.collectionId,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
async deleteItem(request) {
|
|
833
|
+
return this.client.deleteOgcItem({
|
|
834
|
+
...request,
|
|
835
|
+
collectionId: this.collectionId,
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
export function createHonuaService(client, serviceId) {
|
|
840
|
+
return new HonuaService({
|
|
841
|
+
client,
|
|
842
|
+
serviceId,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
export function createHonuaOgcFeatures(client) {
|
|
846
|
+
return new HonuaOgcFeatures({
|
|
847
|
+
client,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Wrapper over a Honua ImageServer endpoint. Each operation maps to the
|
|
852
|
+
* server route published in
|
|
853
|
+
* `honua-server/docs/gis/image-server-matrix.md`. The wrapper does not
|
|
854
|
+
* downgrade to a generic raw call: it carries a typed request shape so
|
|
855
|
+
* the contract layer can negotiate capabilities and the server can
|
|
856
|
+
* branch on a stable method name.
|
|
857
|
+
*/
|
|
858
|
+
export class HonuaImageService {
|
|
859
|
+
client;
|
|
860
|
+
serviceId;
|
|
861
|
+
constructor(options) {
|
|
862
|
+
this.client = options.client;
|
|
863
|
+
this.serviceId = options.serviceId;
|
|
864
|
+
}
|
|
865
|
+
async metadata() {
|
|
866
|
+
return this.client.request({
|
|
867
|
+
method: "GET",
|
|
868
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}/ImageServer`,
|
|
869
|
+
responseFormat: "json",
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
async queryRasterCatalog(request = {}) {
|
|
873
|
+
return this.dispatch("query", request, imageQueryParams(request));
|
|
874
|
+
}
|
|
875
|
+
async queryRasterCatalogObjectIds(request = {}) {
|
|
876
|
+
const response = await this.dispatch("query", request, {
|
|
877
|
+
...imageQueryParams(request),
|
|
878
|
+
where: request.where ?? "1=1",
|
|
879
|
+
returnIdsOnly: true,
|
|
880
|
+
});
|
|
881
|
+
if (!Array.isArray(response.objectIds))
|
|
882
|
+
return [];
|
|
883
|
+
return response.objectIds.map((v) => Number(v)).filter((v) => Number.isFinite(v));
|
|
884
|
+
}
|
|
885
|
+
async exportImage(request) {
|
|
886
|
+
return this.dispatch("exportImage", request, imageExportParams(request));
|
|
887
|
+
}
|
|
888
|
+
async identify(request) {
|
|
889
|
+
return this.dispatch("identify", request, imageIdentifyParams(request));
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Dispatch an ImageServer operation. POST mode sends params as a
|
|
893
|
+
* form-encoded body so the server's `TryReadRequestValuesAsync` parser
|
|
894
|
+
* finds them (returns "Request body is required" otherwise); GET mode
|
|
895
|
+
* keeps params in the query string. Both encodings are accepted by
|
|
896
|
+
* Honua Server per its ImageServer endpoint registration.
|
|
897
|
+
*/
|
|
898
|
+
async dispatch(op, request, params) {
|
|
899
|
+
const method = request.method ?? "GET";
|
|
900
|
+
const path = `/rest/services/${encodeURIComponent(this.serviceId)}/ImageServer/${op}`;
|
|
901
|
+
const responseFormat = request.responseFormat ?? "json";
|
|
902
|
+
if (method === "GET") {
|
|
903
|
+
return this.client.request({ method: "GET", path, responseFormat, query: params, signal: request.signal });
|
|
904
|
+
}
|
|
905
|
+
return this.client.request({
|
|
906
|
+
method: "POST",
|
|
907
|
+
path,
|
|
908
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
909
|
+
body: toFormBody({ f: responseFormat, ...params }),
|
|
910
|
+
signal: request.signal,
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
tileUrl(level, row, col, format = "png") {
|
|
914
|
+
const path = `/rest/services/${encodeURIComponent(this.serviceId)}/ImageServer/tile/${level}/${row}/${col}`;
|
|
915
|
+
return `${this.client.serverBaseUrl}${path}?f=${format}`;
|
|
916
|
+
}
|
|
917
|
+
async legend() {
|
|
918
|
+
return this.client.request({
|
|
919
|
+
method: "GET",
|
|
920
|
+
path: `/rest/services/${encodeURIComponent(this.serviceId)}/ImageServer/legend`,
|
|
921
|
+
responseFormat: "json",
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
function imageQueryParams(request) {
|
|
926
|
+
const params = {};
|
|
927
|
+
if (request.where !== undefined)
|
|
928
|
+
params.where = request.where;
|
|
929
|
+
if (request.outFields !== undefined) {
|
|
930
|
+
params.outFields = Array.isArray(request.outFields) ? request.outFields.join(",") : String(request.outFields);
|
|
931
|
+
}
|
|
932
|
+
if (request.objectIds !== undefined) {
|
|
933
|
+
params.objectIds = Array.isArray(request.objectIds) ? request.objectIds.join(",") : String(request.objectIds);
|
|
934
|
+
}
|
|
935
|
+
if (request.returnGeometry !== undefined)
|
|
936
|
+
params.returnGeometry = request.returnGeometry;
|
|
937
|
+
if (request.outSr !== undefined)
|
|
938
|
+
params.outSR = String(request.outSr);
|
|
939
|
+
if (request.resultOffset !== undefined)
|
|
940
|
+
params.resultOffset = request.resultOffset;
|
|
941
|
+
if (request.resultRecordCount !== undefined)
|
|
942
|
+
params.resultRecordCount = request.resultRecordCount;
|
|
943
|
+
if (request.geometry !== undefined)
|
|
944
|
+
params.geometry = JSON.stringify(request.geometry);
|
|
945
|
+
if (request.geometryType !== undefined)
|
|
946
|
+
params.geometryType = String(request.geometryType);
|
|
947
|
+
if (request.spatialRel !== undefined)
|
|
948
|
+
params.spatialRel = String(request.spatialRel);
|
|
949
|
+
Object.assign(params, request.extraParams ?? {});
|
|
950
|
+
return params;
|
|
951
|
+
}
|
|
952
|
+
function imageExportParams(request) {
|
|
953
|
+
const params = {};
|
|
954
|
+
if (request.bbox !== undefined) {
|
|
955
|
+
params.bbox = Array.isArray(request.bbox) ? request.bbox.join(",") : request.bbox;
|
|
956
|
+
}
|
|
957
|
+
if (request.size !== undefined) {
|
|
958
|
+
params.size = Array.isArray(request.size) ? request.size.join(",") : request.size;
|
|
959
|
+
}
|
|
960
|
+
if (request.format !== undefined)
|
|
961
|
+
params.format = request.format;
|
|
962
|
+
if (request.pixelType !== undefined)
|
|
963
|
+
params.pixelType = request.pixelType;
|
|
964
|
+
if (request.noData !== undefined)
|
|
965
|
+
params.noData = request.noData;
|
|
966
|
+
if (request.interpolation !== undefined)
|
|
967
|
+
params.interpolation = request.interpolation;
|
|
968
|
+
if (request.compressionQuality !== undefined)
|
|
969
|
+
params.compressionQuality = request.compressionQuality;
|
|
970
|
+
if (request.bandIds !== undefined) {
|
|
971
|
+
params.bandIds = Array.isArray(request.bandIds) ? request.bandIds.join(",") : String(request.bandIds);
|
|
972
|
+
}
|
|
973
|
+
if (request.mosaicRule !== undefined) {
|
|
974
|
+
params.mosaicRule =
|
|
975
|
+
typeof request.mosaicRule === "string" ? request.mosaicRule : JSON.stringify(request.mosaicRule);
|
|
976
|
+
}
|
|
977
|
+
if (request.renderingRule !== undefined) {
|
|
978
|
+
params.renderingRule =
|
|
979
|
+
typeof request.renderingRule === "string" ? request.renderingRule : JSON.stringify(request.renderingRule);
|
|
980
|
+
}
|
|
981
|
+
if (request.imageSr !== undefined)
|
|
982
|
+
params.imageSR = String(request.imageSr);
|
|
983
|
+
if (request.bboxSr !== undefined)
|
|
984
|
+
params.bboxSR = String(request.bboxSr);
|
|
985
|
+
Object.assign(params, request.extraParams ?? {});
|
|
986
|
+
return params;
|
|
987
|
+
}
|
|
988
|
+
function imageIdentifyParams(request) {
|
|
989
|
+
const params = {};
|
|
990
|
+
params.geometry = typeof request.geometry === "string" ? request.geometry : JSON.stringify(request.geometry);
|
|
991
|
+
if (request.geometryType !== undefined)
|
|
992
|
+
params.geometryType = request.geometryType;
|
|
993
|
+
if (request.sr !== undefined)
|
|
994
|
+
params.sr = String(request.sr);
|
|
995
|
+
if (request.mosaicRule !== undefined) {
|
|
996
|
+
params.mosaicRule =
|
|
997
|
+
typeof request.mosaicRule === "string" ? request.mosaicRule : JSON.stringify(request.mosaicRule);
|
|
998
|
+
}
|
|
999
|
+
if (request.renderingRule !== undefined) {
|
|
1000
|
+
params.renderingRule =
|
|
1001
|
+
typeof request.renderingRule === "string" ? request.renderingRule : JSON.stringify(request.renderingRule);
|
|
1002
|
+
}
|
|
1003
|
+
if (request.pixelSize !== undefined) {
|
|
1004
|
+
params.pixelSize = Array.isArray(request.pixelSize) ? request.pixelSize.join(",") : request.pixelSize;
|
|
1005
|
+
}
|
|
1006
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1007
|
+
return params;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Wrapper over a Honua Geometry Service endpoint. Routes match the
|
|
1011
|
+
* canonical paths published by Honua Server's `EndpointRegistry`
|
|
1012
|
+
* (`/rest/services/Utilities/Geometry/GeometryServer/<op>`; see
|
|
1013
|
+
* `honua-server/docs/gis/geometry-service-matrix.md`). Wraps the
|
|
1014
|
+
* server-supported operations: `project`, `buffer`, `simplify`,
|
|
1015
|
+
* `intersect`, `union`, `clip`, `difference`. Operations not
|
|
1016
|
+
* implemented in Honua Server (autoComplete, convexHull, cut,
|
|
1017
|
+
* areasAndLengths/lengths measurement helpers, etc.) intentionally have
|
|
1018
|
+
* no wrapper — callers that need them go through the raw `request()`
|
|
1019
|
+
* escape hatch and handle 404s themselves.
|
|
1020
|
+
*
|
|
1021
|
+
* POST mode submits form-encoded bodies so the server's
|
|
1022
|
+
* `TryReadRequestValuesAsync` parser finds the parameters. GET mode keeps
|
|
1023
|
+
* params in the query string (the server accepts both).
|
|
1024
|
+
*/
|
|
1025
|
+
const GEOMETRY_SERVICE_ROOT = "/rest/services/Utilities/Geometry/GeometryServer";
|
|
1026
|
+
export class HonuaGeometryService {
|
|
1027
|
+
client;
|
|
1028
|
+
constructor(options) {
|
|
1029
|
+
this.client = options.client;
|
|
1030
|
+
}
|
|
1031
|
+
async project(request) {
|
|
1032
|
+
return this.dispatch("project", request, geometryProjectParams(request));
|
|
1033
|
+
}
|
|
1034
|
+
async buffer(request) {
|
|
1035
|
+
return this.dispatch("buffer", request, geometryBufferParams(request));
|
|
1036
|
+
}
|
|
1037
|
+
async simplify(request) {
|
|
1038
|
+
return this.dispatch("simplify", request, geometrySimplifyParams(request));
|
|
1039
|
+
}
|
|
1040
|
+
async intersect(request) {
|
|
1041
|
+
return this.dispatch("intersect", request, geometryBinaryParams(request));
|
|
1042
|
+
}
|
|
1043
|
+
async union(request) {
|
|
1044
|
+
return this.dispatch("union", request, geometryUnionParams(request));
|
|
1045
|
+
}
|
|
1046
|
+
async clip(request) {
|
|
1047
|
+
return this.dispatch("clip", request, geometryBinaryParams(request));
|
|
1048
|
+
}
|
|
1049
|
+
async difference(request) {
|
|
1050
|
+
return this.dispatch("difference", request, geometryBinaryParams(request));
|
|
1051
|
+
}
|
|
1052
|
+
async dispatch(op, request, params) {
|
|
1053
|
+
const method = request.method ?? "POST";
|
|
1054
|
+
const path = `${GEOMETRY_SERVICE_ROOT}/${op}`;
|
|
1055
|
+
const responseFormat = request.responseFormat ?? "json";
|
|
1056
|
+
if (method === "GET") {
|
|
1057
|
+
return this.client.request({ method: "GET", path, responseFormat, query: params, signal: request.signal });
|
|
1058
|
+
}
|
|
1059
|
+
return this.client.request({
|
|
1060
|
+
method: "POST",
|
|
1061
|
+
path,
|
|
1062
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1063
|
+
body: toFormBody({ f: responseFormat, ...params }),
|
|
1064
|
+
signal: request.signal,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
function geometryProjectParams(request) {
|
|
1069
|
+
const params = {
|
|
1070
|
+
geometries: typeof request.geometries === "string" ? request.geometries : JSON.stringify(request.geometries),
|
|
1071
|
+
inSR: typeof request.inSr === "string" || typeof request.inSr === "number"
|
|
1072
|
+
? String(request.inSr)
|
|
1073
|
+
: JSON.stringify(request.inSr),
|
|
1074
|
+
outSR: typeof request.outSr === "string" || typeof request.outSr === "number"
|
|
1075
|
+
? String(request.outSr)
|
|
1076
|
+
: JSON.stringify(request.outSr),
|
|
1077
|
+
};
|
|
1078
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1079
|
+
return params;
|
|
1080
|
+
}
|
|
1081
|
+
function geometryBufferParams(request) {
|
|
1082
|
+
const params = {
|
|
1083
|
+
geometries: typeof request.geometries === "string" ? request.geometries : JSON.stringify(request.geometries),
|
|
1084
|
+
distances: Array.isArray(request.distances) ? request.distances.join(",") : String(request.distances),
|
|
1085
|
+
};
|
|
1086
|
+
if (request.unit !== undefined)
|
|
1087
|
+
params.unit = request.unit;
|
|
1088
|
+
if (request.inSr !== undefined)
|
|
1089
|
+
params.inSR = typeof request.inSr === "object" ? JSON.stringify(request.inSr) : String(request.inSr);
|
|
1090
|
+
if (request.outSr !== undefined)
|
|
1091
|
+
params.outSR = typeof request.outSr === "object" ? JSON.stringify(request.outSr) : String(request.outSr);
|
|
1092
|
+
if (request.bufferSr !== undefined)
|
|
1093
|
+
params.bufferSR =
|
|
1094
|
+
typeof request.bufferSr === "object" ? JSON.stringify(request.bufferSr) : String(request.bufferSr);
|
|
1095
|
+
if (request.unionResults !== undefined)
|
|
1096
|
+
params.unionResults = request.unionResults;
|
|
1097
|
+
if (request.geodesic !== undefined)
|
|
1098
|
+
params.geodesic = request.geodesic;
|
|
1099
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1100
|
+
return params;
|
|
1101
|
+
}
|
|
1102
|
+
function geometrySimplifyParams(request) {
|
|
1103
|
+
const params = {
|
|
1104
|
+
geometries: typeof request.geometries === "string" ? request.geometries : JSON.stringify(request.geometries),
|
|
1105
|
+
};
|
|
1106
|
+
if (request.sr !== undefined)
|
|
1107
|
+
params.sr = typeof request.sr === "object" ? JSON.stringify(request.sr) : String(request.sr);
|
|
1108
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1109
|
+
return params;
|
|
1110
|
+
}
|
|
1111
|
+
function geometryBinaryParams(request) {
|
|
1112
|
+
const params = {
|
|
1113
|
+
geometries: typeof request.geometries === "string" ? request.geometries : JSON.stringify(request.geometries),
|
|
1114
|
+
geometry: typeof request.geometry === "string" ? request.geometry : JSON.stringify(request.geometry),
|
|
1115
|
+
sr: typeof request.sr === "object" ? JSON.stringify(request.sr) : String(request.sr),
|
|
1116
|
+
};
|
|
1117
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1118
|
+
return params;
|
|
1119
|
+
}
|
|
1120
|
+
function geometryUnionParams(request) {
|
|
1121
|
+
const params = {
|
|
1122
|
+
geometries: typeof request.geometries === "string" ? request.geometries : JSON.stringify(request.geometries),
|
|
1123
|
+
sr: typeof request.sr === "object" ? JSON.stringify(request.sr) : String(request.sr),
|
|
1124
|
+
};
|
|
1125
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1126
|
+
return params;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Wrapper over a Honua GP Service task. Mirrors the routes published in
|
|
1130
|
+
* `honua-server/docs/gis/geoprocess-framework-analysis.md`: `submitJob`,
|
|
1131
|
+
* `jobs/{jobId}` (status), `jobs/{jobId}/cancel`, and per-result lookup
|
|
1132
|
+
* (currently registered route, output delivery still depends on the
|
|
1133
|
+
* execution engine — see the parity matrix).
|
|
1134
|
+
*/
|
|
1135
|
+
export class HonuaGeoprocessingService {
|
|
1136
|
+
client;
|
|
1137
|
+
serviceId;
|
|
1138
|
+
taskName;
|
|
1139
|
+
constructor(options) {
|
|
1140
|
+
this.client = options.client;
|
|
1141
|
+
this.serviceId = options.serviceId;
|
|
1142
|
+
this.taskName = options.taskName;
|
|
1143
|
+
}
|
|
1144
|
+
async submitJob(request) {
|
|
1145
|
+
return this.client.request({
|
|
1146
|
+
method: request.method ?? "POST",
|
|
1147
|
+
path: this.taskPath("submitJob"),
|
|
1148
|
+
responseFormat: request.responseFormat ?? "json",
|
|
1149
|
+
query: gpSubmitParams(request),
|
|
1150
|
+
signal: request.signal,
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
async jobStatus(jobId, options = {}) {
|
|
1154
|
+
return this.client.request({
|
|
1155
|
+
method: "GET",
|
|
1156
|
+
path: `${this.taskPath("jobs")}/${encodeURIComponent(jobId)}`,
|
|
1157
|
+
responseFormat: "json",
|
|
1158
|
+
signal: options.signal,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
async cancelJob(jobId, options = {}) {
|
|
1162
|
+
return this.client.request({
|
|
1163
|
+
method: "POST",
|
|
1164
|
+
path: `${this.taskPath("jobs")}/${encodeURIComponent(jobId)}/cancel`,
|
|
1165
|
+
responseFormat: "json",
|
|
1166
|
+
signal: options.signal,
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
async jobResult(jobId, resultName, options = {}) {
|
|
1170
|
+
return this.client.request({
|
|
1171
|
+
method: "GET",
|
|
1172
|
+
path: `${this.taskPath("jobs")}/${encodeURIComponent(jobId)}/results/${encodeURIComponent(resultName)}`,
|
|
1173
|
+
responseFormat: "json",
|
|
1174
|
+
signal: options.signal,
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
taskPath(suffix) {
|
|
1178
|
+
const taskSegment = this.taskName ? `/${encodeURIComponent(this.taskName)}` : "";
|
|
1179
|
+
return `/rest/services/${encodeURIComponent(this.serviceId)}/GPServer${taskSegment}/${suffix}`;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
function gpSubmitParams(request) {
|
|
1183
|
+
const params = {};
|
|
1184
|
+
for (const [key, value] of Object.entries(request.parameters)) {
|
|
1185
|
+
params[key] =
|
|
1186
|
+
typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
1187
|
+
? value
|
|
1188
|
+
: JSON.stringify(value);
|
|
1189
|
+
}
|
|
1190
|
+
Object.assign(params, request.extraParams ?? {});
|
|
1191
|
+
return params;
|
|
1192
|
+
}
|
|
1193
|
+
function isObject(value) {
|
|
1194
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1195
|
+
}
|
|
1196
|
+
function isFiniteNumber(value) {
|
|
1197
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
1198
|
+
}
|
|
1199
|
+
function extractFeatureCountFromResponse(response) {
|
|
1200
|
+
if (isObject(response) && typeof response.count === "number" && Number.isFinite(response.count)) {
|
|
1201
|
+
return response.count;
|
|
1202
|
+
}
|
|
1203
|
+
if (isObject(response) && Array.isArray(response.features)) {
|
|
1204
|
+
return response.features.length;
|
|
1205
|
+
}
|
|
1206
|
+
return 0;
|
|
1207
|
+
}
|
|
1208
|
+
function extractFeaturesFromResponse(response) {
|
|
1209
|
+
if (!isObject(response) || !Array.isArray(response.features)) {
|
|
1210
|
+
return [];
|
|
1211
|
+
}
|
|
1212
|
+
return response.features;
|
|
1213
|
+
}
|
|
1214
|
+
function extractObjectIdsFromResponse(response) {
|
|
1215
|
+
if (!isObject(response) || !Array.isArray(response.objectIds)) {
|
|
1216
|
+
return [];
|
|
1217
|
+
}
|
|
1218
|
+
return response.objectIds.map((value) => Number(value)).filter((value) => Number.isFinite(value));
|
|
1219
|
+
}
|
|
1220
|
+
function extractExtentFromResponse(response) {
|
|
1221
|
+
if (!isObject(response)) {
|
|
1222
|
+
return { extent: null };
|
|
1223
|
+
}
|
|
1224
|
+
const count = isFiniteNumber(response.count) ? response.count : undefined;
|
|
1225
|
+
const extent = isObject(response.extent) ? response.extent : null;
|
|
1226
|
+
return { extent, count };
|
|
1227
|
+
}
|
|
1228
|
+
function normalizeObjectIds(ids) {
|
|
1229
|
+
return Array.isArray(ids) ? ids.join(",") : String(ids);
|
|
1230
|
+
}
|
|
1231
|
+
function toFormBody(values) {
|
|
1232
|
+
const params = new URLSearchParams();
|
|
1233
|
+
for (const [key, value] of Object.entries(values)) {
|
|
1234
|
+
params.set(key, String(value));
|
|
1235
|
+
}
|
|
1236
|
+
return params.toString();
|
|
1237
|
+
}
|
|
1238
|
+
function normalizeLayerPath(path) {
|
|
1239
|
+
return path.startsWith("/") ? path.slice(1) : path;
|
|
1240
|
+
}
|
|
1241
|
+
function normalizeServicePath(path) {
|
|
1242
|
+
return path.startsWith("/") ? path.slice(1) : path;
|
|
1243
|
+
}
|
|
1244
|
+
function normalizePageSize(pageSize, limit) {
|
|
1245
|
+
if (isFinitePositiveInteger(pageSize)) {
|
|
1246
|
+
return pageSize;
|
|
1247
|
+
}
|
|
1248
|
+
if (isFinitePositiveInteger(limit)) {
|
|
1249
|
+
return limit;
|
|
1250
|
+
}
|
|
1251
|
+
return 100;
|
|
1252
|
+
}
|
|
1253
|
+
function normalizeMaxPages(maxPages) {
|
|
1254
|
+
if (isFinitePositiveInteger(maxPages)) {
|
|
1255
|
+
return maxPages;
|
|
1256
|
+
}
|
|
1257
|
+
return 100;
|
|
1258
|
+
}
|
|
1259
|
+
function normalizeOffset(offset) {
|
|
1260
|
+
if (typeof offset !== "number" || !Number.isFinite(offset)) {
|
|
1261
|
+
return 0;
|
|
1262
|
+
}
|
|
1263
|
+
return Math.max(0, Math.trunc(offset));
|
|
1264
|
+
}
|
|
1265
|
+
function normalizeTotalLimit(limit) {
|
|
1266
|
+
if (!isFinitePositiveInteger(limit)) {
|
|
1267
|
+
return undefined;
|
|
1268
|
+
}
|
|
1269
|
+
return limit;
|
|
1270
|
+
}
|
|
1271
|
+
function isFinitePositiveInteger(value) {
|
|
1272
|
+
return typeof value === "number" && Number.isFinite(value) && Math.trunc(value) > 0;
|
|
1273
|
+
}
|
|
1274
|
+
function buildAttachmentFormData(request) {
|
|
1275
|
+
const form = new FormData();
|
|
1276
|
+
if (request.attachment instanceof Blob) {
|
|
1277
|
+
const blob = ensureBlobType(request.attachment, request.contentType);
|
|
1278
|
+
const fileName = request.name ?? resolveBlobName(request.attachment);
|
|
1279
|
+
form.set("attachment", blob, fileName);
|
|
1280
|
+
return form;
|
|
1281
|
+
}
|
|
1282
|
+
const blob = new Blob([request.attachment], {
|
|
1283
|
+
type: request.contentType ?? "application/octet-stream",
|
|
1284
|
+
});
|
|
1285
|
+
form.set("attachment", blob, request.name ?? "attachment.txt");
|
|
1286
|
+
return form;
|
|
1287
|
+
}
|
|
1288
|
+
function resolveBlobName(blob) {
|
|
1289
|
+
if ("name" in blob && typeof blob.name === "string" && blob.name.length > 0) {
|
|
1290
|
+
return blob.name;
|
|
1291
|
+
}
|
|
1292
|
+
return "attachment.bin";
|
|
1293
|
+
}
|
|
1294
|
+
function ensureBlobType(blob, contentType) {
|
|
1295
|
+
if (!contentType || blob.type === contentType) {
|
|
1296
|
+
return blob;
|
|
1297
|
+
}
|
|
1298
|
+
return new Blob([blob], { type: contentType });
|
|
1299
|
+
}
|
|
1300
|
+
function extractLayerIds(metadata) {
|
|
1301
|
+
if (!isObject(metadata) || !Array.isArray(metadata.layers)) {
|
|
1302
|
+
return [];
|
|
1303
|
+
}
|
|
1304
|
+
const ids = [];
|
|
1305
|
+
for (const layer of metadata.layers) {
|
|
1306
|
+
if (!isObject(layer)) {
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
const parsed = Number(layer.id);
|
|
1310
|
+
if (!Number.isFinite(parsed)) {
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
ids.push(Math.trunc(parsed));
|
|
1314
|
+
}
|
|
1315
|
+
return ids;
|
|
1316
|
+
}
|
|
1317
|
+
function extractOgcFeatures(response) {
|
|
1318
|
+
if (!isObject(response) || !Array.isArray(response.features)) {
|
|
1319
|
+
return [];
|
|
1320
|
+
}
|
|
1321
|
+
return response.features;
|
|
1322
|
+
}
|