@oatscenter/trellis 0.100.0-rc.1
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 +59 -0
- package/auth/authorization/client_context.d.ts +61 -0
- package/auth/authorization/client_context.js +266 -0
- package/auth/authorization/nats_registry.d.ts +41 -0
- package/auth/authorization/nats_registry.js +283 -0
- package/auth/authorization/provider_cache.d.ts +90 -0
- package/auth/authorization/provider_cache.js +783 -0
- package/auth/authorization/refresh.d.ts +46 -0
- package/auth/authorization/refresh.js +246 -0
- package/auth/authorization/types.d.ts +207 -0
- package/auth/authorization/types.js +60 -0
- package/auth/authorization_context.d.ts +11 -0
- package/auth/authorization_context.js +10 -0
- package/auth/browser/flow_types.d.ts +84 -0
- package/auth/browser/flow_types.js +70 -0
- package/auth/browser/portal.d.ts +21 -0
- package/auth/browser/portal.js +307 -0
- package/auth/browser/storage.d.ts +26 -0
- package/auth/browser/storage.js +224 -0
- package/auth/browser.d.ts +11 -0
- package/auth/browser.js +10 -0
- package/auth/browser_recovery.d.ts +13 -0
- package/auth/browser_recovery.js +38 -0
- package/auth/device_activation.d.ts +134 -0
- package/auth/device_activation.js +376 -0
- package/auth/http_error.d.ts +12 -0
- package/auth/http_error.js +32 -0
- package/auth/keys.d.ts +5 -0
- package/auth/keys.js +63 -0
- package/auth/mod.d.ts +16 -0
- package/auth/mod.js +16 -0
- package/auth/proof.d.ts +31 -0
- package/auth/proof.js +95 -0
- package/auth/protocol_wasm/trellis_protocol_wasm.d.ts +138 -0
- package/auth/protocol_wasm/trellis_protocol_wasm.js +605 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bg.wasm +0 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.d.ts +1 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.js +2 -0
- package/auth/protocol_wasm.d.ts +179 -0
- package/auth/protocol_wasm.js +133 -0
- package/auth/session_auth.d.ts +30 -0
- package/auth/session_auth.js +77 -0
- package/auth/session_proof.d.ts +53 -0
- package/auth/session_proof.js +43 -0
- package/auth/time.d.ts +6 -0
- package/auth/time.js +7 -0
- package/auth/trellis_id.d.ts +1 -0
- package/auth/trellis_id.js +5 -0
- package/auth/utils.d.ts +10 -0
- package/auth/utils.js +69 -0
- package/auth.d.ts +1 -0
- package/auth.js +1 -0
- package/caller.d.ts +111 -0
- package/caller.js +85 -0
- package/client.d.ts +14 -0
- package/client.js +1 -0
- package/client_connect.d.ts +143 -0
- package/client_connect.js +1097 -0
- package/codec.d.ts +13 -0
- package/codec.js +192 -0
- package/connection.d.ts +107 -0
- package/connection.js +396 -0
- package/device/activation.d.ts +42 -0
- package/device/activation.js +319 -0
- package/device.d.ts +80 -0
- package/device.js +687 -0
- package/env.d.ts +2 -0
- package/env.js +10 -0
- package/errors/AuthError.d.ts +30 -0
- package/errors/AuthError.js +34 -0
- package/errors/KVError.d.ts +30 -0
- package/errors/KVError.js +36 -0
- package/errors/OperationLifecycleError.d.ts +110 -0
- package/errors/OperationLifecycleError.js +142 -0
- package/errors/RemoteError.d.ts +61 -0
- package/errors/RemoteError.js +72 -0
- package/errors/SchemaValidationError.d.ts +48 -0
- package/errors/SchemaValidationError.js +49 -0
- package/errors/StoreError.d.ts +21 -0
- package/errors/StoreError.js +31 -0
- package/errors/TransferError.d.ts +21 -0
- package/errors/TransferError.js +31 -0
- package/errors/TransportError.d.ts +29 -0
- package/errors/TransportError.js +33 -0
- package/errors/TrellisError.d.ts +15 -0
- package/errors/TrellisError.js +15 -0
- package/errors/ValidationError.d.ts +50 -0
- package/errors/ValidationError.js +59 -0
- package/errors/index.d.ts +254 -0
- package/errors/index.js +238 -0
- package/generated.d.ts +4 -0
- package/generated.js +3 -0
- package/generated_support.d.ts +120 -0
- package/generated_support.js +359 -0
- package/globals.d.ts +9 -0
- package/globals.js +16 -0
- package/health_transport.d.ts +18 -0
- package/health_transport.js +32 -0
- package/helpers.d.ts +11 -0
- package/helpers.js +53 -0
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/internal_sdk/generated/apis/auth/mod.d.ts +805 -0
- package/internal_sdk/generated/apis/auth/mod.js +958 -0
- package/internal_sdk/generated/apis/core/mod.d.ts +79 -0
- package/internal_sdk/generated/apis/core/mod.js +93 -0
- package/internal_sdk/generated/apis/events/mod.d.ts +224 -0
- package/internal_sdk/generated/apis/events/mod.js +313 -0
- package/internal_sdk/generated/apis/health/mod.d.ts +106 -0
- package/internal_sdk/generated/apis/health/mod.js +132 -0
- package/internal_sdk/generated/apis/index.d.ts +7 -0
- package/internal_sdk/generated/apis/index.js +8 -0
- package/internal_sdk/generated/apis/jobs/mod.d.ts +176 -0
- package/internal_sdk/generated/apis/jobs/mod.js +209 -0
- package/internal_sdk/generated/apis/state/mod.d.ts +104 -0
- package/internal_sdk/generated/apis/state/mod.js +139 -0
- package/internal_sdk/generated/index.d.ts +4 -0
- package/internal_sdk/generated/index.js +5 -0
- package/internal_sdk/generated/package.json +18 -0
- package/internal_sdk/generated/participants/cli/mod.d.ts +402 -0
- package/internal_sdk/generated/participants/cli/mod.js +460 -0
- package/internal_sdk/generated/participants/cli/types.d.ts +2 -0
- package/internal_sdk/generated/participants/cli/types.js +3 -0
- package/internal_sdk/generated/participants/console/mod.d.ts +489 -0
- package/internal_sdk/generated/participants/console/mod.js +579 -0
- package/internal_sdk/generated/participants/console/types.d.ts +2 -0
- package/internal_sdk/generated/participants/console/types.js +3 -0
- package/internal_sdk/generated/participants/eventsRuntime/mod.d.ts +64 -0
- package/internal_sdk/generated/participants/eventsRuntime/mod.js +42 -0
- package/internal_sdk/generated/participants/eventsRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/eventsRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/healthRuntime/mod.d.ts +58 -0
- package/internal_sdk/generated/participants/healthRuntime/mod.js +36 -0
- package/internal_sdk/generated/participants/healthRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/healthRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/index.d.ts +8 -0
- package/internal_sdk/generated/participants/index.js +9 -0
- package/internal_sdk/generated/participants/jobsRuntime/mod.d.ts +64 -0
- package/internal_sdk/generated/participants/jobsRuntime/mod.js +42 -0
- package/internal_sdk/generated/participants/jobsRuntime/types.d.ts +2 -0
- package/internal_sdk/generated/participants/jobsRuntime/types.js +3 -0
- package/internal_sdk/generated/participants/platform/mod.d.ts +164 -0
- package/internal_sdk/generated/participants/platform/mod.js +149 -0
- package/internal_sdk/generated/participants/platform/types.d.ts +7 -0
- package/internal_sdk/generated/participants/platform/types.js +5 -0
- package/internal_sdk/generated/participants/portal/mod.d.ts +131 -0
- package/internal_sdk/generated/participants/portal/mod.js +109 -0
- package/internal_sdk/generated/participants/portal/types.d.ts +2 -0
- package/internal_sdk/generated/participants/portal/types.js +3 -0
- package/internal_sdk/generated/types/_internal/p0.d.ts +13511 -0
- package/internal_sdk/generated/types/_internal/p0.js +6105 -0
- package/internal_sdk/generated/types/index.d.ts +2951 -0
- package/internal_sdk/generated/types/index.js +1477 -0
- package/jobs.d.ts +309 -0
- package/jobs.js +389 -0
- package/kv.d.ts +85 -0
- package/kv.js +330 -0
- package/operations.d.ts +189 -0
- package/operations.js +847 -0
- package/package.json +73 -0
- package/pagination.d.ts +25 -0
- package/pagination.js +117 -0
- package/participant.d.ts +6 -0
- package/participant.js +6 -0
- package/participant_runtime/api.d.ts +131 -0
- package/participant_runtime/api.js +42 -0
- package/participant_runtime/json.d.ts +16 -0
- package/participant_runtime/json.js +193 -0
- package/participant_runtime/metadata.d.ts +34 -0
- package/participant_runtime/metadata.js +4 -0
- package/participant_runtime/participant.d.ts +200 -0
- package/participant_runtime/participant.js +330 -0
- package/participant_runtime/schemas.d.ts +347 -0
- package/participant_runtime/schemas.js +211 -0
- package/participant_runtime/surface_names.d.ts +16 -0
- package/participant_runtime/surface_names.js +34 -0
- package/portable.d.ts +30 -0
- package/portable.js +14 -0
- package/provider.d.ts +69 -0
- package/provider.js +68 -0
- package/runtime_transport.d.ts +25 -0
- package/runtime_transport.js +48 -0
- package/service/mod.d.ts +14 -0
- package/service/mod.js +13 -0
- package/service/outbox_inbox.d.ts +259 -0
- package/service/outbox_inbox.js +908 -0
- package/service/runtime/bootstrap.d.ts +56 -0
- package/service/runtime/bootstrap.js +226 -0
- package/service/runtime/core.d.ts +46 -0
- package/service/runtime/core.js +1747 -0
- package/service/runtime/health.d.ts +97 -0
- package/service/runtime/health.js +153 -0
- package/service/runtime/health_schemas.d.ts +23 -0
- package/service/runtime/health_schemas.js +20 -0
- package/service/runtime/internal_jobs/active-job.d.ts +40 -0
- package/service/runtime/internal_jobs/active-job.js +91 -0
- package/service/runtime/internal_jobs/bindings.d.ts +40 -0
- package/service/runtime/internal_jobs/bindings.js +1 -0
- package/service/runtime/internal_jobs/cancellation-registry.d.ts +13 -0
- package/service/runtime/internal_jobs/cancellation-registry.js +55 -0
- package/service/runtime/internal_jobs/heartbeat.d.ts +33 -0
- package/service/runtime/internal_jobs/heartbeat.js +65 -0
- package/service/runtime/internal_jobs/job-manager.d.ts +126 -0
- package/service/runtime/internal_jobs/job-manager.js +821 -0
- package/service/runtime/internal_jobs/key-coordinator.d.ts +280 -0
- package/service/runtime/internal_jobs/key-coordinator.js +747 -0
- package/service/runtime/internal_jobs/projection.d.ts +3 -0
- package/service/runtime/internal_jobs/projection.js +42 -0
- package/service/runtime/internal_jobs/runtime-worker.d.ts +126 -0
- package/service/runtime/internal_jobs/runtime-worker.js +454 -0
- package/service/runtime/internal_jobs/types.d.ts +246 -0
- package/service/runtime/internal_jobs/types.js +163 -0
- package/service/runtime/logger.d.ts +2 -0
- package/service/runtime/logger.js +7 -0
- package/service/runtime/runtime.d.ts +16 -0
- package/service/runtime/runtime.js +1 -0
- package/service/runtime/service.d.ts +372 -0
- package/service/runtime/service.js +1896 -0
- package/service/runtime/transfer/download.d.ts +27 -0
- package/service/runtime/transfer/download.js +1 -0
- package/service/runtime/transfer/protocol.d.ts +15 -0
- package/service/runtime/transfer/protocol.js +46 -0
- package/service/runtime/transfer/queue.d.ts +18 -0
- package/service/runtime/transfer/queue.js +136 -0
- package/service/runtime/transfer/upload.d.ts +40 -0
- package/service/runtime/transfer/upload.js +27 -0
- package/service/runtime/transfer.d.ts +62 -0
- package/service/runtime/transfer.js +763 -0
- package/session.d.ts +862 -0
- package/session.js +3407 -0
- package/store.d.ts +71 -0
- package/store.js +412 -0
- package/store_entry.d.ts +20 -0
- package/store_entry.js +75 -0
- package/tasks.d.ts +10 -0
- package/tasks.js +28 -0
- package/telemetry/carrier.d.ts +8 -0
- package/telemetry/carrier.js +20 -0
- package/telemetry/core.d.ts +7 -0
- package/telemetry/core.js +14 -0
- package/telemetry/env.d.ts +2 -0
- package/telemetry/env.js +10 -0
- package/telemetry/init.d.ts +2 -0
- package/telemetry/init.js +7 -0
- package/telemetry/metrics.d.ts +81 -0
- package/telemetry/metrics.js +267 -0
- package/telemetry/mod.d.ts +13 -0
- package/telemetry/mod.js +8 -0
- package/telemetry/nats.d.ts +6 -0
- package/telemetry/nats.js +6 -0
- package/telemetry/result.d.ts +1 -0
- package/telemetry/result.js +18 -0
- package/telemetry/runtime.d.ts +1 -0
- package/telemetry/runtime.js +141 -0
- package/telemetry/trace.d.ts +4 -0
- package/telemetry/trace.js +26 -0
- package/telemetry/trellis.d.ts +1 -0
- package/telemetry/trellis.js +1 -0
- package/telemetry.d.ts +1 -0
- package/telemetry.js +1 -0
- package/transfer.d.ts +112 -0
- package/transfer.js +525 -0
- package/transfer_protocol.d.ts +1 -0
- package/transfer_protocol.js +13 -0
package/operations.js
ADDED
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
import { AsyncResult, err, isErr, ok } from "@oatscenter/result";
|
|
2
|
+
import { ulid } from "ulid";
|
|
3
|
+
import { parseUnknownSchema } from "./codec.js";
|
|
4
|
+
import { getBuiltinRpcError, OperationAlreadyTerminalError, OperationMismatchError, OperationNotFoundError, TransferError, TransportError, UnexpectedError, } from "./errors/index.js";
|
|
5
|
+
let activeJobWaitHook;
|
|
6
|
+
/** @internal Registers the Jobs runtime hook used to track operation waits inside job handlers. */
|
|
7
|
+
export function setActiveJobWaitHook(hook) {
|
|
8
|
+
activeJobWaitHook = hook;
|
|
9
|
+
}
|
|
10
|
+
function operationRequestBody(input, invocationId) {
|
|
11
|
+
return { invocationId, input: input };
|
|
12
|
+
}
|
|
13
|
+
function encodeOperationInput(schema, value) {
|
|
14
|
+
if (value === undefined || value === null || schema === undefined ||
|
|
15
|
+
schema === null) {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
if (typeof Reflect.get(schema, "encode") === "function") {
|
|
19
|
+
return schema.encode(value);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
export function controlSubject(subject) {
|
|
24
|
+
return `${subject}.control`;
|
|
25
|
+
}
|
|
26
|
+
function isTerminalState(state) {
|
|
27
|
+
return state === "completed" || state === "failed" || state === "cancelled";
|
|
28
|
+
}
|
|
29
|
+
function createTransportError(args) {
|
|
30
|
+
return new TransportError({
|
|
31
|
+
code: args.code,
|
|
32
|
+
message: args.message,
|
|
33
|
+
hint: args.hint,
|
|
34
|
+
cause: args.cause,
|
|
35
|
+
context: {
|
|
36
|
+
...(args.context ?? {}),
|
|
37
|
+
...(args.cause instanceof Error
|
|
38
|
+
? { causeName: args.cause.name, causeMessage: args.cause.message }
|
|
39
|
+
: args.cause === undefined
|
|
40
|
+
? {}
|
|
41
|
+
: { cause: String(args.cause) }),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function snapshotToEvent(snapshot) {
|
|
46
|
+
switch (snapshot.state) {
|
|
47
|
+
case "pending":
|
|
48
|
+
return { type: "accepted", snapshot };
|
|
49
|
+
case "running":
|
|
50
|
+
return { type: "started", snapshot };
|
|
51
|
+
case "completed":
|
|
52
|
+
return {
|
|
53
|
+
type: "completed",
|
|
54
|
+
snapshot: snapshot,
|
|
55
|
+
};
|
|
56
|
+
case "failed":
|
|
57
|
+
return {
|
|
58
|
+
type: "failed",
|
|
59
|
+
snapshot: snapshot,
|
|
60
|
+
};
|
|
61
|
+
case "cancelled":
|
|
62
|
+
return {
|
|
63
|
+
type: "cancelled",
|
|
64
|
+
snapshot: snapshot,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function isTerminalEvent(event) {
|
|
69
|
+
return event.type === "completed" || event.type === "failed" ||
|
|
70
|
+
event.type === "cancelled";
|
|
71
|
+
}
|
|
72
|
+
function normalizeOperationEvent(event) {
|
|
73
|
+
try {
|
|
74
|
+
switch (event.type) {
|
|
75
|
+
case "transfer": {
|
|
76
|
+
const transfer = event.transfer ?? event.snapshot.transfer;
|
|
77
|
+
if (!transfer) {
|
|
78
|
+
throw new Error("transfer event is missing transfer progress");
|
|
79
|
+
}
|
|
80
|
+
return ok({
|
|
81
|
+
type: "transfer",
|
|
82
|
+
transfer,
|
|
83
|
+
snapshot: {
|
|
84
|
+
...event.snapshot,
|
|
85
|
+
transfer,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
case "progress": {
|
|
90
|
+
const progress = event.progress ?? event.snapshot.progress;
|
|
91
|
+
if (progress === undefined) {
|
|
92
|
+
throw new Error("progress event is missing progress payload");
|
|
93
|
+
}
|
|
94
|
+
return ok({
|
|
95
|
+
type: "progress",
|
|
96
|
+
progress,
|
|
97
|
+
snapshot: {
|
|
98
|
+
...event.snapshot,
|
|
99
|
+
progress,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
return ok(event);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (cause) {
|
|
108
|
+
return err(createTransportError({
|
|
109
|
+
code: "trellis.operation.invalid_event",
|
|
110
|
+
message: "Trellis returned an invalid operation event.",
|
|
111
|
+
hint: "Retry the operation watch. If it keeps failing, reconnect to Trellis and try again.",
|
|
112
|
+
cause,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function dispatchObservedOperationEvent(options, event) {
|
|
117
|
+
switch (event.type) {
|
|
118
|
+
case "accepted":
|
|
119
|
+
await options.onAccepted?.(event);
|
|
120
|
+
break;
|
|
121
|
+
case "started":
|
|
122
|
+
await options.onStarted?.(event);
|
|
123
|
+
break;
|
|
124
|
+
case "transfer":
|
|
125
|
+
await options.onTransfer?.(event);
|
|
126
|
+
break;
|
|
127
|
+
case "progress":
|
|
128
|
+
await options.onProgress?.(event);
|
|
129
|
+
break;
|
|
130
|
+
case "update":
|
|
131
|
+
await options.onUpdate?.(event);
|
|
132
|
+
break;
|
|
133
|
+
case "completed":
|
|
134
|
+
await options.onCompleted?.(event);
|
|
135
|
+
break;
|
|
136
|
+
case "failed":
|
|
137
|
+
await options.onFailed?.(event);
|
|
138
|
+
break;
|
|
139
|
+
case "cancelled":
|
|
140
|
+
await options.onCancelled?.(event);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
await options.onEvent?.(event);
|
|
144
|
+
}
|
|
145
|
+
function hasObserverCallbacks(options) {
|
|
146
|
+
return Boolean(options.onAccepted ||
|
|
147
|
+
options.onStarted ||
|
|
148
|
+
options.onTransfer ||
|
|
149
|
+
options.onProgress ||
|
|
150
|
+
options.onUpdate ||
|
|
151
|
+
options.onCompleted ||
|
|
152
|
+
options.onFailed ||
|
|
153
|
+
options.onCancelled ||
|
|
154
|
+
options.onEvent);
|
|
155
|
+
}
|
|
156
|
+
function decodeAcceptedEnvelope(value) {
|
|
157
|
+
try {
|
|
158
|
+
const envelope = value;
|
|
159
|
+
if (envelope?.kind !== "accepted" || !envelope.ref || !envelope.snapshot) {
|
|
160
|
+
throw new Error(`Expected accepted operation envelope, got ${JSON.stringify(value)}`);
|
|
161
|
+
}
|
|
162
|
+
return ok(envelope);
|
|
163
|
+
}
|
|
164
|
+
catch (cause) {
|
|
165
|
+
return err(createTransportError({
|
|
166
|
+
code: "trellis.operation.invalid_accept",
|
|
167
|
+
message: "Trellis returned an invalid operation start response.",
|
|
168
|
+
hint: "Retry starting the operation. If it keeps failing, reconnect to Trellis and try again.",
|
|
169
|
+
cause,
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function decodeSnapshotFrame(value) {
|
|
174
|
+
try {
|
|
175
|
+
if (isOperationControlErrorFrame(value)) {
|
|
176
|
+
return err(controlFrameToError(value));
|
|
177
|
+
}
|
|
178
|
+
const frame = value;
|
|
179
|
+
if (frame?.kind !== "snapshot" || !frame.snapshot) {
|
|
180
|
+
throw new Error("Expected snapshot operation frame");
|
|
181
|
+
}
|
|
182
|
+
return ok(frame);
|
|
183
|
+
}
|
|
184
|
+
catch (cause) {
|
|
185
|
+
return err(createTransportError({
|
|
186
|
+
code: "trellis.operation.invalid_snapshot",
|
|
187
|
+
message: "Trellis returned an invalid operation snapshot.",
|
|
188
|
+
hint: "Retry the operation request. If it keeps failing, reconnect to Trellis and try again.",
|
|
189
|
+
cause,
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function decodeSignalAckFrame(value) {
|
|
194
|
+
try {
|
|
195
|
+
if (isOperationControlErrorFrame(value)) {
|
|
196
|
+
return err(controlFrameToError(value));
|
|
197
|
+
}
|
|
198
|
+
const frame = value;
|
|
199
|
+
if (frame?.kind !== "signal-accepted" ||
|
|
200
|
+
typeof frame.operationId !== "string" ||
|
|
201
|
+
typeof frame.signal !== "string" ||
|
|
202
|
+
typeof frame.signalSequence !== "number" ||
|
|
203
|
+
typeof frame.acceptedAt !== "string" ||
|
|
204
|
+
!frame.snapshot) {
|
|
205
|
+
throw new Error(`Expected signal-accepted operation frame, received ${JSON.stringify(value)}`);
|
|
206
|
+
}
|
|
207
|
+
return ok(frame);
|
|
208
|
+
}
|
|
209
|
+
catch (cause) {
|
|
210
|
+
return err(createTransportError({
|
|
211
|
+
code: "trellis.operation.invalid_signal_ack",
|
|
212
|
+
message: "Trellis returned an invalid operation signal response.",
|
|
213
|
+
hint: "Retry the operation signal. If it keeps failing, reconnect to Trellis and try again.",
|
|
214
|
+
cause,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
class RuntimeOperationRef {
|
|
219
|
+
id;
|
|
220
|
+
service;
|
|
221
|
+
operation;
|
|
222
|
+
#transport;
|
|
223
|
+
#descriptor;
|
|
224
|
+
#acceptedTransfer;
|
|
225
|
+
constructor(transport, descriptor, ref, acceptedTransfer) {
|
|
226
|
+
this.#transport = transport;
|
|
227
|
+
this.#descriptor = descriptor;
|
|
228
|
+
this.id = ref.id;
|
|
229
|
+
this.service = ref.service;
|
|
230
|
+
this.operation = ref.operation;
|
|
231
|
+
this.#acceptedTransfer = acceptedTransfer;
|
|
232
|
+
}
|
|
233
|
+
#decodePayload(schema, value) {
|
|
234
|
+
return decodeOperationPayload(schema, value);
|
|
235
|
+
}
|
|
236
|
+
#decodeSnapshot(snapshot) {
|
|
237
|
+
return decodeOperationSnapshot(this.#descriptor, snapshot);
|
|
238
|
+
}
|
|
239
|
+
#decodeEvent(event) {
|
|
240
|
+
const descriptor = this.#descriptor;
|
|
241
|
+
const decoded = event.snapshot === undefined
|
|
242
|
+
? { ...event }
|
|
243
|
+
: { ...event, snapshot: this.#decodeSnapshot(event.snapshot) };
|
|
244
|
+
if (event.type === "progress") {
|
|
245
|
+
return {
|
|
246
|
+
...decoded,
|
|
247
|
+
progress: this.#decodePayload(descriptor.progress, event.progress),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (event.type === "update") {
|
|
251
|
+
return {
|
|
252
|
+
...decoded,
|
|
253
|
+
update: this.#decodePayload(descriptor.update, event.update),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
return decoded;
|
|
257
|
+
}
|
|
258
|
+
get() {
|
|
259
|
+
return this.#controlSnapshot("get");
|
|
260
|
+
}
|
|
261
|
+
wait() {
|
|
262
|
+
return AsyncResult.from((async () => {
|
|
263
|
+
const initialTerminal = await this.#terminalSnapshotFromGet().take();
|
|
264
|
+
if (isErr(initialTerminal)) {
|
|
265
|
+
return initialTerminal;
|
|
266
|
+
}
|
|
267
|
+
if (initialTerminal !== null) {
|
|
268
|
+
return ok(initialTerminal);
|
|
269
|
+
}
|
|
270
|
+
const eventsValue = await this.watch().take();
|
|
271
|
+
if (isErr(eventsValue)) {
|
|
272
|
+
const terminal = await this.#terminalSnapshotFromGet().take();
|
|
273
|
+
if (!isErr(terminal) && terminal !== null) {
|
|
274
|
+
return ok(terminal);
|
|
275
|
+
}
|
|
276
|
+
return eventsValue;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
for await (const event of eventsValue) {
|
|
280
|
+
if (isTerminalEvent(event)) {
|
|
281
|
+
return ok(event.snapshot);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (cause) {
|
|
286
|
+
const terminal = await this.#terminalSnapshotFromGet().take();
|
|
287
|
+
if (!isErr(terminal) && terminal !== null) {
|
|
288
|
+
return ok(terminal);
|
|
289
|
+
}
|
|
290
|
+
return err(cause instanceof TransportError || cause instanceof UnexpectedError ||
|
|
291
|
+
isOperationLifecycleError(cause)
|
|
292
|
+
? cause
|
|
293
|
+
: new UnexpectedError({ cause }));
|
|
294
|
+
}
|
|
295
|
+
const terminal = await this.#terminalSnapshotFromGet().take();
|
|
296
|
+
if (!isErr(terminal) && terminal !== null) {
|
|
297
|
+
return ok(terminal);
|
|
298
|
+
}
|
|
299
|
+
return err(createTransportError({
|
|
300
|
+
code: "trellis.operation.watch_closed",
|
|
301
|
+
message: "Trellis operation watch ended before a terminal snapshot.",
|
|
302
|
+
hint: "Retry the operation wait. If it keeps happening, reconnect to Trellis and try again.",
|
|
303
|
+
context: { operationId: this.id, operation: this.operation },
|
|
304
|
+
}));
|
|
305
|
+
})());
|
|
306
|
+
}
|
|
307
|
+
#terminalSnapshotFromGet() {
|
|
308
|
+
return AsyncResult.from((async () => {
|
|
309
|
+
const snapshotValue = await this.#controlSnapshot("get").take();
|
|
310
|
+
if (isErr(snapshotValue)) {
|
|
311
|
+
return snapshotValue;
|
|
312
|
+
}
|
|
313
|
+
if (isTerminalState(snapshotValue.state)) {
|
|
314
|
+
return ok(snapshotValue);
|
|
315
|
+
}
|
|
316
|
+
return ok(null);
|
|
317
|
+
})());
|
|
318
|
+
}
|
|
319
|
+
cancel() {
|
|
320
|
+
return this.#controlSnapshot("cancel");
|
|
321
|
+
}
|
|
322
|
+
signal(signal, input) {
|
|
323
|
+
return AsyncResult.from((async () => {
|
|
324
|
+
const body = {
|
|
325
|
+
action: "signal",
|
|
326
|
+
operationId: this.id,
|
|
327
|
+
signal,
|
|
328
|
+
};
|
|
329
|
+
if (input !== undefined) {
|
|
330
|
+
const signals = this.#descriptor
|
|
331
|
+
.signals;
|
|
332
|
+
body.input = encodeOperationInput(signals?.[signal], input);
|
|
333
|
+
}
|
|
334
|
+
const responseValue = await this.#transport.requestJson(controlSubject(this.#descriptor.subject), body).take();
|
|
335
|
+
if (isErr(responseValue)) {
|
|
336
|
+
return err(responseValue.error);
|
|
337
|
+
}
|
|
338
|
+
const ack = decodeSignalAckFrame(responseValue)
|
|
339
|
+
.take();
|
|
340
|
+
if (isErr(ack)) {
|
|
341
|
+
return ack;
|
|
342
|
+
}
|
|
343
|
+
return ok({ ...ack, snapshot: this.#decodeSnapshot(ack.snapshot) });
|
|
344
|
+
})());
|
|
345
|
+
}
|
|
346
|
+
startTransfer(body) {
|
|
347
|
+
const grant = this.#acceptedTransfer;
|
|
348
|
+
if (!grant) {
|
|
349
|
+
return AsyncResult.err(new TransferError({
|
|
350
|
+
operation: "transfer",
|
|
351
|
+
context: { reason: "missing_transfer" },
|
|
352
|
+
}));
|
|
353
|
+
}
|
|
354
|
+
return this.#transport.putTransfer(grant, body);
|
|
355
|
+
}
|
|
356
|
+
watch(options = {}) {
|
|
357
|
+
return AsyncResult.from((async () => {
|
|
358
|
+
const rawIterable = await this.#transport.watchJson(controlSubject(this.#descriptor.subject), {
|
|
359
|
+
action: "watch",
|
|
360
|
+
operationId: this.id,
|
|
361
|
+
...(options.updates ? { includeUpdates: true } : {}),
|
|
362
|
+
}).take();
|
|
363
|
+
if (isErr(rawIterable)) {
|
|
364
|
+
return err(rawIterable.error);
|
|
365
|
+
}
|
|
366
|
+
const iterable = rawIterable;
|
|
367
|
+
const decodeEvent = this.#decodeEvent.bind(this);
|
|
368
|
+
async function* events() {
|
|
369
|
+
for await (const frame of iterable) {
|
|
370
|
+
const frameValue = frame.take();
|
|
371
|
+
if (isErr(frameValue)) {
|
|
372
|
+
throw frameValue.error;
|
|
373
|
+
}
|
|
374
|
+
const decoded = decodeWatchFrame(frameValue);
|
|
375
|
+
const decodedValue = decoded.take();
|
|
376
|
+
if (isErr(decodedValue)) {
|
|
377
|
+
throw decodedValue.error;
|
|
378
|
+
}
|
|
379
|
+
if (decodedValue === null) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const normalized = normalizeOperationEvent(decodedValue).take();
|
|
383
|
+
if (isErr(normalized)) {
|
|
384
|
+
throw normalized.error;
|
|
385
|
+
}
|
|
386
|
+
const event = decodeEvent(normalized);
|
|
387
|
+
yield event;
|
|
388
|
+
if (isTerminalEvent(event)) {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return ok(events());
|
|
394
|
+
})());
|
|
395
|
+
}
|
|
396
|
+
#controlSnapshot(action) {
|
|
397
|
+
return AsyncResult.from((async () => {
|
|
398
|
+
const responseValue = await this.#transport.requestJson(controlSubject(this.#descriptor.subject), {
|
|
399
|
+
action,
|
|
400
|
+
operationId: this.id,
|
|
401
|
+
}).take();
|
|
402
|
+
if (isErr(responseValue)) {
|
|
403
|
+
return err(responseValue.error);
|
|
404
|
+
}
|
|
405
|
+
const frame = decodeSnapshotFrame(responseValue).take();
|
|
406
|
+
if (isErr(frame)) {
|
|
407
|
+
return frame;
|
|
408
|
+
}
|
|
409
|
+
return ok(this.#decodeSnapshot(frame.snapshot));
|
|
410
|
+
})());
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function decodeWatchFrame(value) {
|
|
414
|
+
try {
|
|
415
|
+
if (value && typeof value === "object" &&
|
|
416
|
+
value.kind === "keepalive") {
|
|
417
|
+
return ok(null);
|
|
418
|
+
}
|
|
419
|
+
if (isOperationControlErrorFrame(value)) {
|
|
420
|
+
return err(controlFrameToError(value));
|
|
421
|
+
}
|
|
422
|
+
const frame = value;
|
|
423
|
+
if (frame.kind === "snapshot" && "snapshot" in frame) {
|
|
424
|
+
return ok(snapshotToEvent(frame.snapshot));
|
|
425
|
+
}
|
|
426
|
+
if (frame.kind === "event" && "event" in frame) {
|
|
427
|
+
return ok(frame.event);
|
|
428
|
+
}
|
|
429
|
+
throw new Error("Expected snapshot, event, or keepalive frame");
|
|
430
|
+
}
|
|
431
|
+
catch (cause) {
|
|
432
|
+
return err(createTransportError({
|
|
433
|
+
code: "trellis.operation.invalid_frame",
|
|
434
|
+
message: "Trellis returned an invalid operation watch frame.",
|
|
435
|
+
hint: "Retry the operation watch. If it keeps failing, reconnect to Trellis and try again.",
|
|
436
|
+
cause,
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function invokeOperation(transport, descriptor, input, invocationId) {
|
|
441
|
+
return AsyncResult.from((async () => {
|
|
442
|
+
const responseValue = await transport.requestJson(descriptor.subject, operationRequestBody(encodeOperationInput(descriptor.input, input), invocationId)).take();
|
|
443
|
+
if (isErr(responseValue)) {
|
|
444
|
+
return responseValue;
|
|
445
|
+
}
|
|
446
|
+
const envelope = decodeAcceptedEnvelope(responseValue)
|
|
447
|
+
.take();
|
|
448
|
+
if (isErr(envelope)) {
|
|
449
|
+
return envelope;
|
|
450
|
+
}
|
|
451
|
+
return ok({
|
|
452
|
+
accepted: {
|
|
453
|
+
type: "accepted",
|
|
454
|
+
snapshot: decodeOperationSnapshot(descriptor, envelope.snapshot),
|
|
455
|
+
},
|
|
456
|
+
operation: new RuntimeOperationRef(transport, descriptor, envelope.ref, envelope.transfer),
|
|
457
|
+
});
|
|
458
|
+
})());
|
|
459
|
+
}
|
|
460
|
+
function beginObservedWatch(operation, callbacks, options = {}) {
|
|
461
|
+
if (!hasObserverCallbacks(callbacks)) {
|
|
462
|
+
return AsyncResult.ok({});
|
|
463
|
+
}
|
|
464
|
+
return AsyncResult.from((async () => {
|
|
465
|
+
const watchValue = await operation.watch({
|
|
466
|
+
updates: callbacks.onUpdate !== undefined,
|
|
467
|
+
}).take();
|
|
468
|
+
if (isErr(watchValue)) {
|
|
469
|
+
return watchValue;
|
|
470
|
+
}
|
|
471
|
+
const iterator = watchValue[Symbol.asyncIterator]();
|
|
472
|
+
const close = async () => {
|
|
473
|
+
await iterator.return?.();
|
|
474
|
+
};
|
|
475
|
+
const task = (async () => {
|
|
476
|
+
try {
|
|
477
|
+
await options.ready;
|
|
478
|
+
while (true) {
|
|
479
|
+
const next = await iterator.next();
|
|
480
|
+
if (next.done) {
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
const event = next.value;
|
|
484
|
+
if (options.skipEvent?.(event)) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
await dispatchObservedOperationEvent(callbacks, event);
|
|
489
|
+
}
|
|
490
|
+
catch (cause) {
|
|
491
|
+
return err(toObservedCallbackError(cause));
|
|
492
|
+
}
|
|
493
|
+
if (isTerminalEvent(event)) {
|
|
494
|
+
await close();
|
|
495
|
+
return ok(event.snapshot);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return err(createTransportError({
|
|
499
|
+
code: "trellis.operation.watch_incomplete",
|
|
500
|
+
message: "Trellis ended the operation watch before completion.",
|
|
501
|
+
hint: "Retry watching the operation. If it keeps happening, reconnect to Trellis and try again.",
|
|
502
|
+
cause: new Error("operation watch ended before terminal event"),
|
|
503
|
+
}));
|
|
504
|
+
}
|
|
505
|
+
catch (cause) {
|
|
506
|
+
return err(cause instanceof TransportError || cause instanceof UnexpectedError ||
|
|
507
|
+
isOperationLifecycleError(cause)
|
|
508
|
+
? cause
|
|
509
|
+
: new UnexpectedError({ cause }));
|
|
510
|
+
}
|
|
511
|
+
})();
|
|
512
|
+
return ok({ task, close });
|
|
513
|
+
})());
|
|
514
|
+
}
|
|
515
|
+
function startObservedOperation(transport, descriptor, input, callbacks, options) {
|
|
516
|
+
return AsyncResult.from((async () => {
|
|
517
|
+
const startedValue = await invokeOperation(transport, descriptor, input, options?.invocationId ?? ulid()).take();
|
|
518
|
+
if (isErr(startedValue)) {
|
|
519
|
+
return startedValue;
|
|
520
|
+
}
|
|
521
|
+
const ready = deferred();
|
|
522
|
+
const observedValue = await beginObservedWatch(startedValue.operation, callbacks, {
|
|
523
|
+
ready: ready.promise,
|
|
524
|
+
skipEvent: createAcceptedReplayFilter(startedValue.accepted),
|
|
525
|
+
}).take();
|
|
526
|
+
const observation = isErr(observedValue) ? {} : observedValue;
|
|
527
|
+
const accepted = await dispatchOperationEventResult(callbacks, startedValue.accepted);
|
|
528
|
+
if (accepted.isErr()) {
|
|
529
|
+
if (!isErr(observedValue)) {
|
|
530
|
+
ready.resolve();
|
|
531
|
+
await observation.close?.();
|
|
532
|
+
}
|
|
533
|
+
return ok(createPublicOperationRef(startedValue.operation, failedObservation(accepted.error)));
|
|
534
|
+
}
|
|
535
|
+
if (!isErr(observedValue)) {
|
|
536
|
+
ready.resolve();
|
|
537
|
+
}
|
|
538
|
+
return ok(createPublicOperationRef(startedValue.operation, observation));
|
|
539
|
+
})());
|
|
540
|
+
}
|
|
541
|
+
function startObservedTransfer(transport, descriptor, input, body, callbacks, options) {
|
|
542
|
+
return AsyncResult.from((async () => {
|
|
543
|
+
const startedValue = await invokeOperation(transport, descriptor, input, options?.invocationId ?? ulid()).take();
|
|
544
|
+
if (isErr(startedValue)) {
|
|
545
|
+
return startedValue;
|
|
546
|
+
}
|
|
547
|
+
const operation = startedValue.operation;
|
|
548
|
+
const ready = deferred();
|
|
549
|
+
const observedValue = await beginObservedWatch(operation, callbacks, {
|
|
550
|
+
ready: ready.promise,
|
|
551
|
+
skipEvent: createAcceptedReplayFilter(startedValue.accepted),
|
|
552
|
+
}).take();
|
|
553
|
+
const observation = isErr(observedValue) ? {} : observedValue;
|
|
554
|
+
const accepted = await dispatchOperationEventResult(callbacks, startedValue.accepted);
|
|
555
|
+
if (accepted.isErr()) {
|
|
556
|
+
if (!isErr(observedValue)) {
|
|
557
|
+
ready.resolve();
|
|
558
|
+
await observation.close?.();
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (!isErr(observedValue)) {
|
|
562
|
+
ready.resolve();
|
|
563
|
+
}
|
|
564
|
+
const transferredValue = await operation.startTransfer(body).take();
|
|
565
|
+
if (isErr(transferredValue)) {
|
|
566
|
+
await observation.close?.();
|
|
567
|
+
return transferredValue;
|
|
568
|
+
}
|
|
569
|
+
const publicOperation = createPublicOperationRef(operation, accepted.isErr() ? failedObservation(accepted.error) : observation);
|
|
570
|
+
return ok({
|
|
571
|
+
operation: publicOperation,
|
|
572
|
+
wait: () => AsyncResult.from((async () => {
|
|
573
|
+
const terminalValue = await publicOperation.wait().take();
|
|
574
|
+
if (isErr(terminalValue)) {
|
|
575
|
+
return terminalValue;
|
|
576
|
+
}
|
|
577
|
+
return ok({
|
|
578
|
+
transferred: transferredValue,
|
|
579
|
+
terminal: terminalValue,
|
|
580
|
+
});
|
|
581
|
+
})()),
|
|
582
|
+
});
|
|
583
|
+
})());
|
|
584
|
+
}
|
|
585
|
+
function createObservedOperationRef(operation, observation) {
|
|
586
|
+
return createPublicOperationRef(operation, observation);
|
|
587
|
+
}
|
|
588
|
+
function createPublicOperationRef(operation, observation) {
|
|
589
|
+
const base = {
|
|
590
|
+
id: operation.id,
|
|
591
|
+
service: operation.service,
|
|
592
|
+
operation: operation.operation,
|
|
593
|
+
get: () => operation.get(),
|
|
594
|
+
wait: () => AsyncResult.from((async () => {
|
|
595
|
+
const waited = activeJobWaitHook?.({
|
|
596
|
+
kind: "operation",
|
|
597
|
+
id: operation.id,
|
|
598
|
+
operationId: operation.id,
|
|
599
|
+
service: operation.service,
|
|
600
|
+
type: operation.operation,
|
|
601
|
+
}, async () => {
|
|
602
|
+
if (observation.task) {
|
|
603
|
+
const terminal = await observation.task;
|
|
604
|
+
const terminalValue = terminal.take();
|
|
605
|
+
if (!isErr(terminalValue)) {
|
|
606
|
+
return ok(terminalValue);
|
|
607
|
+
}
|
|
608
|
+
if (isObservedCallbackError(terminalValue.error)) {
|
|
609
|
+
return terminalValue;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return await operation.wait();
|
|
613
|
+
});
|
|
614
|
+
if (waited)
|
|
615
|
+
return await waited;
|
|
616
|
+
if (observation.task) {
|
|
617
|
+
const terminal = await observation.task;
|
|
618
|
+
const terminalValue = terminal.take();
|
|
619
|
+
if (!isErr(terminalValue)) {
|
|
620
|
+
return ok(terminalValue);
|
|
621
|
+
}
|
|
622
|
+
if (isObservedCallbackError(terminalValue.error)) {
|
|
623
|
+
return terminalValue;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return await operation.wait();
|
|
627
|
+
})()),
|
|
628
|
+
watch: (options) => operation.watch(options),
|
|
629
|
+
cancel: () => operation.cancel(),
|
|
630
|
+
signal: (signal, input) => operation.signal(signal, input),
|
|
631
|
+
};
|
|
632
|
+
return base;
|
|
633
|
+
}
|
|
634
|
+
function createOperationInputBuilder(transport, descriptor, input, callbacks = {}) {
|
|
635
|
+
const rebuild = (nextCallbacks) => createOperationInputBuilder(transport, descriptor, input, nextCallbacks);
|
|
636
|
+
const baseBuilder = {
|
|
637
|
+
onAccepted(handler) {
|
|
638
|
+
return rebuild({ ...callbacks, onAccepted: handler });
|
|
639
|
+
},
|
|
640
|
+
onStarted(handler) {
|
|
641
|
+
return rebuild({ ...callbacks, onStarted: handler });
|
|
642
|
+
},
|
|
643
|
+
onProgress(handler) {
|
|
644
|
+
return rebuild({ ...callbacks, onProgress: handler });
|
|
645
|
+
},
|
|
646
|
+
onUpdate(handler) {
|
|
647
|
+
return rebuild({ ...callbacks, onUpdate: handler });
|
|
648
|
+
},
|
|
649
|
+
onCompleted(handler) {
|
|
650
|
+
return rebuild({ ...callbacks, onCompleted: handler });
|
|
651
|
+
},
|
|
652
|
+
onFailed(handler) {
|
|
653
|
+
return rebuild({ ...callbacks, onFailed: handler });
|
|
654
|
+
},
|
|
655
|
+
onCancelled(handler) {
|
|
656
|
+
return rebuild({ ...callbacks, onCancelled: handler });
|
|
657
|
+
},
|
|
658
|
+
onEvent(handler) {
|
|
659
|
+
return rebuild({ ...callbacks, onEvent: handler });
|
|
660
|
+
},
|
|
661
|
+
start(startCallbacks, options) {
|
|
662
|
+
return startObservedOperation(transport, descriptor, input, { ...callbacks, ...startCallbacks }, options);
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
if (descriptor.transfer) {
|
|
666
|
+
return {
|
|
667
|
+
...baseBuilder,
|
|
668
|
+
transfer(body) {
|
|
669
|
+
return createTransferOperationBuilder(transport, descriptor, input, body, callbacks);
|
|
670
|
+
},
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return baseBuilder;
|
|
674
|
+
}
|
|
675
|
+
function createTransferOperationBuilder(transport, descriptor, input, body, callbacks = {}) {
|
|
676
|
+
const rebuild = (nextCallbacks) => createTransferOperationBuilder(transport, descriptor, input, body, nextCallbacks);
|
|
677
|
+
return {
|
|
678
|
+
onAccepted(handler) {
|
|
679
|
+
return rebuild({ ...callbacks, onAccepted: handler });
|
|
680
|
+
},
|
|
681
|
+
onStarted(handler) {
|
|
682
|
+
return rebuild({ ...callbacks, onStarted: handler });
|
|
683
|
+
},
|
|
684
|
+
onTransfer(handler) {
|
|
685
|
+
return rebuild({ ...callbacks, onTransfer: handler });
|
|
686
|
+
},
|
|
687
|
+
onProgress(handler) {
|
|
688
|
+
return rebuild({ ...callbacks, onProgress: handler });
|
|
689
|
+
},
|
|
690
|
+
onUpdate(handler) {
|
|
691
|
+
return rebuild({ ...callbacks, onUpdate: handler });
|
|
692
|
+
},
|
|
693
|
+
onCompleted(handler) {
|
|
694
|
+
return rebuild({ ...callbacks, onCompleted: handler });
|
|
695
|
+
},
|
|
696
|
+
onFailed(handler) {
|
|
697
|
+
return rebuild({ ...callbacks, onFailed: handler });
|
|
698
|
+
},
|
|
699
|
+
onCancelled(handler) {
|
|
700
|
+
return rebuild({ ...callbacks, onCancelled: handler });
|
|
701
|
+
},
|
|
702
|
+
onEvent(handler) {
|
|
703
|
+
return rebuild({ ...callbacks, onEvent: handler });
|
|
704
|
+
},
|
|
705
|
+
start(startCallbacks, options) {
|
|
706
|
+
return startObservedTransfer(transport, descriptor, input, body, { ...callbacks, ...startCallbacks }, options);
|
|
707
|
+
},
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
export class OperationInvoker {
|
|
711
|
+
#transport;
|
|
712
|
+
#descriptor;
|
|
713
|
+
constructor(transport, descriptor) {
|
|
714
|
+
this.#transport = transport;
|
|
715
|
+
this.#descriptor = descriptor;
|
|
716
|
+
}
|
|
717
|
+
resume(ref) {
|
|
718
|
+
return createPublicOperationRef(new RuntimeOperationRef(this.#transport, this.#descriptor, ref), {});
|
|
719
|
+
}
|
|
720
|
+
start(input, callbacks) {
|
|
721
|
+
return createOperationInputBuilder(this.#transport, this.#descriptor, input).start(callbacks);
|
|
722
|
+
}
|
|
723
|
+
input(input) {
|
|
724
|
+
return createOperationInputBuilder(this.#transport, this.#descriptor, input);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
function decodeOperationPayload(schema, value) {
|
|
728
|
+
if (value === undefined || value === null || schema === undefined ||
|
|
729
|
+
schema === null) {
|
|
730
|
+
return value;
|
|
731
|
+
}
|
|
732
|
+
if (typeof Reflect.get(schema, "decode") === "function") {
|
|
733
|
+
return schema.decode(value);
|
|
734
|
+
}
|
|
735
|
+
return value;
|
|
736
|
+
}
|
|
737
|
+
function decodeOperationSnapshot(descriptor, snapshot) {
|
|
738
|
+
if (!snapshot || typeof snapshot !== "object") {
|
|
739
|
+
return snapshot;
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
...snapshot,
|
|
743
|
+
...(snapshot.progress === undefined ? {} : {
|
|
744
|
+
progress: decodeOperationPayload(descriptor.progress, snapshot.progress),
|
|
745
|
+
}),
|
|
746
|
+
...(snapshot.output === undefined ? {} : {
|
|
747
|
+
output: decodeOperationPayload(descriptor.output, snapshot.output),
|
|
748
|
+
}),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
function isOperationControlErrorFrame(value) {
|
|
752
|
+
return !!value && typeof value === "object" &&
|
|
753
|
+
value.kind === "error" &&
|
|
754
|
+
typeof Reflect.get(value, "error") === "object";
|
|
755
|
+
}
|
|
756
|
+
function controlFrameToError(frame) {
|
|
757
|
+
const lifecycleError = controlFrameToLifecycleError(frame);
|
|
758
|
+
if (lifecycleError) {
|
|
759
|
+
return lifecycleError;
|
|
760
|
+
}
|
|
761
|
+
return createTransportError({
|
|
762
|
+
code: "trellis.operation.control_error",
|
|
763
|
+
message: "Trellis rejected the operation control request.",
|
|
764
|
+
hint: "Check the operation state, then retry the action if it still applies.",
|
|
765
|
+
context: {
|
|
766
|
+
controlErrorType: frame.error.type,
|
|
767
|
+
controlErrorMessage: frame.error.message,
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
function controlFrameToLifecycleError(frame) {
|
|
772
|
+
if (!isFullOperationLifecycleErrorData(frame.error)) {
|
|
773
|
+
return undefined;
|
|
774
|
+
}
|
|
775
|
+
const descriptor = getBuiltinRpcError(frame.error.type);
|
|
776
|
+
if (!descriptor?.schema) {
|
|
777
|
+
return undefined;
|
|
778
|
+
}
|
|
779
|
+
const parsed = parseUnknownSchema(descriptor.schema, frame.error).take();
|
|
780
|
+
if (isErr(parsed)) {
|
|
781
|
+
return undefined;
|
|
782
|
+
}
|
|
783
|
+
const error = descriptor.fromSerializable(parsed);
|
|
784
|
+
return isOperationLifecycleError(error) ? error : undefined;
|
|
785
|
+
}
|
|
786
|
+
function isOperationLifecycleError(error) {
|
|
787
|
+
return error instanceof OperationNotFoundError ||
|
|
788
|
+
error instanceof OperationAlreadyTerminalError ||
|
|
789
|
+
error instanceof OperationMismatchError;
|
|
790
|
+
}
|
|
791
|
+
function isFullOperationLifecycleErrorData(error) {
|
|
792
|
+
if (typeof Reflect.get(error, "id") !== "string") {
|
|
793
|
+
return false;
|
|
794
|
+
}
|
|
795
|
+
switch (error.type) {
|
|
796
|
+
case "OperationNotFoundError":
|
|
797
|
+
case "OperationAlreadyTerminalError":
|
|
798
|
+
return typeof Reflect.get(error, "operationId") === "string";
|
|
799
|
+
case "OperationMismatchError":
|
|
800
|
+
return typeof Reflect.get(error, "operationId") === "string" &&
|
|
801
|
+
typeof Reflect.get(error, "expectedService") === "string" &&
|
|
802
|
+
typeof Reflect.get(error, "expectedOperation") === "string";
|
|
803
|
+
default:
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function deferred() {
|
|
808
|
+
let resolve;
|
|
809
|
+
const promise = new Promise((r) => {
|
|
810
|
+
resolve = r;
|
|
811
|
+
});
|
|
812
|
+
return { promise, resolve };
|
|
813
|
+
}
|
|
814
|
+
function createAcceptedReplayFilter(accepted) {
|
|
815
|
+
return (event) => {
|
|
816
|
+
return event.type === "accepted" &&
|
|
817
|
+
event.snapshot.id === accepted.snapshot.id &&
|
|
818
|
+
event.snapshot.service === accepted.snapshot.service &&
|
|
819
|
+
event.snapshot.operation === accepted.snapshot.operation &&
|
|
820
|
+
event.snapshot.revision === accepted.snapshot.revision &&
|
|
821
|
+
event.snapshot.state === accepted.snapshot.state;
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
function failedObservation(error) {
|
|
825
|
+
return {
|
|
826
|
+
task: Promise.resolve(err(error)),
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
async function dispatchOperationEventResult(callbacks, event) {
|
|
830
|
+
try {
|
|
831
|
+
await dispatchObservedOperationEvent(callbacks, event);
|
|
832
|
+
return ok(undefined);
|
|
833
|
+
}
|
|
834
|
+
catch (cause) {
|
|
835
|
+
return err(toObservedCallbackError(cause));
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
function toObservedCallbackError(cause) {
|
|
839
|
+
return (cause instanceof UnexpectedError
|
|
840
|
+
? cause
|
|
841
|
+
: new UnexpectedError({ cause }))
|
|
842
|
+
.withContext({ operationObserverCallback: true });
|
|
843
|
+
}
|
|
844
|
+
function isObservedCallbackError(error) {
|
|
845
|
+
return error instanceof UnexpectedError &&
|
|
846
|
+
error.getContext().operationObserverCallback === true;
|
|
847
|
+
}
|