@honua/react 0.1.7-beta.0 → 0.1.10-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/control-plane/admin-client.d.ts +89 -0
- package/control-plane/admin-client.d.ts.map +1 -0
- package/control-plane/admin-client.js +200 -0
- package/control-plane/client.d.ts +1 -1
- package/control-plane/client.d.ts.map +1 -1
- package/control-plane/client.js +145 -11
- package/control-plane/commands/catalog.d.ts +133 -0
- package/control-plane/commands/catalog.d.ts.map +1 -0
- package/control-plane/commands/catalog.js +365 -0
- package/control-plane/commands/errors.d.ts +96 -0
- package/control-plane/commands/errors.d.ts.map +1 -0
- package/control-plane/commands/errors.js +130 -0
- package/control-plane/commands/identity.d.ts +71 -0
- package/control-plane/commands/identity.d.ts.map +1 -0
- package/control-plane/commands/identity.js +0 -0
- package/control-plane/commands/index.d.ts +39 -0
- package/control-plane/commands/index.d.ts.map +1 -0
- package/control-plane/commands/index.js +34 -0
- package/control-plane/commands/runtime.d.ts +146 -0
- package/control-plane/commands/runtime.d.ts.map +1 -0
- package/control-plane/commands/runtime.js +330 -0
- package/control-plane/commands/types.d.ts +228 -0
- package/control-plane/commands/types.d.ts.map +1 -0
- package/control-plane/commands/types.js +30 -0
- package/control-plane/commands/validate.d.ts +27 -0
- package/control-plane/commands/validate.d.ts.map +1 -0
- package/control-plane/commands/validate.js +132 -0
- package/control-plane/generated/admin-api.d.ts +30265 -0
- package/control-plane/generated/admin-api.d.ts.map +1 -0
- package/control-plane/generated/admin-api.js +5 -0
- package/control-plane/generated/admin-operations.d.ts +4053 -0
- package/control-plane/generated/admin-operations.d.ts.map +1 -0
- package/control-plane/generated/admin-operations.js +820 -0
- package/control-plane/index.d.ts +11 -0
- package/control-plane/index.d.ts.map +1 -1
- package/control-plane/index.js +8 -0
- package/control-plane/types.d.ts +14 -0
- package/control-plane/types.d.ts.map +1 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +29 -31
- package/core/credential-redaction.d.ts +163 -0
- package/core/credential-redaction.d.ts.map +1 -0
- package/core/credential-redaction.js +389 -0
- package/core/error-classifications.d.ts +15 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +15 -0
- package/core/error-code-registry.d.ts +15 -0
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +15 -0
- package/core/error-envelope.d.ts +31 -0
- package/core/error-envelope.d.ts.map +1 -1
- package/core/error-envelope.js +11 -0
- package/core/errors.d.ts +15 -3
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +254 -2
- package/core/geometry-input-sr.d.ts +3 -0
- package/core/geometry-input-sr.d.ts.map +1 -0
- package/core/geometry-input-sr.js +28 -0
- package/core/geoservices.d.ts.map +1 -1
- package/core/geoservices.js +33 -6
- package/core/grpc-adapter.d.ts +2 -2
- package/core/grpc-adapter.d.ts.map +1 -1
- package/core/grpc-adapter.js +41 -9
- package/core/job-run-errors.d.ts +10 -0
- package/core/job-run-errors.d.ts.map +1 -0
- package/core/job-run-errors.js +14 -0
- package/core/job-run-lifecycle.d.ts +34 -0
- package/core/job-run-lifecycle.d.ts.map +1 -0
- package/core/job-run-lifecycle.js +193 -0
- package/core/ogc-processes.d.ts +38 -31
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +123 -173
- package/core/pbf-decoder.d.ts.map +1 -1
- package/core/pbf-decoder.js +16 -4
- package/core/process-runner.js +15 -100
- package/core/protocol-transport.d.ts +6 -1
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/request-pipeline.d.ts +6 -3
- package/core/request-pipeline.d.ts.map +1 -1
- package/core/request-pipeline.js +28 -11
- package/core/spatial-filter.d.ts +4 -4
- package/core/spatial-filter.d.ts.map +1 -1
- package/core/spatial-filter.js +7 -7
- package/core/surfaces.d.ts +2 -8
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +21 -112
- package/core/types.d.ts +21 -9
- package/core/types.d.ts.map +1 -1
- package/esri-compat/class-breaks-renderer.d.ts +2 -0
- package/esri-compat/class-breaks-renderer.d.ts.map +1 -1
- package/esri-compat/class-breaks-renderer.js +7 -0
- package/esri-compat/controls.d.ts +10 -1
- package/esri-compat/controls.d.ts.map +1 -1
- package/esri-compat/controls.js +86 -2
- package/esri-compat/directions.d.ts +35 -0
- package/esri-compat/directions.d.ts.map +1 -1
- package/esri-compat/directions.js +153 -2
- package/esri-compat/expand.d.ts +1 -0
- package/esri-compat/expand.d.ts.map +1 -1
- package/esri-compat/expand.js +61 -0
- package/esri-compat/feature-layer.d.ts +29 -4
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +335 -13
- package/esri-compat/geometry-engine.d.ts +4 -0
- package/esri-compat/geometry-engine.d.ts.map +1 -1
- package/esri-compat/geometry-engine.js +8 -1
- package/esri-compat/graphic.d.ts +7 -4
- package/esri-compat/graphic.d.ts.map +1 -1
- package/esri-compat/legend.d.ts +2 -1
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +15 -0
- package/esri-compat/map-view-mount.d.ts +48 -0
- package/esri-compat/map-view-mount.d.ts.map +1 -0
- package/esri-compat/map-view-mount.js +344 -0
- package/esri-compat/map-view.d.ts +38 -6
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +467 -33
- package/esri-compat/portal.d.ts +2 -0
- package/esri-compat/portal.d.ts.map +1 -1
- package/esri-compat/portal.js +7 -2
- package/esri-compat/renderer-objects.d.ts +7 -2
- package/esri-compat/renderer-objects.d.ts.map +1 -1
- package/esri-compat/renderer-objects.js +16 -5
- package/esri-compat/route-layer.d.ts +8 -0
- package/esri-compat/route-layer.d.ts.map +1 -1
- package/esri-compat/route-layer.js +24 -4
- package/esri-compat/route-task.d.ts +5 -1
- package/esri-compat/route-task.d.ts.map +1 -1
- package/esri-compat/route-task.js +119 -7
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/scene-view.js +1 -0
- package/esri-compat/search.d.ts +2 -1
- package/esri-compat/search.d.ts.map +1 -1
- package/esri-compat/search.js +52 -2
- package/esri-compat/unique-value-renderer.d.ts +2 -0
- package/esri-compat/unique-value-renderer.d.ts.map +1 -1
- package/esri-compat/unique-value-renderer.js +7 -0
- package/esri-compat/web-map.d.ts +10 -0
- package/esri-compat/web-map.d.ts.map +1 -1
- package/esri-compat/web-map.js +102 -0
- package/gen/geospatial/v1/common_pb.d.ts +514 -0
- package/gen/geospatial/v1/common_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/common_pb.js +335 -0
- package/gen/geospatial/v1/execution_types_pb.d.ts +1186 -0
- package/gen/geospatial/v1/execution_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/execution_types_pb.js +396 -0
- package/gen/geospatial/v1/feature_service_pb.d.ts +403 -0
- package/gen/geospatial/v1/feature_service_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/feature_service_pb.js +47 -0
- package/gen/geospatial/v1/index.d.ts +5 -0
- package/gen/geospatial/v1/index.d.ts.map +1 -0
- package/gen/geospatial/v1/index.js +9 -0
- package/gen/geospatial/v1/spatial_types_pb.d.ts +285 -0
- package/gen/geospatial/v1/spatial_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/spatial_types_pb.js +58 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts +379 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.js +151 -0
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/projection.js +10 -1
- package/map/webmap-maplibre.d.ts +2 -1
- package/map/webmap-maplibre.d.ts.map +1 -1
- package/map/webmap-maplibre.js +3 -0
- package/package.json +3 -3
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +2 -0
- package/query-planner/grpc.d.ts +4 -4
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +11 -11
- package/query-planner/types.d.ts +6 -4
- package/query-planner/types.d.ts.map +1 -1
- package/realtime/honua-server.d.ts +4 -0
- package/realtime/honua-server.d.ts.map +1 -1
- package/realtime/honua-server.js +10 -0
- package/realtime/resumable.js +9 -0
- package/realtime/types.d.ts +8 -0
- package/realtime/types.d.ts.map +1 -1
- package/runtime/errors.d.ts +1 -1
- package/runtime/errors.d.ts.map +1 -1
- package/runtime/errors.js +2 -0
- package/runtime/generated/map-package-schema-meta.d.ts +11 -0
- package/runtime/generated/map-package-schema-meta.d.ts.map +1 -0
- package/runtime/generated/map-package-schema-meta.js +12 -0
- package/runtime/generated/map-package-schema-validator.d.ts +16 -0
- package/runtime/generated/map-package-schema-validator.d.ts.map +1 -0
- package/runtime/generated/map-package-schema-validator.js +1422 -0
- package/runtime/index.d.ts +5 -1
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +6 -0
- package/runtime/map-package-export.d.ts +151 -0
- package/runtime/map-package-export.d.ts.map +1 -0
- package/runtime/map-package-export.js +636 -0
- package/runtime/map-package-validation.d.ts +21 -1
- package/runtime/map-package-validation.d.ts.map +1 -1
- package/runtime/map-package-validation.js +132 -95
- package/runtime/map-package.d.ts +80 -0
- package/runtime/map-package.d.ts.map +1 -1
- package/studio/capability-manifest.d.ts +10 -0
- package/studio/capability-manifest.d.ts.map +1 -1
- package/studio/capability-manifest.js +38 -0
- package/studio/chart-spec.d.ts +6 -6
- package/studio/chart-spec.d.ts.map +1 -1
- package/studio/chart-spec.js +6 -6
- package/studio/command-adapter.d.ts +35 -0
- package/studio/command-adapter.d.ts.map +1 -0
- package/studio/command-adapter.js +36 -0
- package/studio/generated/studio-api.d.ts +1062 -0
- package/studio/generated/studio-api.d.ts.map +1 -0
- package/studio/generated/studio-api.js +4 -0
- package/studio/index.d.ts +25 -13
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -10
- package/studio/lifecycle-client.d.ts +262 -22
- package/studio/lifecycle-client.d.ts.map +1 -1
- package/studio/lifecycle-client.js +543 -24
- package/studio/lifecycle-errors.d.ts +8 -2
- package/studio/lifecycle-errors.d.ts.map +1 -1
- package/studio/lifecycle-errors.js +6 -1
- package/studio/lifecycle-types.d.ts +237 -38
- package/studio/lifecycle-types.d.ts.map +1 -1
- package/studio/lifecycle-types.js +5 -12
- package/studio/publication-status.d.ts +55 -0
- package/studio/publication-status.d.ts.map +1 -0
- package/studio/publication-status.js +103 -0
- package/studio/types.d.ts +37 -7
- package/studio/types.d.ts.map +1 -1
- package/studio/types.js +5 -3
- package/studio/validate.d.ts.map +1 -1
- package/studio/validate.js +104 -7
- package/style/renderers.d.ts +6 -1
- package/style/renderers.d.ts.map +1 -1
- package/style/renderers.js +11 -6
- package/style/visual-variables.d.ts +43 -0
- package/style/visual-variables.d.ts.map +1 -0
- package/style/visual-variables.js +183 -0
- package/webmap/convert-layer.d.ts +2 -1
- package/webmap/convert-layer.d.ts.map +1 -1
- package/webmap/convert-layer.js +20 -3
- package/webmap/convert-renderer.d.ts +10 -3
- package/webmap/convert-renderer.d.ts.map +1 -1
- package/webmap/convert-renderer.js +190 -36
- package/webmap/index.d.ts +1 -0
- package/webmap/index.d.ts.map +1 -1
- package/webmap/parse.d.ts +2 -1
- package/webmap/parse.d.ts.map +1 -1
- package/webmap/parse.js +1 -1
- package/gen/honua/v1/feature_service_pb.d.ts +0 -918
- package/gen/honua/v1/feature_service_pb.d.ts.map +0 -1
- package/gen/honua/v1/feature_service_pb.js +0 -375
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2026.1 command catalog: real commands over the existing control-plane and
|
|
3
|
+
* Studio resource clients.
|
|
4
|
+
*
|
|
5
|
+
* These four cover one end-to-end slice of the terminal release journey —
|
|
6
|
+
* probe a connection, start an import, publish a map package, and save a Studio
|
|
7
|
+
* draft as an immutable version — and exercise every capability the shared
|
|
8
|
+
* layer promises: idempotency, dry run, cancellation, validation, typed errors,
|
|
9
|
+
* and deterministic receipts. Each command owns its own sequencing, which is
|
|
10
|
+
* why `studio.draft.saveVersion` performs the optimistic-generation check here
|
|
11
|
+
* rather than in four transports.
|
|
12
|
+
*
|
|
13
|
+
* ## Where the concurrency check is bracketed, not atomic
|
|
14
|
+
*
|
|
15
|
+
* `studio.draft.saveVersion` cannot make its generation check atomic with the
|
|
16
|
+
* write, because the Studio lifecycle API offers nothing to make it atomic
|
|
17
|
+
* with: `POST /package-drafts/{draftId}/content-versions` takes no request body
|
|
18
|
+
* (`HonuaStudioDraftsClient.createContentVersion`, and the pinned contract
|
|
19
|
+
* fixture `test/fixtures/studio-lifecycle/content-version-create.v1.json`) and
|
|
20
|
+
* `HonuaStudioRequestOptions` has no `ifMatch` — unlike its control-plane
|
|
21
|
+
* sibling `HonuaControlPlaneRequestOptions`. The one optimistic-concurrency
|
|
22
|
+
* primitive in the surface is the `generation` field on the
|
|
23
|
+
* `PUT /package-drafts/{draftId}` *body* (`StudioPackageDraftReplaceRequest`),
|
|
24
|
+
* which this route has no analogue for.
|
|
25
|
+
*
|
|
26
|
+
* So the command brackets the write instead of pretending the check was
|
|
27
|
+
* atomic: it reads the generation before, re-reads it after, and raises a
|
|
28
|
+
* `conflict` naming the version it created if the draft moved at any point.
|
|
29
|
+
* `generation` is documented to increment on every successful `PUT`
|
|
30
|
+
* (`StudioPackageDraft`), so no concurrent edit can slip through the bracket
|
|
31
|
+
* unseen. When honua-server grows a real precondition on this route, the
|
|
32
|
+
* bracket collapses into it and the second read goes away.
|
|
33
|
+
*
|
|
34
|
+
* @experimental
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
import type { HonuaMapPackage } from "../../runtime/index.js";
|
|
38
|
+
import type { StudioContentVersion } from "../../studio/lifecycle-types.js";
|
|
39
|
+
import type { HonuaControlPlaneJob, HonuaPublishMapPackageResponse } from "../types.js";
|
|
40
|
+
import type { HonuaCommand } from "./types.js";
|
|
41
|
+
/** Input for {@link connectionTestCommand}. */
|
|
42
|
+
export interface ConnectionTestInput {
|
|
43
|
+
/** Existing connection to probe. */
|
|
44
|
+
readonly connectionId: string;
|
|
45
|
+
}
|
|
46
|
+
/** Server probe result. Left open: the probe payload is deployment-specific. */
|
|
47
|
+
export interface ConnectionTestOutput {
|
|
48
|
+
readonly ok?: boolean;
|
|
49
|
+
readonly status?: string;
|
|
50
|
+
readonly detail?: string;
|
|
51
|
+
readonly [extra: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* `POST /connections/{connectionId}/test` — probe a stored connection.
|
|
55
|
+
*
|
|
56
|
+
* The server does not consume an idempotency key or a workspace body. Keep the
|
|
57
|
+
* command identity limited to the connection route so receipts describe the
|
|
58
|
+
* request the server actually processed.
|
|
59
|
+
*/
|
|
60
|
+
export declare const connectionTestCommand: HonuaCommand<ConnectionTestInput, ConnectionTestOutput>;
|
|
61
|
+
/**
|
|
62
|
+
* Input for {@link importCreateCommand}.
|
|
63
|
+
*
|
|
64
|
+
* The server's own `dryRun` request field is deliberately not exposed: dry run
|
|
65
|
+
* is a command-layer concept here, and two spellings of it would let one
|
|
66
|
+
* transport preview while another executed. The current file-import endpoint
|
|
67
|
+
* accepts public source URLs only; stored-connection imports have no matching
|
|
68
|
+
* server route yet and are rejected before a request is issued.
|
|
69
|
+
*/
|
|
70
|
+
export interface ImportCreateInput {
|
|
71
|
+
readonly sourceKind: string;
|
|
72
|
+
readonly sourceUrl?: string;
|
|
73
|
+
readonly connectionId?: string;
|
|
74
|
+
readonly workspaceId?: string;
|
|
75
|
+
readonly title?: string;
|
|
76
|
+
readonly options?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
/** `POST /import/upload-url` — enqueue a URL import job. */
|
|
79
|
+
export declare const importCreateCommand: HonuaCommand<ImportCreateInput, HonuaControlPlaneJob>;
|
|
80
|
+
/**
|
|
81
|
+
* Input for {@link mapPackagePublishCommand}.
|
|
82
|
+
*
|
|
83
|
+
* There is no approval field, and the schema is closed: publication approval is
|
|
84
|
+
* a server decision, and no transport may express one. The optimistic-
|
|
85
|
+
* concurrency validator travels on `HonuaCommandInvocation.ifMatch`, not in the
|
|
86
|
+
* input, so it can never become part of the idempotency identity.
|
|
87
|
+
*/
|
|
88
|
+
export interface MapPackagePublishInput {
|
|
89
|
+
/** Hosted map the package belongs to. */
|
|
90
|
+
readonly mapId?: string;
|
|
91
|
+
readonly workspaceId?: string;
|
|
92
|
+
/** The `honua_map_package.v1` document to publish. */
|
|
93
|
+
readonly package: HonuaMapPackage;
|
|
94
|
+
/** Publication message recorded with the version. */
|
|
95
|
+
readonly message?: string;
|
|
96
|
+
}
|
|
97
|
+
/** `POST /packages` — publish a map package version. */
|
|
98
|
+
export declare const mapPackagePublishCommand: HonuaCommand<MapPackagePublishInput, HonuaPublishMapPackageResponse>;
|
|
99
|
+
/** Input for {@link studioDraftSaveVersionCommand}. */
|
|
100
|
+
export interface StudioDraftSaveVersionInput {
|
|
101
|
+
readonly draftId: string;
|
|
102
|
+
/**
|
|
103
|
+
* Last-seen draft `generation`. When supplied, the command brackets the write
|
|
104
|
+
* with a generation read on each side and fails with a `conflict` error if
|
|
105
|
+
* the draft moved — the optimistic-concurrency sequencing every transport
|
|
106
|
+
* would otherwise reimplement.
|
|
107
|
+
*
|
|
108
|
+
* The check is *detected*, not *enforced*: the route accepts no precondition,
|
|
109
|
+
* so a concurrent edit surfaces as a loud conflict naming the version that
|
|
110
|
+
* was created rather than as a rejected write. See this module's
|
|
111
|
+
* "Where the concurrency check is bracketed, not atomic".
|
|
112
|
+
*/
|
|
113
|
+
readonly generation?: number;
|
|
114
|
+
}
|
|
115
|
+
/** `POST /package-drafts/{draftId}/content-versions` — save a draft as an immutable version. */
|
|
116
|
+
export declare const studioDraftSaveVersionCommand: HonuaCommand<StudioDraftSaveVersionInput, StudioContentVersion>;
|
|
117
|
+
/** Every command id in the 2026.1 catalog, in registry order. */
|
|
118
|
+
export declare const HONUA_COMMAND_IDS: readonly ["connection.test", "import.create", "map-package.publish", "studio.draft.saveVersion"];
|
|
119
|
+
/** One of {@link HONUA_COMMAND_IDS}. */
|
|
120
|
+
export type HonuaCommandId = (typeof HONUA_COMMAND_IDS)[number];
|
|
121
|
+
/**
|
|
122
|
+
* The shared registry every transport dispatches through. MCP tool schemas,
|
|
123
|
+
* CLI help, Studio clients, and JS methods all project from these entries.
|
|
124
|
+
*/
|
|
125
|
+
export declare const HONUA_COMMANDS: {
|
|
126
|
+
readonly "connection.test": HonuaCommand<ConnectionTestInput, ConnectionTestOutput>;
|
|
127
|
+
readonly "import.create": HonuaCommand<ImportCreateInput, HonuaControlPlaneJob>;
|
|
128
|
+
readonly "map-package.publish": HonuaCommand<MapPackagePublishInput, HonuaPublishMapPackageResponse>;
|
|
129
|
+
readonly "studio.draft.saveVersion": HonuaCommand<StudioDraftSaveVersionInput, StudioContentVersion>;
|
|
130
|
+
};
|
|
131
|
+
/** Type guard narrowing an arbitrary string to a registered command id. */
|
|
132
|
+
export declare function isHonuaCommandId(value: string): value is HonuaCommandId;
|
|
133
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/commands/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EACV,oBAAoB,EAGpB,8BAA8B,EAC/B,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAmB,YAAY,EAA2B,MAAM,YAAY,CAAC;AAMzF,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,gFAAgF;AAChF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAAY,CAAC,mBAAmB,EAAE,oBAAoB,CAuCzF,CAAC;AAiBF;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,EAAE,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,CAqFrF,CAAC;AAMF;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,EAAE,YAAY,CAAC,sBAAsB,EAAE,8BAA8B,CAwDzG,CAAC;AAMF,uDAAuD;AACvD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,gGAAgG;AAChG,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,2BAA2B,EAAE,oBAAoB,CA0FzG,CAAC;AAMF,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,kGAKpB,CAAC;AAEX,wCAAwC;AACxC,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;CAKiC,CAAC;AAE7D,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2026.1 command catalog: real commands over the existing control-plane and
|
|
3
|
+
* Studio resource clients.
|
|
4
|
+
*
|
|
5
|
+
* These four cover one end-to-end slice of the terminal release journey —
|
|
6
|
+
* probe a connection, start an import, publish a map package, and save a Studio
|
|
7
|
+
* draft as an immutable version — and exercise every capability the shared
|
|
8
|
+
* layer promises: idempotency, dry run, cancellation, validation, typed errors,
|
|
9
|
+
* and deterministic receipts. Each command owns its own sequencing, which is
|
|
10
|
+
* why `studio.draft.saveVersion` performs the optimistic-generation check here
|
|
11
|
+
* rather than in four transports.
|
|
12
|
+
*
|
|
13
|
+
* ## Where the concurrency check is bracketed, not atomic
|
|
14
|
+
*
|
|
15
|
+
* `studio.draft.saveVersion` cannot make its generation check atomic with the
|
|
16
|
+
* write, because the Studio lifecycle API offers nothing to make it atomic
|
|
17
|
+
* with: `POST /package-drafts/{draftId}/content-versions` takes no request body
|
|
18
|
+
* (`HonuaStudioDraftsClient.createContentVersion`, and the pinned contract
|
|
19
|
+
* fixture `test/fixtures/studio-lifecycle/content-version-create.v1.json`) and
|
|
20
|
+
* `HonuaStudioRequestOptions` has no `ifMatch` — unlike its control-plane
|
|
21
|
+
* sibling `HonuaControlPlaneRequestOptions`. The one optimistic-concurrency
|
|
22
|
+
* primitive in the surface is the `generation` field on the
|
|
23
|
+
* `PUT /package-drafts/{draftId}` *body* (`StudioPackageDraftReplaceRequest`),
|
|
24
|
+
* which this route has no analogue for.
|
|
25
|
+
*
|
|
26
|
+
* So the command brackets the write instead of pretending the check was
|
|
27
|
+
* atomic: it reads the generation before, re-reads it after, and raises a
|
|
28
|
+
* `conflict` naming the version it created if the draft moved at any point.
|
|
29
|
+
* `generation` is documented to increment on every successful `PUT`
|
|
30
|
+
* (`StudioPackageDraft`), so no concurrent edit can slip through the bracket
|
|
31
|
+
* unseen. When honua-server grows a real precondition on this route, the
|
|
32
|
+
* bracket collapses into it and the second read goes away.
|
|
33
|
+
*
|
|
34
|
+
* @experimental
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
import { HonuaCommandError } from "./errors.js";
|
|
38
|
+
/**
|
|
39
|
+
* `POST /connections/{connectionId}/test` — probe a stored connection.
|
|
40
|
+
*
|
|
41
|
+
* The server does not consume an idempotency key or a workspace body. Keep the
|
|
42
|
+
* command identity limited to the connection route so receipts describe the
|
|
43
|
+
* request the server actually processed.
|
|
44
|
+
*/
|
|
45
|
+
export const connectionTestCommand = {
|
|
46
|
+
id: "connection.test",
|
|
47
|
+
title: "Test a connection",
|
|
48
|
+
description: "Probe a stored control-plane connection and report whether the server can reach it.",
|
|
49
|
+
mode: "read",
|
|
50
|
+
resourceKind: "connection",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
description: "Identifies the stored connection to probe.",
|
|
54
|
+
properties: {
|
|
55
|
+
connectionId: { type: "string", minLength: 1, description: "Identifier of the stored connection." },
|
|
56
|
+
},
|
|
57
|
+
required: ["connectionId"],
|
|
58
|
+
additionalProperties: false,
|
|
59
|
+
},
|
|
60
|
+
plan(context) {
|
|
61
|
+
return {
|
|
62
|
+
method: "POST",
|
|
63
|
+
path: connectionTestPath(context.input.connectionId),
|
|
64
|
+
summary: `Probe connection ${context.input.connectionId}`,
|
|
65
|
+
resourceRef: connectionRef(context.input),
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
async execute(context) {
|
|
69
|
+
const result = await context.controlPlane.raw({
|
|
70
|
+
method: "POST",
|
|
71
|
+
path: connectionTestPath(context.input.connectionId),
|
|
72
|
+
...context.requestOptions(),
|
|
73
|
+
});
|
|
74
|
+
const value = unwrap(result, this.id, {
|
|
75
|
+
correlationId: context.correlationId,
|
|
76
|
+
idempotencyKey: context.idempotencyKey,
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
output: value ?? {},
|
|
80
|
+
...(value?.ok === false ? { status: "denied" } : {}),
|
|
81
|
+
resourceRef: connectionRef(context.input),
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
function connectionTestPath(connectionId) {
|
|
86
|
+
return `/connections/${encodeURIComponent(connectionId)}/test`;
|
|
87
|
+
}
|
|
88
|
+
function connectionRef(input) {
|
|
89
|
+
return {
|
|
90
|
+
type: "connection",
|
|
91
|
+
id: input.connectionId,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** `POST /import/upload-url` — enqueue a URL import job. */
|
|
95
|
+
export const importCreateCommand = {
|
|
96
|
+
id: "import.create",
|
|
97
|
+
title: "Create an import job",
|
|
98
|
+
description: "Enqueue a control-plane import job for a source URL.",
|
|
99
|
+
mode: "action",
|
|
100
|
+
resourceKind: "import-job",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
description: "Describes the source to import.",
|
|
104
|
+
properties: {
|
|
105
|
+
sourceKind: { type: "string", minLength: 1, description: "Import source kind, e.g. `geojson` or `postgis`." },
|
|
106
|
+
sourceUrl: { type: "string", minLength: 1, description: "Source URL, when the import reads a location." },
|
|
107
|
+
connectionId: {
|
|
108
|
+
type: "string",
|
|
109
|
+
minLength: 1,
|
|
110
|
+
description: "Compatibility input; the current /import/upload-url endpoint accepts sourceUrl only.",
|
|
111
|
+
},
|
|
112
|
+
workspaceId: { type: "string", minLength: 1, description: "Workspace that will own the imported content." },
|
|
113
|
+
title: { type: "string", minLength: 1, description: "Human title for the resulting content." },
|
|
114
|
+
options: { type: "object", description: "Import-kind-specific options, passed through verbatim." },
|
|
115
|
+
},
|
|
116
|
+
required: ["sourceKind"],
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
},
|
|
119
|
+
validate(input) {
|
|
120
|
+
// This has to run before the dry-run short circuit: a preview that accepts
|
|
121
|
+
// an import with no URL would be a preview of a request the server never
|
|
122
|
+
// sees.
|
|
123
|
+
if (!input.sourceUrl && !input.connectionId) {
|
|
124
|
+
return [{ path: "sourceUrl", message: "`sourceUrl` is required by /import/upload-url" }];
|
|
125
|
+
}
|
|
126
|
+
if (!input.sourceUrl && input.connectionId) {
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
path: "connectionId",
|
|
130
|
+
message: "stored-connection imports are not supported by /import/upload-url; provide `sourceUrl`",
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
if (input.sourceUrl && input.connectionId) {
|
|
135
|
+
return [{ path: "", message: "provide only one of `sourceUrl` or `connectionId`" }];
|
|
136
|
+
}
|
|
137
|
+
return [];
|
|
138
|
+
},
|
|
139
|
+
plan(context) {
|
|
140
|
+
const { input } = context;
|
|
141
|
+
return {
|
|
142
|
+
method: "POST",
|
|
143
|
+
path: "/import/upload-url",
|
|
144
|
+
summary: `Import ${input.sourceKind} from ${input.sourceUrl ?? input.connectionId ?? "(unspecified source)"}`,
|
|
145
|
+
resourceRef: {
|
|
146
|
+
type: "import-job",
|
|
147
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
async execute(context) {
|
|
152
|
+
const { input } = context;
|
|
153
|
+
const result = await context.controlPlane.imports.create({
|
|
154
|
+
sourceKind: input.sourceKind,
|
|
155
|
+
...(input.sourceUrl ? { sourceUrl: input.sourceUrl } : {}),
|
|
156
|
+
...(input.connectionId ? { connectionId: input.connectionId } : {}),
|
|
157
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
158
|
+
...(input.title ? { title: input.title } : {}),
|
|
159
|
+
...(input.options ? { options: input.options } : {}),
|
|
160
|
+
}, context.requestOptions());
|
|
161
|
+
const job = unwrap(result, this.id, {
|
|
162
|
+
correlationId: context.correlationId,
|
|
163
|
+
idempotencyKey: context.idempotencyKey,
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
output: job,
|
|
167
|
+
resourceRef: {
|
|
168
|
+
type: "import-job",
|
|
169
|
+
...(job?.id ? { id: job.id } : {}),
|
|
170
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
171
|
+
...(job?.links?.self ? { href: job.links.self } : {}),
|
|
172
|
+
},
|
|
173
|
+
...(validatorsOf(job) ? { validators: validatorsOf(job) } : {}),
|
|
174
|
+
...(job?.problem ? { problem: job.problem } : {}),
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
/** `POST /packages` — publish a map package version. */
|
|
179
|
+
export const mapPackagePublishCommand = {
|
|
180
|
+
id: "map-package.publish",
|
|
181
|
+
title: "Publish a map package",
|
|
182
|
+
description: "Publish a map package version. Approval and visibility remain server-side decisions.",
|
|
183
|
+
mode: "action",
|
|
184
|
+
resourceKind: "map-package",
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: "object",
|
|
187
|
+
description: "The map package to publish and where it belongs.",
|
|
188
|
+
properties: {
|
|
189
|
+
mapId: { type: "string", minLength: 1, description: "Hosted map the package version belongs to." },
|
|
190
|
+
workspaceId: { type: "string", minLength: 1, description: "Owning workspace." },
|
|
191
|
+
package: { type: "object", description: "The `honua_map_package.v1` document." },
|
|
192
|
+
message: { type: "string", description: "Publication message recorded with the version." },
|
|
193
|
+
},
|
|
194
|
+
required: ["package"],
|
|
195
|
+
additionalProperties: false,
|
|
196
|
+
},
|
|
197
|
+
plan(context) {
|
|
198
|
+
const { input } = context;
|
|
199
|
+
return {
|
|
200
|
+
method: "POST",
|
|
201
|
+
path: "/packages",
|
|
202
|
+
summary: input.mapId ? `Publish a package version for map ${input.mapId}` : "Publish a map package version",
|
|
203
|
+
resourceRef: {
|
|
204
|
+
type: "map-package",
|
|
205
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
async execute(context) {
|
|
210
|
+
const { input } = context;
|
|
211
|
+
const result = await context.controlPlane.packages.publish({
|
|
212
|
+
package: input.package,
|
|
213
|
+
...(input.mapId ? { mapId: input.mapId } : {}),
|
|
214
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
215
|
+
...(input.message ? { message: input.message } : {}),
|
|
216
|
+
}, context.requestOptions());
|
|
217
|
+
const response = unwrap(result, this.id, {
|
|
218
|
+
correlationId: context.correlationId,
|
|
219
|
+
idempotencyKey: context.idempotencyKey,
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
output: response,
|
|
223
|
+
resourceRef: {
|
|
224
|
+
type: "map-package",
|
|
225
|
+
...(response?.packageId ? { id: response.packageId } : {}),
|
|
226
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
227
|
+
...(response?.links?.self ? { href: response.links.self } : {}),
|
|
228
|
+
},
|
|
229
|
+
...(validatorsOf(response) ? { validators: validatorsOf(response) } : {}),
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
/** `POST /package-drafts/{draftId}/content-versions` — save a draft as an immutable version. */
|
|
234
|
+
export const studioDraftSaveVersionCommand = {
|
|
235
|
+
id: "studio.draft.saveVersion",
|
|
236
|
+
title: "Save a Studio draft as a version",
|
|
237
|
+
description: "Freeze a mutable Studio package draft into an immutable content version, checking the generation.",
|
|
238
|
+
mode: "action",
|
|
239
|
+
resourceKind: "studio-content-version",
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: "object",
|
|
242
|
+
description: "Identifies the draft to freeze.",
|
|
243
|
+
properties: {
|
|
244
|
+
draftId: { type: "string", minLength: 1, description: "Mutable draft identifier." },
|
|
245
|
+
generation: { type: "integer", minimum: 0, description: "Last-seen draft generation for concurrency checking." },
|
|
246
|
+
},
|
|
247
|
+
required: ["draftId"],
|
|
248
|
+
additionalProperties: false,
|
|
249
|
+
},
|
|
250
|
+
plan(context) {
|
|
251
|
+
return {
|
|
252
|
+
method: "POST",
|
|
253
|
+
path: `/package-drafts/${encodeURIComponent(context.input.draftId)}/content-versions`,
|
|
254
|
+
summary: `Save draft ${context.input.draftId} as an immutable content version`,
|
|
255
|
+
resourceRef: { type: "studio-package-draft", id: context.input.draftId },
|
|
256
|
+
};
|
|
257
|
+
},
|
|
258
|
+
async execute(context) {
|
|
259
|
+
const studio = context.studio;
|
|
260
|
+
if (!studio) {
|
|
261
|
+
throw new HonuaCommandError("transport", this.id, "studio.draft.saveVersion requires a Studio lifecycle client; construct the runtime with `studio`.", { correlationId: context.correlationId, idempotencyKey: context.idempotencyKey });
|
|
262
|
+
}
|
|
263
|
+
// The Studio lifecycle client takes `{ signal, headers }` rather than the
|
|
264
|
+
// control-plane option bag, so the idempotency key is threaded as the
|
|
265
|
+
// header it becomes — and only onto the mutating call.
|
|
266
|
+
const options = context.requestOptions();
|
|
267
|
+
const readOptions = {
|
|
268
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
269
|
+
...(options.headers ? { headers: options.headers } : {}),
|
|
270
|
+
};
|
|
271
|
+
// The command-owned key goes on last: the runtime already refuses a caller
|
|
272
|
+
// header that would replace it, and this keeps the value on the wire equal
|
|
273
|
+
// to the value the receipt records even if that guard is ever relaxed.
|
|
274
|
+
const writeOptions = {
|
|
275
|
+
...readOptions,
|
|
276
|
+
headers: { ...headersToRecord(options.headers), "Idempotency-Key": context.idempotencyKey },
|
|
277
|
+
};
|
|
278
|
+
if (context.input.generation !== undefined) {
|
|
279
|
+
const draft = await studio.drafts.get(context.input.draftId, readOptions);
|
|
280
|
+
if (draft.generation !== context.input.generation) {
|
|
281
|
+
throw new HonuaCommandError("conflict", this.id, `Studio draft ${context.input.draftId} moved from generation ${context.input.generation} to ${draft.generation}; reload and retry.`, { correlationId: context.correlationId, idempotencyKey: context.idempotencyKey, statusCode: 409 });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const version = await studio.drafts.createContentVersion(context.input.draftId, writeOptions);
|
|
285
|
+
// The lifecycle API exposes no precondition on the content-version POST, so
|
|
286
|
+
// the pre-read alone leaves a window in which another editor's `PUT` lands
|
|
287
|
+
// between the check and the write. When the caller asked for concurrency
|
|
288
|
+
// protection, close the bracket: re-read and refuse to report a success we
|
|
289
|
+
// cannot vouch for. The created version is named so the caller can
|
|
290
|
+
// reconcile it rather than lose track of it.
|
|
291
|
+
if (context.input.generation !== undefined) {
|
|
292
|
+
const after = await studio.drafts.get(context.input.draftId, readOptions);
|
|
293
|
+
if (after.generation !== context.input.generation) {
|
|
294
|
+
throw new HonuaCommandError("conflict", this.id, `Studio draft ${context.input.draftId} moved from generation ${context.input.generation} to ${after.generation} while version ${version?.versionId ?? "(unknown)"} was being cut; reconcile that version, then reload and retry.`, { correlationId: context.correlationId, idempotencyKey: context.idempotencyKey, statusCode: 409 });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
output: version,
|
|
299
|
+
resourceRef: {
|
|
300
|
+
type: "studio-content-version",
|
|
301
|
+
...(version?.versionId ? { id: version.versionId } : {}),
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
// Registry
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
/** Every command id in the 2026.1 catalog, in registry order. */
|
|
310
|
+
export const HONUA_COMMAND_IDS = [
|
|
311
|
+
"connection.test",
|
|
312
|
+
"import.create",
|
|
313
|
+
"map-package.publish",
|
|
314
|
+
"studio.draft.saveVersion",
|
|
315
|
+
];
|
|
316
|
+
/**
|
|
317
|
+
* The shared registry every transport dispatches through. MCP tool schemas,
|
|
318
|
+
* CLI help, Studio clients, and JS methods all project from these entries.
|
|
319
|
+
*/
|
|
320
|
+
export const HONUA_COMMANDS = {
|
|
321
|
+
"connection.test": connectionTestCommand,
|
|
322
|
+
"import.create": importCreateCommand,
|
|
323
|
+
"map-package.publish": mapPackagePublishCommand,
|
|
324
|
+
"studio.draft.saveVersion": studioDraftSaveVersionCommand,
|
|
325
|
+
};
|
|
326
|
+
/** Type guard narrowing an arbitrary string to a registered command id. */
|
|
327
|
+
export function isHonuaCommandId(value) {
|
|
328
|
+
return Object.hasOwn(HONUA_COMMANDS, value);
|
|
329
|
+
}
|
|
330
|
+
// ---------------------------------------------------------------------------
|
|
331
|
+
// Shared helpers
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
/**
|
|
334
|
+
* Unwrap a {@link HonuaControlPlaneResult}, converting the "this deployment
|
|
335
|
+
* does not expose the capability" arm into a typed `transport` failure so every
|
|
336
|
+
* transport reports the gap the same way.
|
|
337
|
+
*/
|
|
338
|
+
function unwrap(result, commandId, trace) {
|
|
339
|
+
if (result.supported)
|
|
340
|
+
return result.value;
|
|
341
|
+
throw new HonuaCommandError("transport", commandId, result.reason, {
|
|
342
|
+
correlationId: trace.correlationId,
|
|
343
|
+
idempotencyKey: trace.idempotencyKey,
|
|
344
|
+
...(result.statusCode !== undefined ? { statusCode: result.statusCode } : {}),
|
|
345
|
+
...(result.problem ? { problem: result.problem } : {}),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
function headersToRecord(headers) {
|
|
349
|
+
if (!headers)
|
|
350
|
+
return {};
|
|
351
|
+
if (headers instanceof Headers)
|
|
352
|
+
return Object.fromEntries(headers.entries());
|
|
353
|
+
if (Array.isArray(headers))
|
|
354
|
+
return Object.fromEntries(headers);
|
|
355
|
+
return { ...headers };
|
|
356
|
+
}
|
|
357
|
+
function validatorsOf(value) {
|
|
358
|
+
if (!value)
|
|
359
|
+
return undefined;
|
|
360
|
+
const etag = value.etag;
|
|
361
|
+
const lastModified = value.lastModified;
|
|
362
|
+
if (!etag && !lastModified)
|
|
363
|
+
return undefined;
|
|
364
|
+
return { ...(etag ? { etag } : {}), ...(lastModified ? { lastModified } : {}) };
|
|
365
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed failure taxonomy for the shared control-plane command layer.
|
|
3
|
+
*
|
|
4
|
+
* Every transport surfaces the *same* five discriminants for the same
|
|
5
|
+
* underlying failure, so a negative RBAC or cross-tenant test written once
|
|
6
|
+
* behaves identically from the CLI, MCP, Studio, and direct JS.
|
|
7
|
+
*
|
|
8
|
+
* Like {@link ../../studio/lifecycle-errors.js | HonuaStudioError} and
|
|
9
|
+
* `HonuaCollaborationError`, this module intentionally does not join the
|
|
10
|
+
* central `HonuaSdkError` registry (`src/core/error-code-registry.ts`):
|
|
11
|
+
* `control-plane` is an `@experimental`, not-yet-semver-covered domain and a
|
|
12
|
+
* registry migration is scoped separately.
|
|
13
|
+
*
|
|
14
|
+
* @experimental
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import type { HonuaProblemDetails } from "../types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Failure classes a command can raise.
|
|
20
|
+
*
|
|
21
|
+
* - `validation` — input failed the command's declared JSON schema, or the
|
|
22
|
+
* server rejected the request shape (`400`/`422`).
|
|
23
|
+
* - `conflict` — optimistic concurrency lost: a stale `If-Match` validator or
|
|
24
|
+
* Studio `generation` (`409`/`412`). Reload and retry.
|
|
25
|
+
* - `authorization` — the caller is not permitted (`401`/`403`), or the caller
|
|
26
|
+
* tried to override authority locally (a reserved credential/authority
|
|
27
|
+
* header). Never retry with different local state.
|
|
28
|
+
* - `cancelled` — the caller's `AbortSignal` fired.
|
|
29
|
+
* - `transport` — everything else: network failure, unsupported capability,
|
|
30
|
+
* `5xx`, or a missing client the command needs.
|
|
31
|
+
*/
|
|
32
|
+
export type HonuaCommandErrorKind = "validation" | "conflict" | "authorization" | "cancelled" | "transport";
|
|
33
|
+
/** One schema or domain validation finding. */
|
|
34
|
+
export interface HonuaCommandValidationIssue {
|
|
35
|
+
/** Dotted path into the input, e.g. `package.sources[0].id`; `""` for the root. */
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly message: string;
|
|
38
|
+
}
|
|
39
|
+
/** Constructor options for {@link HonuaCommandError}. */
|
|
40
|
+
export interface HonuaCommandErrorOptions {
|
|
41
|
+
readonly cause?: unknown;
|
|
42
|
+
readonly correlationId?: string;
|
|
43
|
+
readonly idempotencyKey?: string;
|
|
44
|
+
readonly statusCode?: number;
|
|
45
|
+
readonly problem?: HonuaProblemDetails;
|
|
46
|
+
readonly issues?: readonly HonuaCommandValidationIssue[];
|
|
47
|
+
}
|
|
48
|
+
/** Serialization-safe projection of a {@link HonuaCommandError}. */
|
|
49
|
+
export interface SerializedHonuaCommandError {
|
|
50
|
+
readonly kind: "honua.command.error.v1";
|
|
51
|
+
readonly errorKind: HonuaCommandErrorKind;
|
|
52
|
+
readonly commandId: string;
|
|
53
|
+
readonly retryable: boolean;
|
|
54
|
+
readonly correlationId?: string;
|
|
55
|
+
readonly idempotencyKey?: string;
|
|
56
|
+
readonly statusCode?: number;
|
|
57
|
+
readonly issues?: readonly HonuaCommandValidationIssue[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The single error type every command raises. Callers branch on `.kind`
|
|
61
|
+
* rather than on HTTP status numbers or transport-specific error classes.
|
|
62
|
+
*/
|
|
63
|
+
export declare class HonuaCommandError extends Error {
|
|
64
|
+
readonly kind: HonuaCommandErrorKind;
|
|
65
|
+
readonly commandId: string;
|
|
66
|
+
readonly correlationId: string | undefined;
|
|
67
|
+
readonly idempotencyKey: string | undefined;
|
|
68
|
+
readonly statusCode: number | undefined;
|
|
69
|
+
readonly problem: HonuaProblemDetails | undefined;
|
|
70
|
+
readonly issues: readonly HonuaCommandValidationIssue[] | undefined;
|
|
71
|
+
/** `conflict` and `transport` are worth retrying; the rest are terminal. */
|
|
72
|
+
readonly retryable: boolean;
|
|
73
|
+
constructor(kind: HonuaCommandErrorKind, commandId: string, message: string, options?: HonuaCommandErrorOptions);
|
|
74
|
+
/** Safe JSON projection: no message, stack, cause, or response body. */
|
|
75
|
+
toJSON(): SerializedHonuaCommandError;
|
|
76
|
+
}
|
|
77
|
+
/** Type guard for {@link HonuaCommandError}. */
|
|
78
|
+
export declare function isHonuaCommandError(error: unknown): error is HonuaCommandError;
|
|
79
|
+
/** True when the failure is an optimistic-concurrency loss worth reloading and retrying. */
|
|
80
|
+
export declare function isHonuaCommandConflict(error: unknown): error is HonuaCommandError;
|
|
81
|
+
/** Map an HTTP status code onto the command taxonomy. */
|
|
82
|
+
export declare function classifyCommandStatus(statusCode: number): HonuaCommandErrorKind;
|
|
83
|
+
/**
|
|
84
|
+
* Normalize anything thrown beneath a command into a {@link HonuaCommandError}.
|
|
85
|
+
*
|
|
86
|
+
* Recognizes `AbortError`/`AbortSignal.reason` (→ `cancelled`), `HonuaHttpError`
|
|
87
|
+
* and any structurally equivalent error carrying `statusCode` (→ the status
|
|
88
|
+
* classification, which also covers `HonuaStudioError`'s `409`
|
|
89
|
+
* `generation-conflict`), and falls back to `transport`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function toHonuaCommandError(error: unknown, commandId: string, context: {
|
|
92
|
+
readonly correlationId: string;
|
|
93
|
+
readonly idempotencyKey: string;
|
|
94
|
+
readonly signal?: AbortSignal;
|
|
95
|
+
}): HonuaCommandError;
|
|
96
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/control-plane/commands/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,UAAU,GAAG,eAAe,GAAG,WAAW,GAAG,WAAW,CAAC;AAE5G,+CAA+C;AAC/C,MAAM,WAAW,2BAA2B;IAC1C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,yDAAyD;AACzD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC1D;AAED,oEAAoE;AACpE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC1D;AAID;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAgB,IAAI,EAAE,qBAAqB,CAAC;IAC5C,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,SAAgB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,SAAgB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,SAAgB,OAAO,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACzD,SAAgB,MAAM,EAAE,SAAS,2BAA2B,EAAE,GAAG,SAAS,CAAC;IAC3E,4EAA4E;IAC5E,SAAgB,SAAS,EAAE,OAAO,CAAC;gBAGjC,IAAI,EAAE,qBAAqB,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,wBAA6B;IAcxC,wEAAwE;IACjE,MAAM,IAAI,2BAA2B;CAY7C;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE9E;AAED,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAEjF;AAED,yDAAyD;AACzD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAK/E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC1G,iBAAiB,CAwBnB"}
|