@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
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OGC API Processes surface. Process discovery, execution, and async
|
|
3
|
+
* job tracking. Per the ticket constraint, async executions return an
|
|
4
|
+
* `IJobRun` (the canonical async-operation surface) rather than an
|
|
5
|
+
* OGC-specific job type.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { isJobTerminal } from "../contract/jobs.js";
|
|
10
|
+
const DEFAULT_POLL_INTERVAL_MS = 1_000;
|
|
11
|
+
/** Top-level OGC API Processes handle. */
|
|
12
|
+
export class HonuaOgcProcesses {
|
|
13
|
+
client;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.client = options.client;
|
|
16
|
+
}
|
|
17
|
+
async landing(request = {}) {
|
|
18
|
+
return this.client.getOgcProcessesLanding(request);
|
|
19
|
+
}
|
|
20
|
+
async conformance(request = {}) {
|
|
21
|
+
return this.client.getOgcProcessesConformance(request);
|
|
22
|
+
}
|
|
23
|
+
async list(request = {}) {
|
|
24
|
+
return this.client.listOgcProcesses(request);
|
|
25
|
+
}
|
|
26
|
+
async describe(processId, request = {}) {
|
|
27
|
+
return this.client.getOgcProcess({ ...request, processId });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Submit a process for execution. Always returns an `IJobRun`: honua-server
|
|
31
|
+
* is async-only (advertises `jobControlOptions: ['async-execute', 'dismiss']`),
|
|
32
|
+
* so the runner polls for the terminal snapshot regardless of whether
|
|
33
|
+
* `mode` is `"async"` or `"auto"`.
|
|
34
|
+
*/
|
|
35
|
+
async execute(request) {
|
|
36
|
+
const accepted = await this.client.executeOgcProcess(request);
|
|
37
|
+
return new HonuaOgcProcessJobRun({
|
|
38
|
+
client: this.client,
|
|
39
|
+
jobId: accepted.jobID,
|
|
40
|
+
processId: accepted.processID ?? request.processId,
|
|
41
|
+
initialStatus: accepted.statusInfo ?? {
|
|
42
|
+
jobID: accepted.jobID,
|
|
43
|
+
processID: accepted.processID ?? request.processId,
|
|
44
|
+
status: accepted.status,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** Adopt an existing job by id (useful when reconnecting after navigation). */
|
|
49
|
+
job(jobId, options = {}) {
|
|
50
|
+
return new HonuaOgcProcessJobRun({
|
|
51
|
+
client: this.client,
|
|
52
|
+
jobId,
|
|
53
|
+
processId: options.processId,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `IJobRun` implementation backed by OGC API Processes 1.0 status / result
|
|
59
|
+
* endpoints. Watchers receive the latest `JobSnapshot` when status,
|
|
60
|
+
* progress, or terminal result changes; cancel is idempotent and races
|
|
61
|
+
* the server's `dismissed` response against any concurrent terminal
|
|
62
|
+
* transition.
|
|
63
|
+
*/
|
|
64
|
+
export class HonuaOgcProcessJobRun {
|
|
65
|
+
id;
|
|
66
|
+
type;
|
|
67
|
+
client;
|
|
68
|
+
pollIntervalMs;
|
|
69
|
+
pollFn;
|
|
70
|
+
currentStatus;
|
|
71
|
+
currentProgress;
|
|
72
|
+
terminalSnapshot;
|
|
73
|
+
terminalPromise;
|
|
74
|
+
listeners = new Set();
|
|
75
|
+
constructor(options) {
|
|
76
|
+
this.client = options.client;
|
|
77
|
+
this.id = options.jobId;
|
|
78
|
+
this.type = options.processId ?? options.initialStatus?.processID ?? "unknown";
|
|
79
|
+
this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
80
|
+
this.pollFn = options.pollFn ?? ((jobId, signal) => options.client.getOgcProcessJob({ jobId, signal }));
|
|
81
|
+
const initial = options.initialStatus;
|
|
82
|
+
this.currentStatus = initial?.status ?? "accepted";
|
|
83
|
+
this.currentProgress = progressFromOgcStatus(initial);
|
|
84
|
+
}
|
|
85
|
+
get status() {
|
|
86
|
+
return this.currentStatus;
|
|
87
|
+
}
|
|
88
|
+
get progress() {
|
|
89
|
+
return this.currentProgress;
|
|
90
|
+
}
|
|
91
|
+
async poll() {
|
|
92
|
+
if (this.terminalSnapshot) {
|
|
93
|
+
return this.terminalSnapshot;
|
|
94
|
+
}
|
|
95
|
+
const ogcStatus = await this.pollFn(this.id);
|
|
96
|
+
return this.handleOgcStatus(ogcStatus);
|
|
97
|
+
}
|
|
98
|
+
watch(listener) {
|
|
99
|
+
this.listeners.add(listener);
|
|
100
|
+
return () => this.listeners.delete(listener);
|
|
101
|
+
}
|
|
102
|
+
async results() {
|
|
103
|
+
if (!this.terminalPromise) {
|
|
104
|
+
this.terminalPromise = this.runUntilTerminal();
|
|
105
|
+
}
|
|
106
|
+
return this.terminalPromise;
|
|
107
|
+
}
|
|
108
|
+
async cancel() {
|
|
109
|
+
if (this.terminalSnapshot) {
|
|
110
|
+
return this.currentStatus;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const cancelled = await this.client.cancelOgcProcessJob({ jobId: this.id });
|
|
114
|
+
const snapshot = await this.handleOgcStatus(cancelled);
|
|
115
|
+
return snapshot.status;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const statusCode = error?.statusCode;
|
|
119
|
+
// `IJobRun.cancel` is documented as idempotent: when the job is
|
|
120
|
+
// already gone (404), return the cached status. honua-server uses
|
|
121
|
+
// 409 for three distinct cases — only the terminal-race case is
|
|
122
|
+
// benign:
|
|
123
|
+
// - "Cannot dismiss completed job" → terminal race; poll for the
|
|
124
|
+
// authoritative terminal status and return it.
|
|
125
|
+
// - "Dismiss could not be confirmed" → backend dismissal request
|
|
126
|
+
// was issued but did not confirm; rethrow so callers can retry.
|
|
127
|
+
// - "Cancellation not supported" → backend lacks cancel support;
|
|
128
|
+
// rethrow so callers can branch.
|
|
129
|
+
// Any 409 with an unknown title also rethrows. The terminal-race
|
|
130
|
+
// branch only swallows the 409 when the follow-up poll reaches a
|
|
131
|
+
// terminal status; a non-terminal poll or a poll failure means the
|
|
132
|
+
// "completed job" claim cannot be confirmed and the original 409
|
|
133
|
+
// is the most honest signal.
|
|
134
|
+
if (statusCode === 404) {
|
|
135
|
+
return this.currentStatus;
|
|
136
|
+
}
|
|
137
|
+
if (statusCode === 409 && isCompletedJobConflict(error)) {
|
|
138
|
+
let fresh;
|
|
139
|
+
try {
|
|
140
|
+
fresh = await this.pollFn(this.id);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Server claimed the job is in a terminal state but the
|
|
144
|
+
// follow-up poll could not confirm it. Surface the original
|
|
145
|
+
// 409 instead of letting the poll-side error swallow it.
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
const snapshot = await this.handleOgcStatus(fresh);
|
|
149
|
+
if (!isJobTerminal(snapshot.status)) {
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
return snapshot.status;
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async runUntilTerminal() {
|
|
158
|
+
while (!this.terminalSnapshot) {
|
|
159
|
+
const ogcStatus = await this.pollFn(this.id);
|
|
160
|
+
await this.handleOgcStatus(ogcStatus);
|
|
161
|
+
if (this.terminalSnapshot)
|
|
162
|
+
break;
|
|
163
|
+
if (this.pollIntervalMs > 0) {
|
|
164
|
+
await delay(this.pollIntervalMs);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (this.terminalSnapshot.status === "successful" && this.terminalSnapshot.result) {
|
|
168
|
+
return this.terminalSnapshot.result;
|
|
169
|
+
}
|
|
170
|
+
throw makeJobFailedError(this.terminalSnapshot);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Translate an OGC `statusInfo` payload onto the canonical snapshot
|
|
174
|
+
* surface, fire watchers, and (for `successful` terminals) fetch the
|
|
175
|
+
* result document inline so the snapshot's `result.outputs` is
|
|
176
|
+
* populated by the time `runUntilTerminal` / `poll` resolves.
|
|
177
|
+
*/
|
|
178
|
+
async handleOgcStatus(ogcStatus) {
|
|
179
|
+
const status = ogcStatus.status ?? "accepted";
|
|
180
|
+
const progress = progressFromOgcStatus(ogcStatus);
|
|
181
|
+
this.currentStatus = status;
|
|
182
|
+
this.currentProgress = progress;
|
|
183
|
+
if (status === "successful") {
|
|
184
|
+
try {
|
|
185
|
+
// Per OGC API Processes §7.11.1 the document-mode result body is the
|
|
186
|
+
// outputs map itself (honua-server returns `{}` for the canonical
|
|
187
|
+
// V1 process; populated maps are keyed by output id). Wrap it into
|
|
188
|
+
// the canonical `JobResult.outputs` envelope.
|
|
189
|
+
const results = await this.client.getOgcProcessJobResults({ jobId: this.id });
|
|
190
|
+
const snapshot = {
|
|
191
|
+
status: "successful",
|
|
192
|
+
progress,
|
|
193
|
+
result: { outputs: results },
|
|
194
|
+
};
|
|
195
|
+
this.terminalSnapshot = snapshot;
|
|
196
|
+
this.notify(snapshot);
|
|
197
|
+
return snapshot;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
const failure = {
|
|
201
|
+
status: "failed",
|
|
202
|
+
progress,
|
|
203
|
+
error: {
|
|
204
|
+
code: error?.name ?? "ResultsFetchFailed",
|
|
205
|
+
message: error instanceof Error ? error.message : String(error),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
this.currentStatus = "failed";
|
|
209
|
+
this.terminalSnapshot = failure;
|
|
210
|
+
this.notify(failure);
|
|
211
|
+
return failure;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (status === "failed" || status === "dismissed") {
|
|
215
|
+
const error = terminalJobError(status, ogcStatus);
|
|
216
|
+
const snapshot = {
|
|
217
|
+
status,
|
|
218
|
+
progress,
|
|
219
|
+
...(error ? { error } : {}),
|
|
220
|
+
};
|
|
221
|
+
this.terminalSnapshot = snapshot;
|
|
222
|
+
this.notify(snapshot);
|
|
223
|
+
return snapshot;
|
|
224
|
+
}
|
|
225
|
+
const snapshot = { status, progress };
|
|
226
|
+
this.notify(snapshot);
|
|
227
|
+
return snapshot;
|
|
228
|
+
}
|
|
229
|
+
notify(snapshot) {
|
|
230
|
+
for (const listener of this.listeners) {
|
|
231
|
+
try {
|
|
232
|
+
listener(snapshot);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Listener exceptions must not break the runner; log silently.
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Error thrown when `IJobRun.results()` resolves a non-success terminal. */
|
|
241
|
+
export class HonuaJobFailedError extends Error {
|
|
242
|
+
status;
|
|
243
|
+
errorCode;
|
|
244
|
+
details;
|
|
245
|
+
constructor(message, status, errorCode, details) {
|
|
246
|
+
super(message);
|
|
247
|
+
this.name = "HonuaJobFailedError";
|
|
248
|
+
this.status = status;
|
|
249
|
+
this.errorCode = errorCode;
|
|
250
|
+
this.details = details;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Honua-server emits problem-details JSON for DELETE /jobs/{id} 409s. The
|
|
255
|
+
* `title` distinguishes the benign terminal race ("Cannot dismiss
|
|
256
|
+
* completed job") from non-benign 409s ("Dismiss could not be confirmed",
|
|
257
|
+
* "Cancellation not supported"). The detail text mirrors the title
|
|
258
|
+
* ("terminal state '...'") so we accept either as confirmation.
|
|
259
|
+
*/
|
|
260
|
+
function isCompletedJobConflict(error) {
|
|
261
|
+
const body = error?.body;
|
|
262
|
+
if (!body || typeof body !== "object")
|
|
263
|
+
return false;
|
|
264
|
+
const title = body.title;
|
|
265
|
+
const detail = body.detail;
|
|
266
|
+
if (typeof title === "string" && /cannot dismiss completed job/i.test(title)) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
if (typeof detail === "string" && /terminal state/i.test(detail)) {
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
function terminalJobError(status, ogcStatus) {
|
|
275
|
+
if (ogcStatus.exception) {
|
|
276
|
+
return { ...ogcStatus.exception };
|
|
277
|
+
}
|
|
278
|
+
// honua-server emits failure text as `statusInfo.message` (its
|
|
279
|
+
// StatusInfo DTO has no `exception` field). Fall back to the progress
|
|
280
|
+
// message so `HonuaJobFailedError.message` carries the server reason
|
|
281
|
+
// instead of the generic "non-success terminal state" default.
|
|
282
|
+
if (typeof ogcStatus.message === "string" && ogcStatus.message.length > 0) {
|
|
283
|
+
return {
|
|
284
|
+
code: status === "dismissed" ? "JobDismissed" : "JobFailed",
|
|
285
|
+
message: ogcStatus.message,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
function progressFromOgcStatus(ogcStatus) {
|
|
291
|
+
if (!ogcStatus)
|
|
292
|
+
return undefined;
|
|
293
|
+
const out = {};
|
|
294
|
+
if (typeof ogcStatus.progress === "number" && Number.isFinite(ogcStatus.progress)) {
|
|
295
|
+
out.percent = clampPercent(ogcStatus.progress);
|
|
296
|
+
}
|
|
297
|
+
if (ogcStatus.message !== undefined)
|
|
298
|
+
out.message = ogcStatus.message;
|
|
299
|
+
if (ogcStatus.updated !== undefined)
|
|
300
|
+
out.updatedAt = ogcStatus.updated;
|
|
301
|
+
if (out.percent === undefined && out.message === undefined && out.updatedAt === undefined) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
function clampPercent(value) {
|
|
307
|
+
if (value < 0)
|
|
308
|
+
return 0;
|
|
309
|
+
if (value > 100)
|
|
310
|
+
return 100;
|
|
311
|
+
return value;
|
|
312
|
+
}
|
|
313
|
+
function makeJobFailedError(snapshot) {
|
|
314
|
+
const error = snapshot.error;
|
|
315
|
+
const message = error?.message ?? `Job ended in non-success terminal state: ${snapshot.status}`;
|
|
316
|
+
return new HonuaJobFailedError(message, snapshot.status, error?.code, error?.details);
|
|
317
|
+
}
|
|
318
|
+
function delay(ms) {
|
|
319
|
+
return new Promise((resolve) => {
|
|
320
|
+
setTimeout(resolve, ms);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
export function createHonuaOgcProcesses(client) {
|
|
324
|
+
return new HonuaOgcProcesses({ client });
|
|
325
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OGC API Tiles surface. Wraps the wire methods on `HonuaClient` with a
|
|
3
|
+
* tileset-discovery friendly API and a single-tile fetch helper. The
|
|
4
|
+
* conformance class identifiers are kept internal — callers see
|
|
5
|
+
* tilesets, tile-matrix-sets, and styled-tile access through the shared
|
|
6
|
+
* vocabulary, never an `OgcApiTilesPart2DatasetMap` typename.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { HonuaClient } from "./client.js";
|
|
11
|
+
import type { HonuaOgcConformanceResponse, HonuaOgcLandingResponse, HonuaOgcTileMatrixSet, HonuaOgcTileMatrixSetsResponse, HonuaOgcTileResponse, HonuaOgcTilesetMetadata, HonuaOgcTilesetsResponse, OgcMetadataRequest, OgcTileRequest, OgcTilesetRequest, OgcTilesetsRequest } from "./types.js";
|
|
12
|
+
export interface HonuaOgcTilesOptions {
|
|
13
|
+
client: HonuaClient;
|
|
14
|
+
}
|
|
15
|
+
export interface HonuaOgcTilesetOptions {
|
|
16
|
+
client: HonuaClient;
|
|
17
|
+
collectionId: string | number;
|
|
18
|
+
tileMatrixSetId: string;
|
|
19
|
+
}
|
|
20
|
+
export type HonuaOgcCollectionTilesetRequest = Omit<OgcTilesetRequest, "collectionId" | "tileMatrixSetId">;
|
|
21
|
+
export type HonuaOgcCollectionTilesetsRequest = Omit<OgcTilesetsRequest, "collectionId">;
|
|
22
|
+
export type HonuaOgcCollectionTileRequest = Omit<OgcTileRequest, "collectionId" | "tileMatrixSetId">;
|
|
23
|
+
/**
|
|
24
|
+
* Top-level OGC API Tiles handle. Mirrors `HonuaOgcFeatures` for the
|
|
25
|
+
* tiles conformance classes.
|
|
26
|
+
*/
|
|
27
|
+
export declare class HonuaOgcTiles {
|
|
28
|
+
readonly client: HonuaClient;
|
|
29
|
+
constructor(options: HonuaOgcTilesOptions);
|
|
30
|
+
tileset(collectionId: string | number, tileMatrixSetId: string): HonuaOgcTileset;
|
|
31
|
+
landing(request?: OgcMetadataRequest): Promise<HonuaOgcLandingResponse>;
|
|
32
|
+
conformance(request?: OgcMetadataRequest): Promise<HonuaOgcConformanceResponse>;
|
|
33
|
+
tileMatrixSets(request?: OgcMetadataRequest): Promise<HonuaOgcTileMatrixSetsResponse>;
|
|
34
|
+
tileMatrixSet(tileMatrixSetId: string, request?: OgcMetadataRequest): Promise<HonuaOgcTileMatrixSet>;
|
|
35
|
+
tilesets(request: OgcTilesetsRequest): Promise<HonuaOgcTilesetsResponse>;
|
|
36
|
+
tilesetMetadata(request: OgcTilesetRequest): Promise<HonuaOgcTilesetMetadata>;
|
|
37
|
+
tile(request: OgcTileRequest): Promise<HonuaOgcTileResponse>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Bound handle for one (collection × tile-matrix-set) tileset. Drops the
|
|
41
|
+
* discovery params from the per-call surface so callers focus on tile
|
|
42
|
+
* coordinates. Styled-tile access (the OGC `/styles/{styleId}` route) is
|
|
43
|
+
* not exposed here because the Honua server does not currently implement
|
|
44
|
+
* that route; the tile path is the canonical collection tile route.
|
|
45
|
+
*/
|
|
46
|
+
export declare class HonuaOgcTileset {
|
|
47
|
+
readonly client: HonuaClient;
|
|
48
|
+
readonly collectionId: string | number;
|
|
49
|
+
readonly tileMatrixSetId: string;
|
|
50
|
+
constructor(options: HonuaOgcTilesetOptions);
|
|
51
|
+
metadata(request?: HonuaOgcCollectionTilesetRequest): Promise<HonuaOgcTilesetMetadata>;
|
|
52
|
+
tile(request: HonuaOgcCollectionTileRequest): Promise<HonuaOgcTileResponse>;
|
|
53
|
+
}
|
|
54
|
+
export declare function createHonuaOgcTiles(client: HonuaClient): HonuaOgcTiles;
|
|
55
|
+
//# sourceMappingURL=ogc-tiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ogc-tiles.d.ts","sourceRoot":"","sources":["../../../src/core/ogc-tiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EACV,2BAA2B,EAC3B,uBAAuB,EACvB,qBAAqB,EACrB,8BAA8B,EAC9B,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,gCAAgC,GAAG,IAAI,CAAC,iBAAiB,EAAE,cAAc,GAAG,iBAAiB,CAAC,CAAC;AAC3G,MAAM,MAAM,iCAAiC,GAAG,IAAI,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;AACzF,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,iBAAiB,CAAC,CAAC;AAErG;;;GAGG;AACH,qBAAa,aAAa;IACxB,SAAgB,MAAM,EAAE,WAAW,CAAC;gBAEjB,OAAO,EAAE,oBAAoB;IAIzC,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,eAAe;IAQ1E,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAI3E,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAInF,cAAc,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAIzF,aAAa,CACxB,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,qBAAqB,CAAC;IAIpB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAIxE,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAI7E,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAG1E;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,SAAgB,MAAM,EAAE,WAAW,CAAC;IACpC,SAAgB,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9C,SAAgB,eAAe,EAAE,MAAM,CAAC;gBAErB,OAAO,EAAE,sBAAsB;IAMrC,QAAQ,CAAC,OAAO,GAAE,gCAAqC,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAQ1F,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAOzF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAEtE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OGC API Tiles surface. Wraps the wire methods on `HonuaClient` with a
|
|
3
|
+
* tileset-discovery friendly API and a single-tile fetch helper. The
|
|
4
|
+
* conformance class identifiers are kept internal — callers see
|
|
5
|
+
* tilesets, tile-matrix-sets, and styled-tile access through the shared
|
|
6
|
+
* vocabulary, never an `OgcApiTilesPart2DatasetMap` typename.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Top-level OGC API Tiles handle. Mirrors `HonuaOgcFeatures` for the
|
|
12
|
+
* tiles conformance classes.
|
|
13
|
+
*/
|
|
14
|
+
export class HonuaOgcTiles {
|
|
15
|
+
client;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.client = options.client;
|
|
18
|
+
}
|
|
19
|
+
tileset(collectionId, tileMatrixSetId) {
|
|
20
|
+
return new HonuaOgcTileset({
|
|
21
|
+
client: this.client,
|
|
22
|
+
collectionId,
|
|
23
|
+
tileMatrixSetId,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async landing(request = {}) {
|
|
27
|
+
return this.client.getOgcTilesLanding(request);
|
|
28
|
+
}
|
|
29
|
+
async conformance(request = {}) {
|
|
30
|
+
return this.client.getOgcTilesConformance(request);
|
|
31
|
+
}
|
|
32
|
+
async tileMatrixSets(request = {}) {
|
|
33
|
+
return this.client.listOgcTileMatrixSets(request);
|
|
34
|
+
}
|
|
35
|
+
async tileMatrixSet(tileMatrixSetId, request = {}) {
|
|
36
|
+
return this.client.getOgcTileMatrixSet({ ...request, tileMatrixSetId });
|
|
37
|
+
}
|
|
38
|
+
async tilesets(request) {
|
|
39
|
+
return this.client.listOgcCollectionTilesets(request);
|
|
40
|
+
}
|
|
41
|
+
async tilesetMetadata(request) {
|
|
42
|
+
return this.client.getOgcCollectionTileset(request);
|
|
43
|
+
}
|
|
44
|
+
async tile(request) {
|
|
45
|
+
return this.client.fetchOgcTile(request);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Bound handle for one (collection × tile-matrix-set) tileset. Drops the
|
|
50
|
+
* discovery params from the per-call surface so callers focus on tile
|
|
51
|
+
* coordinates. Styled-tile access (the OGC `/styles/{styleId}` route) is
|
|
52
|
+
* not exposed here because the Honua server does not currently implement
|
|
53
|
+
* that route; the tile path is the canonical collection tile route.
|
|
54
|
+
*/
|
|
55
|
+
export class HonuaOgcTileset {
|
|
56
|
+
client;
|
|
57
|
+
collectionId;
|
|
58
|
+
tileMatrixSetId;
|
|
59
|
+
constructor(options) {
|
|
60
|
+
this.client = options.client;
|
|
61
|
+
this.collectionId = options.collectionId;
|
|
62
|
+
this.tileMatrixSetId = options.tileMatrixSetId;
|
|
63
|
+
}
|
|
64
|
+
async metadata(request = {}) {
|
|
65
|
+
return this.client.getOgcCollectionTileset({
|
|
66
|
+
...request,
|
|
67
|
+
collectionId: this.collectionId,
|
|
68
|
+
tileMatrixSetId: this.tileMatrixSetId,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async tile(request) {
|
|
72
|
+
return this.client.fetchOgcTile({
|
|
73
|
+
...request,
|
|
74
|
+
collectionId: this.collectionId,
|
|
75
|
+
tileMatrixSetId: this.tileMatrixSetId,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function createHonuaOgcTiles(client) {
|
|
80
|
+
return new HonuaOgcTiles({ client });
|
|
81
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal protobuf wire-format reader and Esri PBF query response decoder.
|
|
3
|
+
*
|
|
4
|
+
* Decodes `FeatureCollectionPBuffer` responses (from `f=pbf`) into the same
|
|
5
|
+
* JSON-compatible shape as `f=json`, making the binary format transparent
|
|
6
|
+
* to callers.
|
|
7
|
+
*
|
|
8
|
+
* No external protobuf library dependency. Implements only the subset of
|
|
9
|
+
* the wire format needed for the Esri PBF query schema.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Decode an Esri FeatureCollectionPBuffer response into a JSON-compatible
|
|
15
|
+
* query response object.
|
|
16
|
+
*
|
|
17
|
+
* The returned object has the same shape as an `f=json` response:
|
|
18
|
+
* `{ objectIdFieldName, geometryType, spatialReference, fields, features, ... }`
|
|
19
|
+
*
|
|
20
|
+
* @param buffer - The raw PBF bytes from a `f=pbf` response.
|
|
21
|
+
* @returns A JSON-compatible query response object.
|
|
22
|
+
*/
|
|
23
|
+
export declare function decodePbfQueryResponse(buffer: ArrayBuffer | Uint8Array): Record<string, unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Check whether a Response has a protobuf content type.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isPbfResponse(response: Response): boolean;
|
|
28
|
+
//# sourceMappingURL=pbf-decoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pbf-decoder.d.ts","sourceRoot":"","sources":["../../../src/core/pbf-decoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmkBH;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiChG;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAGzD"}
|