@honua/app-platform 0.2.6 → 0.2.7
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/control-plane/dataset-import/index.d.ts +2 -1
- package/control-plane/dataset-import/index.d.ts.map +1 -1
- package/control-plane/dataset-import/index.js +1 -0
- package/control-plane/dataset-import/server-job-source-client.d.ts +16 -0
- package/control-plane/dataset-import/server-job-source-client.d.ts.map +1 -0
- package/control-plane/dataset-import/server-job-source-client.js +143 -0
- package/control-plane/dataset-import/types.d.ts +65 -3
- package/control-plane/dataset-import/types.d.ts.map +1 -1
- package/control-plane/dataset-import/upload-client.d.ts +7 -0
- package/control-plane/dataset-import/upload-client.d.ts.map +1 -1
- package/control-plane/dataset-import/upload-client.js +14 -0
- package/map/feature-service-adapter.d.ts +3 -3
- package/map/feature-service-adapter.d.ts.map +1 -1
- package/map/feature-service-adapter.js +99 -69
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { hashDatasetImportFile } from "./file-hash.js";
|
|
2
2
|
export type { DatasetImportFileHashOptions } from "./file-hash.js";
|
|
3
|
-
export type { CreateDatasetImportTask, DatasetImportArtifactSource, DatasetImportAuthorityDescriptor, DatasetImportAuthorityRenewal, DatasetImportDestination, DatasetImportSource, DatasetImportTask, DatasetImportTaskOptions, DatasetImportTaskReference, RenewDatasetImportAuthority, } from "./types.js";
|
|
3
|
+
export type { CreateDatasetImportTask, DatasetImportArtifactSource, DatasetImportAuthorityDescriptor, DatasetImportAuthorityRenewal, DatasetImportBrowserFileSource, DatasetImportDestination, DatasetImportLocalProcessSource, DatasetImportServerJobArtifactReference, DatasetImportServerJobArtifactSource, DatasetImportServerJobSource, DatasetImportSource, DatasetImportTask, DatasetImportTaskOptions, DatasetImportTaskReference, RenewDatasetImportAuthority, DescribeServerJobImportSource, ListServerJobImportSources, ServerJobImportSourceChoice, ServerJobImportSourcePage, } from "./types.js";
|
|
4
|
+
export { DatasetImportServerJobSourceClient } from "./server-job-source-client.js";
|
|
4
5
|
export { DatasetImportTaskApiError, DatasetImportTaskClient, } from "./client.js";
|
|
5
6
|
export type { DatasetImportTaskClientOptions } from "./client.js";
|
|
6
7
|
export { DatasetImportUploadClient } from "./upload-client.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AACnE,YAAY,EACV,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,6BAA6B,EAC7B,wBAAwB,EACxB,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AACnE,YAAY,EACV,uBAAuB,EACvB,2BAA2B,EAC3B,gCAAgC,EAChC,6BAA6B,EAC7B,8BAA8B,EAC9B,wBAAwB,EACxB,+BAA+B,EAC/B,uCAAuC,EACvC,oCAAoC,EACpC,4BAA4B,EAC5B,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,EACxB,0BAA0B,EAC1B,2BAA2B,EAC3B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kCAAkC,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,YAAY,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACvE,YAAY,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,8BAA8B,EAC9B,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { hashDatasetImportFile } from "./file-hash.js";
|
|
2
|
+
export { DatasetImportServerJobSourceClient } from "./server-job-source-client.js";
|
|
2
3
|
export { DatasetImportTaskApiError, DatasetImportTaskClient, } from "./client.js";
|
|
3
4
|
export { DatasetImportUploadClient } from "./upload-client.js";
|
|
4
5
|
export { DatasetImportSubmissionClient } from "./submission-client.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DatasetImportTaskClientOptions } from "./client.js";
|
|
2
|
+
import type { DatasetImportServerJobSource, DescribeServerJobImportSource, ListServerJobImportSources, ServerJobImportSourcePage } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Optional preview Server-job source APIs. Requires an installed Server that
|
|
5
|
+
* advertises these capabilities. Discovery is metadata-only; describe verifies
|
|
6
|
+
* the original output without returning its bytes or storage location. Server
|
|
7
|
+
* authorization remains authoritative on every observation and transfer.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DatasetImportServerJobSourceClient {
|
|
10
|
+
private readonly transport;
|
|
11
|
+
private readonly targetId;
|
|
12
|
+
constructor(options: DatasetImportTaskClientOptions);
|
|
13
|
+
list(request: ListServerJobImportSources, signal?: AbortSignal): Promise<ServerJobImportSourcePage | null>;
|
|
14
|
+
describe(request: DescribeServerJobImportSource, signal?: AbortSignal): Promise<DatasetImportServerJobSource | null>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=server-job-source-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-job-source-client.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/server-job-source-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,KAAK,EACV,4BAA4B,EAC5B,6BAA6B,EAC7B,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,qBAAa,kCAAkC;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,OAAO,EAAE,8BAA8B;IAK7C,IAAI,CAAC,OAAO,EAAE,0BAA0B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IA2D1G,QAAQ,CACZ,OAAO,EAAE,6BAA6B,EACtC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC;CA4DhD"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { DatasetImportWorkspaceTransport, validId } from "./transport.js";
|
|
2
|
+
/**
|
|
3
|
+
* Optional preview Server-job source APIs. Requires an installed Server that
|
|
4
|
+
* advertises these capabilities. Discovery is metadata-only; describe verifies
|
|
5
|
+
* the original output without returning its bytes or storage location. Server
|
|
6
|
+
* authorization remains authoritative on every observation and transfer.
|
|
7
|
+
*/
|
|
8
|
+
export class DatasetImportServerJobSourceClient {
|
|
9
|
+
transport;
|
|
10
|
+
targetId;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.transport = new DatasetImportWorkspaceTransport(options);
|
|
13
|
+
this.targetId = options.targetId;
|
|
14
|
+
}
|
|
15
|
+
async list(request, signal) {
|
|
16
|
+
const { jobId, offset = 0, resultPackageId = null } = request;
|
|
17
|
+
validId(jobId);
|
|
18
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || (offset > 0 && resultPackageId === null))
|
|
19
|
+
throw new TypeError("Continuation requires a nonnegative offset and the original result package.");
|
|
20
|
+
if (resultPackageId !== null)
|
|
21
|
+
validPackage(jobId, resultPackageId);
|
|
22
|
+
const value = await this.transport.request("/dataset-import-sources/server-job-artifacts", "POST", JSON.stringify({ jobId, offset, resultPackageId }), signal, true);
|
|
23
|
+
if (value === null)
|
|
24
|
+
return null;
|
|
25
|
+
if (value.targetId !== this.targetId || value.jobId !== jobId)
|
|
26
|
+
throw new Error("The job source page changed deployment or job identity.");
|
|
27
|
+
validPackage(jobId, value.resultPackageId);
|
|
28
|
+
if (resultPackageId !== null && value.resultPackageId !== resultPackageId)
|
|
29
|
+
throw new Error("The job source page changed the original result version.");
|
|
30
|
+
// AgentWorkspaceJsonContext omits null members on the wire.
|
|
31
|
+
const nextOffset = value.nextOffset ?? null;
|
|
32
|
+
if (!Number.isSafeInteger(value.totalArtifacts) ||
|
|
33
|
+
value.totalArtifacts < offset ||
|
|
34
|
+
!Array.isArray(value.artifacts) ||
|
|
35
|
+
value.artifacts.length !== Math.min(50, value.totalArtifacts - offset) ||
|
|
36
|
+
nextOffset !== (offset + value.artifacts.length < value.totalArtifacts ? offset + value.artifacts.length : null))
|
|
37
|
+
throw new Error("The job source page has an inconsistent bounded continuation.");
|
|
38
|
+
const artifacts = value.artifacts.map((choice, index) => {
|
|
39
|
+
if (!choice ||
|
|
40
|
+
choice.artifactId !== `${jobId}:artifact:${offset + index + 1}` ||
|
|
41
|
+
typeof choice.kind !== "string" ||
|
|
42
|
+
!/^[A-Za-z][A-Za-z0-9]{0,63}$/.test(choice.kind) ||
|
|
43
|
+
typeof choice.label !== "string" ||
|
|
44
|
+
!/^[A-Za-z0-9 _.\-]{1,128}$/.test(choice.label) ||
|
|
45
|
+
typeof choice.canDescribeForImport !== "boolean")
|
|
46
|
+
throw new Error("The job source page contains an invalid artifact identity or metadata.");
|
|
47
|
+
return {
|
|
48
|
+
artifactId: choice.artifactId,
|
|
49
|
+
kind: choice.kind,
|
|
50
|
+
label: choice.label,
|
|
51
|
+
canDescribeForImport: choice.canDescribeForImport,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
// Project only the supported metadata: never propagate unexpected bulk or
|
|
55
|
+
// storage-location members to an agent through a loosely typed JSON object.
|
|
56
|
+
return {
|
|
57
|
+
targetId: value.targetId,
|
|
58
|
+
jobId,
|
|
59
|
+
resultPackageId: value.resultPackageId,
|
|
60
|
+
artifacts,
|
|
61
|
+
totalArtifacts: value.totalArtifacts,
|
|
62
|
+
nextOffset,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async describe(request, signal) {
|
|
66
|
+
const { jobId, resultPackageId, artifactId } = request;
|
|
67
|
+
validId(jobId);
|
|
68
|
+
validPackage(jobId, resultPackageId);
|
|
69
|
+
validArtifact(jobId, artifactId);
|
|
70
|
+
const source = await this.transport.request("/dataset-import-sources/server-job-artifact", "POST", JSON.stringify({ jobId, resultPackageId, artifactId }), signal, true);
|
|
71
|
+
if (source === null)
|
|
72
|
+
return null;
|
|
73
|
+
const output = source.serverJobArtifact;
|
|
74
|
+
const reference = output?.reference;
|
|
75
|
+
if (source.kind !== "server-job-artifact" ||
|
|
76
|
+
source.fileName !== "job-artifact.geojson" ||
|
|
77
|
+
!positiveInteger(source.totalBytes) ||
|
|
78
|
+
!digest(source.expectedSha256) ||
|
|
79
|
+
source.artifact != null ||
|
|
80
|
+
source.browserSelectionId != null ||
|
|
81
|
+
!reference ||
|
|
82
|
+
reference.targetId !== this.targetId ||
|
|
83
|
+
reference.jobId !== jobId ||
|
|
84
|
+
reference.resultPackageId !== resultPackageId ||
|
|
85
|
+
reference.artifactId !== artifactId ||
|
|
86
|
+
!digest(reference.referenceSha256) ||
|
|
87
|
+
!positiveInteger(output.featureCount) ||
|
|
88
|
+
(output.crsState === "known"
|
|
89
|
+
? !positiveInteger(output.sourceSrid) || output.sourceSrid > 2147483647
|
|
90
|
+
: output.crsState !== "unknown" || output.sourceSrid != null))
|
|
91
|
+
throw new Error("The job source description changed its original identity or content/coordinate contract.");
|
|
92
|
+
if (!principalText(output.producerActorId, 2048) ||
|
|
93
|
+
(output.producerTenantId != null && !principalText(output.producerTenantId, 512, true)))
|
|
94
|
+
throw new Error("The job source producer identity is outside the Server contract.");
|
|
95
|
+
return {
|
|
96
|
+
kind: "server-job-artifact",
|
|
97
|
+
fileName: source.fileName,
|
|
98
|
+
totalBytes: source.totalBytes,
|
|
99
|
+
expectedSha256: source.expectedSha256,
|
|
100
|
+
serverJobArtifact: {
|
|
101
|
+
reference: {
|
|
102
|
+
targetId: this.targetId,
|
|
103
|
+
jobId,
|
|
104
|
+
resultPackageId,
|
|
105
|
+
artifactId,
|
|
106
|
+
referenceSha256: reference.referenceSha256,
|
|
107
|
+
},
|
|
108
|
+
producerActorId: output.producerActorId,
|
|
109
|
+
producerTenantId: output.producerTenantId ?? null,
|
|
110
|
+
crsState: output.crsState,
|
|
111
|
+
sourceSrid: output.sourceSrid ?? null,
|
|
112
|
+
featureCount: output.featureCount,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function validPackage(jobId, value) {
|
|
118
|
+
validId(value);
|
|
119
|
+
if (!value.startsWith(`${jobId}:v`) || !/^[1-9][0-9]*$/.test(value.slice(jobId.length + 2)))
|
|
120
|
+
throw new TypeError("The original versioned job result package is required.");
|
|
121
|
+
}
|
|
122
|
+
function validArtifact(jobId, value) {
|
|
123
|
+
validId(value);
|
|
124
|
+
const prefix = `${jobId}:artifact:`;
|
|
125
|
+
if (!value.startsWith(prefix) || !/^[1-9][0-9]*$/.test(value.slice(prefix.length)))
|
|
126
|
+
throw new TypeError("The original job artifact identity is required.");
|
|
127
|
+
}
|
|
128
|
+
function positiveInteger(value) {
|
|
129
|
+
return Number.isSafeInteger(value) && value > 0;
|
|
130
|
+
}
|
|
131
|
+
function digest(value) {
|
|
132
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
133
|
+
}
|
|
134
|
+
// Principal identifiers have different Server bounds from workspace/job IDs.
|
|
135
|
+
function principalText(value, maximum, allowEmpty = false) {
|
|
136
|
+
return (typeof value === "string" &&
|
|
137
|
+
(allowEmpty || value.length > 0) &&
|
|
138
|
+
value.length <= maximum &&
|
|
139
|
+
Array.from(value).every((character) => {
|
|
140
|
+
const code = character.charCodeAt(0);
|
|
141
|
+
return code > 31 && (code < 127 || code > 159);
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
@@ -10,14 +10,75 @@ export interface DatasetImportArtifactSource {
|
|
|
10
10
|
readonly runId: string;
|
|
11
11
|
readonly path: string;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
readonly kind: "browser-file" | "local-process-artifact";
|
|
13
|
+
interface DatasetImportSourceMetadata {
|
|
15
14
|
readonly fileName: string;
|
|
16
15
|
readonly totalBytes: number;
|
|
17
16
|
readonly expectedSha256?: string | null;
|
|
18
|
-
|
|
17
|
+
}
|
|
18
|
+
export interface DatasetImportBrowserFileSource extends DatasetImportSourceMetadata {
|
|
19
|
+
readonly kind: "browser-file";
|
|
19
20
|
/** Original human file selection captured by the immutable originating turn. */
|
|
20
21
|
readonly browserSelectionId?: string | null;
|
|
22
|
+
readonly artifact?: null;
|
|
23
|
+
readonly serverJobArtifact?: null;
|
|
24
|
+
}
|
|
25
|
+
export interface DatasetImportLocalProcessSource extends DatasetImportSourceMetadata {
|
|
26
|
+
readonly kind: "local-process-artifact";
|
|
27
|
+
readonly artifact: DatasetImportArtifactSource;
|
|
28
|
+
readonly browserSelectionId?: null;
|
|
29
|
+
readonly serverJobArtifact?: null;
|
|
30
|
+
}
|
|
31
|
+
/** Each source kind carries its own canonical reference rather than optional mixed identities. */
|
|
32
|
+
export type DatasetImportSource = DatasetImportBrowserFileSource | DatasetImportLocalProcessSource | DatasetImportServerJobSource;
|
|
33
|
+
/** Exact Server-owned result identity; no caller-supplied location or bulk content. */
|
|
34
|
+
export interface DatasetImportServerJobArtifactReference {
|
|
35
|
+
readonly targetId: string;
|
|
36
|
+
readonly jobId: string;
|
|
37
|
+
readonly resultPackageId: string;
|
|
38
|
+
readonly artifactId: string;
|
|
39
|
+
readonly referenceSha256: string;
|
|
40
|
+
}
|
|
41
|
+
/** Server recomputes this description at task creation; it is not execution authority. */
|
|
42
|
+
export interface DatasetImportServerJobArtifactSource {
|
|
43
|
+
readonly reference: DatasetImportServerJobArtifactReference;
|
|
44
|
+
readonly producerActorId: string;
|
|
45
|
+
readonly producerTenantId: string | null;
|
|
46
|
+
readonly crsState: "known" | "unknown";
|
|
47
|
+
readonly sourceSrid: number | null;
|
|
48
|
+
readonly featureCount: number;
|
|
49
|
+
}
|
|
50
|
+
export interface DatasetImportServerJobSource extends DatasetImportSourceMetadata {
|
|
51
|
+
readonly kind: "server-job-artifact";
|
|
52
|
+
readonly expectedSha256: string;
|
|
53
|
+
readonly serverJobArtifact: DatasetImportServerJobArtifactSource;
|
|
54
|
+
readonly artifact?: null;
|
|
55
|
+
readonly browserSelectionId?: null;
|
|
56
|
+
}
|
|
57
|
+
export interface ListServerJobImportSources {
|
|
58
|
+
readonly jobId: string;
|
|
59
|
+
readonly offset?: number;
|
|
60
|
+
/** Required for continuation, preserving the exact original result version. */
|
|
61
|
+
readonly resultPackageId?: string | null;
|
|
62
|
+
}
|
|
63
|
+
export interface DescribeServerJobImportSource {
|
|
64
|
+
readonly jobId: string;
|
|
65
|
+
readonly resultPackageId: string;
|
|
66
|
+
readonly artifactId: string;
|
|
67
|
+
}
|
|
68
|
+
export interface ServerJobImportSourceChoice {
|
|
69
|
+
readonly artifactId: string;
|
|
70
|
+
readonly kind: string;
|
|
71
|
+
readonly label: string;
|
|
72
|
+
/** Envelope eligibility only; describe still verifies content, CRS and current access. */
|
|
73
|
+
readonly canDescribeForImport: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface ServerJobImportSourcePage {
|
|
76
|
+
readonly targetId: string;
|
|
77
|
+
readonly jobId: string;
|
|
78
|
+
readonly resultPackageId: string;
|
|
79
|
+
readonly artifacts: readonly ServerJobImportSourceChoice[];
|
|
80
|
+
readonly totalArtifacts: number;
|
|
81
|
+
readonly nextOffset: number | null;
|
|
21
82
|
}
|
|
22
83
|
export interface DatasetImportTaskOptions {
|
|
23
84
|
/** Current new-table slice supports Append (1); occupied destinations remain unsupported. */
|
|
@@ -147,4 +208,5 @@ export interface DatasetImportSubmissionReceipt {
|
|
|
147
208
|
readonly acceptBefore?: string | null;
|
|
148
209
|
readonly job?: DatasetImportJobReceipt | null;
|
|
149
210
|
}
|
|
211
|
+
export {};
|
|
150
212
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/types.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACD,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,13 @@ export declare class DatasetImportUploadClient {
|
|
|
14
14
|
/** Read-only recovery of a known session, preserving its immutable fields and terminal receipts. */
|
|
15
15
|
reconcile(reference: DatasetImportTaskReference, original: DatasetImportUploadReceipt, signal?: AbortSignal): Promise<DatasetImportUploadReceipt | null>;
|
|
16
16
|
create(reference: DatasetImportTaskReference, signal?: AbortSignal): Promise<DatasetImportUploadReceipt>;
|
|
17
|
+
/**
|
|
18
|
+
* Transfer the original task's Server-owned job output through the canonical
|
|
19
|
+
* upload coordinator and retain it. This does not submit an import. A lost
|
|
20
|
+
* reply remains unknown: recover with read/reconcile before explicitly resuming
|
|
21
|
+
* this same task. Never create a replacement task or automatically retry.
|
|
22
|
+
*/
|
|
23
|
+
transferServerJobArtifact(reference: DatasetImportTaskReference, signal?: AbortSignal): Promise<DatasetImportUploadReceipt>;
|
|
17
24
|
appendChunk(reference: DatasetImportTaskReference, original: DatasetImportUploadReceipt, chunk: Blob, signal?: AbortSignal): Promise<DatasetImportUploadReceipt>;
|
|
18
25
|
seal(reference: DatasetImportTaskReference, original: DatasetImportUploadReceipt, signal?: AbortSignal): Promise<DatasetImportUploadReceipt>;
|
|
19
26
|
retainSource(reference: DatasetImportTaskReference, original: DatasetImportUploadReceipt, signal?: AbortSignal): Promise<DatasetImportUploadReceipt>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-client.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/upload-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAGlE,OAAO,KAAK,EACV,0BAA0B,EAC1B,+BAA+B,EAC/B,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAKpB;;;;;GAKG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;gBAChD,OAAO,EAAE,8BAA8B;IAI7C,YAAY,CAChB,SAAS,EAAE,0BAA0B,EACrC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,+BAA+B,GAAG,IAAI,CAAC;IAqB5C,IAAI,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;IAanH,oGAAoG;IAC9F,SAAS,CACb,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;IAcvC,MAAM,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"upload-client.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/dataset-import/upload-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAGlE,OAAO,KAAK,EACV,0BAA0B,EAC1B,+BAA+B,EAC/B,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAKpB;;;;;GAKG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;gBAChD,OAAO,EAAE,8BAA8B;IAI7C,YAAY,CAChB,SAAS,EAAE,0BAA0B,EACrC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,+BAA+B,GAAG,IAAI,CAAC;IAqB5C,IAAI,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;IAanH,oGAAoG;IAC9F,SAAS,CACb,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;IAcvC,MAAM,CAAC,SAAS,EAAE,0BAA0B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAQ9G;;;;;OAKG;IACG,yBAAyB,CAC7B,SAAS,EAAE,0BAA0B,EACrC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC;IAchC,WAAW,CACf,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,KAAK,EAAE,IAAI,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC;IAqBhC,IAAI,CACR,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC;IAGhC,YAAY,CAChB,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC;IAGhC,MAAM,CACV,SAAS,EAAE,0BAA0B,EACrC,QAAQ,EAAE,0BAA0B,EACpC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC;YAaxB,MAAM;CAmBrB"}
|
|
@@ -48,6 +48,20 @@ export class DatasetImportUploadClient {
|
|
|
48
48
|
validate(value, pinned);
|
|
49
49
|
return value;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Transfer the original task's Server-owned job output through the canonical
|
|
53
|
+
* upload coordinator and retain it. This does not submit an import. A lost
|
|
54
|
+
* reply remains unknown: recover with read/reconcile before explicitly resuming
|
|
55
|
+
* this same task. Never create a replacement task or automatically retry.
|
|
56
|
+
*/
|
|
57
|
+
async transferServerJobArtifact(reference, signal) {
|
|
58
|
+
const pinned = pin(reference);
|
|
59
|
+
const value = await this.transport.request(`${path(pinned)}/server-job-artifact`, "POST", JSON.stringify({ taskContentHash: pinned.contentHash }), signal);
|
|
60
|
+
validate(value, pinned);
|
|
61
|
+
if (value.state !== "sealed" || value.sourceRetention == null)
|
|
62
|
+
throw new Error("The Server job transfer did not return a sealed retained source receipt.");
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
51
65
|
async appendChunk(reference, original, chunk, signal) {
|
|
52
66
|
const pinned = pin(reference);
|
|
53
67
|
const session = captureSession(original, pinned);
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
25
|
import type { HonuaClient } from "../core/client.js";
|
|
26
|
-
import type { EsriGeometryType } from "../core/types.js";
|
|
26
|
+
import type { EsriGeometryType, HonuaLayerMetadata } from "../core/types.js";
|
|
27
27
|
import type { HonuaMap } from "./honua-map.js";
|
|
28
28
|
/** A GeoJSON geometry produced by the adapter. */
|
|
29
29
|
export interface AdapterGeoJsonGeometry {
|
|
@@ -81,7 +81,7 @@ export interface FeatureServiceAdapterMap {
|
|
|
81
81
|
* multipoint, polyline, polygon, envelope). Returns `null` when the geometry is
|
|
82
82
|
* absent or unrecognised so the feature still renders attribute-only.
|
|
83
83
|
*/
|
|
84
|
-
export declare function esriGeometryToGeoJson(geometry: Record<string, unknown> | null | undefined, geometryType: EsriGeometryType | undefined): AdapterGeoJsonGeometry | null;
|
|
84
|
+
export declare function esriGeometryToGeoJson(geometry: Record<string, unknown> | null | undefined, geometryType: EsriGeometryType | undefined, dimensions?: Pick<HonuaLayerMetadata, "hasZ" | "hasM">): AdapterGeoJsonGeometry | null;
|
|
85
85
|
/**
|
|
86
86
|
* Convert an array of Esri features (attributes + geometry) into a GeoJSON
|
|
87
87
|
* `FeatureCollection`.
|
|
@@ -89,7 +89,7 @@ export declare function esriGeometryToGeoJson(geometry: Record<string, unknown>
|
|
|
89
89
|
export declare function esriFeaturesToGeoJson(features: ReadonlyArray<{
|
|
90
90
|
attributes?: Record<string, unknown>;
|
|
91
91
|
geometry?: Record<string, unknown> | null;
|
|
92
|
-
}>, geometryType: EsriGeometryType | undefined): AdapterGeoJsonFeatureCollection;
|
|
92
|
+
}>, geometryType: EsriGeometryType | undefined, dimensions?: Pick<HonuaLayerMetadata, "hasZ" | "hasM">): AdapterGeoJsonFeatureCollection;
|
|
93
93
|
/**
|
|
94
94
|
* Fetch a Honua feature-service layer through the SDK and return a standard
|
|
95
95
|
* MapLibre `geojson` source specification that the renderer renders natively.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-service-adapter.d.ts","sourceRoot":"","sources":["../../../src/map/feature-service-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-service-adapter.d.ts","sourceRoot":"","sources":["../../../src/map/feature-service-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE7E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,kDAAkD;AAClD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,0DAA0D;AAC1D,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,+BAA+B,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wEAAwE;AACxE,MAAM,WAAW,qCAAqC;IACpD,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AA+CD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACpD,YAAY,EAAE,gBAAgB,GAAG,SAAS,EAC1C,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,GACrD,sBAAsB,GAAG,IAAI,CA4C/B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,CAAC;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAAE,CAAC,EAC5G,YAAY,EAAE,gBAAgB,GAAG,SAAS,EAC1C,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,GACrD,+BAA+B,CASjC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,qCAA0C,GAClD,OAAO,CAAC,kCAAkC,CAAC,CAoC7C;AAED,4DAA4D;AAC5D,MAAM,WAAW,wCAAwC;IACvD,mEAAmE;IACnE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,kEAAkE;IAClE,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,8DAA8D;AAC9D,MAAM,WAAW,yCAA0C,SAAQ,qCAAqC;IACtG;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAsB,kCAAkC,CACtD,GAAG,EAAE,wBAAwB,EAC7B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,yCAA8C,GACtD,OAAO,CAAC,wCAAwC,CAAC,CA4DnD"}
|
|
@@ -22,8 +22,46 @@
|
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
|
+
import { esriGeometryToGeoJSON } from "../core/esri-geojson.js";
|
|
25
26
|
import { HonuaFeatureLayer } from "../core/surfaces.js";
|
|
26
27
|
import { parseFeatureLayerUrl } from "../esri-compat/url.js";
|
|
28
|
+
/** Validate an unambiguous shape when the service cannot declare its geometry type. */
|
|
29
|
+
function isValidGenericGeometry(geometry) {
|
|
30
|
+
const shapes = [
|
|
31
|
+
"x" in geometry || "y" in geometry,
|
|
32
|
+
"points" in geometry,
|
|
33
|
+
"paths" in geometry,
|
|
34
|
+
"rings" in geometry,
|
|
35
|
+
["xmin", "ymin", "xmax", "ymax"].some((key) => key in geometry),
|
|
36
|
+
];
|
|
37
|
+
if (shapes.filter(Boolean).length !== 1)
|
|
38
|
+
return false;
|
|
39
|
+
if (shapes[0])
|
|
40
|
+
return asFiniteNumber(geometry.x) !== undefined && asFiniteNumber(geometry.y) !== undefined;
|
|
41
|
+
if (shapes[1])
|
|
42
|
+
return (Array.isArray(geometry.points) &&
|
|
43
|
+
geometry.points.length > 0 &&
|
|
44
|
+
geometry.points.every((point) => asPosition(point) !== undefined));
|
|
45
|
+
if (shapes[2] || shapes[3]) {
|
|
46
|
+
const parts = shapes[2] ? geometry.paths : geometry.rings;
|
|
47
|
+
const polygon = shapes[3];
|
|
48
|
+
return (Array.isArray(parts) &&
|
|
49
|
+
parts.length > 0 &&
|
|
50
|
+
parts.every((part) => {
|
|
51
|
+
if (!Array.isArray(part) ||
|
|
52
|
+
part.length < (polygon ? 4 : 2) ||
|
|
53
|
+
!part.every((point) => asPosition(point) !== undefined))
|
|
54
|
+
return false;
|
|
55
|
+
if (!polygon)
|
|
56
|
+
return true;
|
|
57
|
+
const first = asPosition(part[0]);
|
|
58
|
+
const last = asPosition(part[part.length - 1]);
|
|
59
|
+
return first[0] === last[0] && first[1] === last[1];
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
const bounds = [geometry.xmin, geometry.ymin, geometry.xmax, geometry.ymax].map(asFiniteNumber);
|
|
63
|
+
return bounds.every((value) => value !== undefined) && bounds[0] <= bounds[2] && bounds[1] <= bounds[3];
|
|
64
|
+
}
|
|
27
65
|
/**
|
|
28
66
|
* Convert a single Esri geometry into a GeoJSON geometry.
|
|
29
67
|
*
|
|
@@ -31,75 +69,68 @@ import { parseFeatureLayerUrl } from "../esri-compat/url.js";
|
|
|
31
69
|
* multipoint, polyline, polygon, envelope). Returns `null` when the geometry is
|
|
32
70
|
* absent or unrecognised so the feature still renders attribute-only.
|
|
33
71
|
*/
|
|
34
|
-
export function esriGeometryToGeoJson(geometry, geometryType) {
|
|
35
|
-
if (!geometry)
|
|
72
|
+
export function esriGeometryToGeoJson(geometry, geometryType, dimensions) {
|
|
73
|
+
if (!geometry || typeof geometry !== "object" || Array.isArray(geometry))
|
|
36
74
|
return null;
|
|
75
|
+
let shape;
|
|
76
|
+
if (geometryType === undefined || geometryType === null || geometryType === "esriGeometryNull") {
|
|
77
|
+
shape = geometry;
|
|
37
78
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (geometryType === "esriGeometryPoint" || (geometry.x !== undefined && geometry.y !== undefined)) {
|
|
41
|
-
const x = asFiniteNumber(geometry.x);
|
|
42
|
-
const y = asFiniteNumber(geometry.y);
|
|
43
|
-
if (x === undefined || y === undefined)
|
|
44
|
-
return null;
|
|
45
|
-
return { type: "Point", coordinates: [x, y] };
|
|
79
|
+
else if (geometryType === "esriGeometryPoint" || (geometry.x !== undefined && geometry.y !== undefined)) {
|
|
80
|
+
shape = { x: geometry.x, y: geometry.y, z: geometry.z };
|
|
46
81
|
}
|
|
47
|
-
if (geometryType === "esriGeometryMultipoint") {
|
|
48
|
-
|
|
49
|
-
.map(asCoordinatePair)
|
|
50
|
-
.filter((value) => value !== undefined);
|
|
51
|
-
return { type: "MultiPoint", coordinates: points };
|
|
82
|
+
else if (geometryType === "esriGeometryMultipoint") {
|
|
83
|
+
shape = { points: geometry.points };
|
|
52
84
|
}
|
|
53
|
-
if (geometryType === "esriGeometryPolyline") {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return { type: "LineString", coordinates: paths[0] };
|
|
59
|
-
}
|
|
60
|
-
return { type: "MultiLineString", coordinates: paths };
|
|
85
|
+
else if (geometryType === "esriGeometryPolyline") {
|
|
86
|
+
shape = { paths: geometry.paths };
|
|
87
|
+
}
|
|
88
|
+
else if (geometryType === "esriGeometryPolygon") {
|
|
89
|
+
shape = { rings: geometry.rings };
|
|
61
90
|
}
|
|
62
|
-
if (geometryType === "
|
|
63
|
-
|
|
64
|
-
.map(asCoordinateArray)
|
|
65
|
-
.filter((ring) => ring.length > 0);
|
|
66
|
-
// MapLibre does not enforce GeoJSON ring winding for rendering, so the
|
|
67
|
-
// adapter passes Esri rings through as a Polygon without re-nesting.
|
|
68
|
-
return { type: "Polygon", coordinates: rings };
|
|
91
|
+
else if (geometryType === "esriGeometryEnvelope") {
|
|
92
|
+
shape = { xmin: geometry.xmin, ymin: geometry.ymin, xmax: geometry.xmax, ymax: geometry.ymax };
|
|
69
93
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
else
|
|
95
|
+
return null;
|
|
96
|
+
// One converter owns exterior/hole grouping, winding and coordinate ordinates
|
|
97
|
+
// for both metadata-declared and structurally inferred feature geometry.
|
|
98
|
+
if (!isValidGenericGeometry(shape))
|
|
99
|
+
return null;
|
|
100
|
+
// Optional Esri Z/M can be null. Keep finite spatial coordinates, omit
|
|
101
|
+
// absent Z, and never treat a measure as GeoJSON altitude.
|
|
102
|
+
const converted = esriGeometryToGeoJSON({ ...shape, z: asFiniteNumber(shape.z) });
|
|
103
|
+
if (!converted || !("coordinates" in converted))
|
|
104
|
+
return null;
|
|
105
|
+
const hasZ = asFiniteNumber(shape.z) !== undefined || (geometry.hasZ ?? dimensions?.hasZ) === true;
|
|
106
|
+
const coordinates = projectCoordinates(converted.coordinates, hasZ);
|
|
107
|
+
const polygons = converted.type === "Polygon"
|
|
108
|
+
? [coordinates]
|
|
109
|
+
: converted.type === "MultiPolygon"
|
|
110
|
+
? coordinates
|
|
111
|
+
: [];
|
|
112
|
+
for (const polygon of polygons) {
|
|
113
|
+
for (const ring of polygon) {
|
|
114
|
+
const first = ring[0];
|
|
115
|
+
const last = ring[ring.length - 1];
|
|
116
|
+
// Close after dimension projection, comparing every retained ordinate.
|
|
117
|
+
// Append the first position so a distinct final Z is not discarded.
|
|
118
|
+
if (first && last && (first.length !== last.length || first.some((value, index) => value !== last[index])))
|
|
119
|
+
ring.push([...first]);
|
|
77
120
|
}
|
|
78
|
-
return {
|
|
79
|
-
type: "Polygon",
|
|
80
|
-
coordinates: [
|
|
81
|
-
[
|
|
82
|
-
[xmin, ymin],
|
|
83
|
-
[xmax, ymin],
|
|
84
|
-
[xmax, ymax],
|
|
85
|
-
[xmin, ymax],
|
|
86
|
-
[xmin, ymin],
|
|
87
|
-
],
|
|
88
|
-
],
|
|
89
|
-
};
|
|
90
121
|
}
|
|
91
|
-
return
|
|
122
|
+
return { type: converted.type, coordinates };
|
|
92
123
|
}
|
|
93
124
|
/**
|
|
94
125
|
* Convert an array of Esri features (attributes + geometry) into a GeoJSON
|
|
95
126
|
* `FeatureCollection`.
|
|
96
127
|
*/
|
|
97
|
-
export function esriFeaturesToGeoJson(features, geometryType) {
|
|
128
|
+
export function esriFeaturesToGeoJson(features, geometryType, dimensions) {
|
|
98
129
|
return {
|
|
99
130
|
type: "FeatureCollection",
|
|
100
131
|
features: features.map((feature) => ({
|
|
101
132
|
type: "Feature",
|
|
102
|
-
geometry: esriGeometryToGeoJson(feature.geometry ?? null, geometryType),
|
|
133
|
+
geometry: esriGeometryToGeoJson(feature.geometry ?? null, geometryType, dimensions),
|
|
103
134
|
properties: { ...(feature.attributes ?? {}) },
|
|
104
135
|
})),
|
|
105
136
|
};
|
|
@@ -136,8 +167,8 @@ export async function loadHonuaFeatureServiceGeoJson(client, url, options = {})
|
|
|
136
167
|
};
|
|
137
168
|
const metadataPromise = layer.metadata(options.signal ? { signal: options.signal } : {}).catch(() => undefined);
|
|
138
169
|
const features = await layer.queryFeaturesAll(request);
|
|
139
|
-
const
|
|
140
|
-
const data = esriFeaturesToGeoJson(features, geometryType);
|
|
170
|
+
const metadata = await metadataPromise;
|
|
171
|
+
const data = esriFeaturesToGeoJson(features, metadata?.geometryType, metadata);
|
|
141
172
|
return {
|
|
142
173
|
type: "geojson",
|
|
143
174
|
data,
|
|
@@ -260,20 +291,19 @@ async function allSettledLimited(values, concurrency, worker) {
|
|
|
260
291
|
function asFiniteNumber(value) {
|
|
261
292
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
262
293
|
}
|
|
263
|
-
function
|
|
264
|
-
return Array.isArray(value)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const y = asFiniteNumber(value[1]);
|
|
271
|
-
if (x === undefined || y === undefined)
|
|
272
|
-
return undefined;
|
|
273
|
-
return [x, y];
|
|
294
|
+
function asPosition(value) {
|
|
295
|
+
return Array.isArray(value) &&
|
|
296
|
+
value.length >= 2 &&
|
|
297
|
+
asFiniteNumber(value[0]) !== undefined &&
|
|
298
|
+
asFiniteNumber(value[1]) !== undefined
|
|
299
|
+
? value
|
|
300
|
+
: undefined;
|
|
274
301
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
302
|
+
/** GeoJSON has spatial coordinates, not Esri measures; absent optional Z stays 2D. */
|
|
303
|
+
function projectCoordinates(coordinates, hasZ) {
|
|
304
|
+
if (!Array.isArray(coordinates))
|
|
305
|
+
return coordinates;
|
|
306
|
+
if (Array.isArray(coordinates[0]))
|
|
307
|
+
return coordinates.map((part) => projectCoordinates(part, hasZ));
|
|
308
|
+
return coordinates.slice(0, hasZ && asFiniteNumber(coordinates[2]) !== undefined ? 3 : 2);
|
|
279
309
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honua/app-platform",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "Honua application-platform surfaces: app-shell, workspace, scene, operator, studio, and hosted-product clients",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gis",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"proj4": "^2.20.9"
|
|
122
122
|
},
|
|
123
123
|
"peerDependencies": {
|
|
124
|
-
"@honua/sdk": "0.2.
|
|
124
|
+
"@honua/sdk": "0.2.7",
|
|
125
125
|
"@bufbuild/protobuf": "^2.0.0",
|
|
126
126
|
"@connectrpc/connect": "^2.0.0",
|
|
127
127
|
"@connectrpc/connect-web": "^2.0.0",
|