@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/kv.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type KV } from "@nats-io/kv";
|
|
2
|
+
import type { NatsConnection } from "@nats-io/nats-core/internal";
|
|
3
|
+
import { AsyncResult, type BaseError, Result } from "@oatscenter/result";
|
|
4
|
+
import type { Codec } from "./generated.ts";
|
|
5
|
+
import { KVError, ValidationError } from "./errors/index.ts";
|
|
6
|
+
declare const resourceRevisionBrand: unique symbol;
|
|
7
|
+
/** Opaque storage revision returned by State and KV resources. */
|
|
8
|
+
export type ResourceRevision = number & {
|
|
9
|
+
readonly [resourceRevisionBrand]: "ResourceRevision";
|
|
10
|
+
};
|
|
11
|
+
/** A direct historical-to-current representation migration. */
|
|
12
|
+
export type KvMigration<TCurrent, THistoric = unknown> = (value: THistoric) => TCurrent | Result<TCurrent, BaseError> | Promise<TCurrent | Result<TCurrent, BaseError>>;
|
|
13
|
+
/** Runtime representation metadata emitted by a generated participant. */
|
|
14
|
+
export type KvRepresentation<T> = Readonly<{
|
|
15
|
+
codec: Codec<T>;
|
|
16
|
+
version: number;
|
|
17
|
+
migrations: Readonly<Record<number, Codec<unknown>>>;
|
|
18
|
+
}>;
|
|
19
|
+
/** Caller-supplied direct migrations keyed by historical representation version. */
|
|
20
|
+
export type ResourceMigrations<T> = Readonly<Record<number, KvMigration<T>>>;
|
|
21
|
+
/** The operation represented by one retained KV revision. */
|
|
22
|
+
export type KvOperation = "put" | "delete";
|
|
23
|
+
/** Immutable value and storage metadata for one KV revision. */
|
|
24
|
+
export type TypedKvEntry<T> = Readonly<{
|
|
25
|
+
key: string;
|
|
26
|
+
value?: T;
|
|
27
|
+
revision: ResourceRevision;
|
|
28
|
+
timestamp: Date;
|
|
29
|
+
operation: KvOperation;
|
|
30
|
+
}>;
|
|
31
|
+
/** A fallible entry yielded by a KV watcher. */
|
|
32
|
+
export type KvWatchItem<T> = Result<TypedKvEntry<T>, KVError | ValidationError>;
|
|
33
|
+
/** Options used to open a typed KV resource. */
|
|
34
|
+
export type KvOpenOptions<T = unknown> = Readonly<{
|
|
35
|
+
history?: number;
|
|
36
|
+
ttl?: number;
|
|
37
|
+
bindOnly?: boolean;
|
|
38
|
+
maxValueBytes?: number;
|
|
39
|
+
replicas?: number;
|
|
40
|
+
migrations?: ResourceMigrations<T>;
|
|
41
|
+
isCurrent?: () => boolean;
|
|
42
|
+
}>;
|
|
43
|
+
type ExistingBucketStatus = Pick<Awaited<ReturnType<KV["status"]>>, "bucket" | "history" | "ttl" | "maxValueSize" | "max_bytes">;
|
|
44
|
+
/** Verifies that an existing physical bucket satisfies the requested limits. */
|
|
45
|
+
export declare function ensureExistingBucketOptions(kv: {
|
|
46
|
+
status(): Promise<ExistingBucketStatus>;
|
|
47
|
+
}, name: string, options: KvOpenOptions): Promise<void>;
|
|
48
|
+
/** Encode a current value in the strict TRKV envelope. */
|
|
49
|
+
export declare function encodeResourceValue<T>(representation: KvRepresentation<T>, value: T): Uint8Array<ArrayBuffer>;
|
|
50
|
+
/** Decode and optionally migrate one envelope without writing it back. */
|
|
51
|
+
export declare function decodeResourceValue<T>(representation: KvRepresentation<T>, migrations: ResourceMigrations<T>, bytes: Uint8Array): Promise<T>;
|
|
52
|
+
/** Typed access to a generated, versioned KV resource. */
|
|
53
|
+
export declare class TypedKV<T> {
|
|
54
|
+
#private;
|
|
55
|
+
readonly representation: KvRepresentation<T>;
|
|
56
|
+
readonly kv: KV;
|
|
57
|
+
readonly migrations: ResourceMigrations<T>;
|
|
58
|
+
readonly isCurrent: () => boolean;
|
|
59
|
+
private constructor();
|
|
60
|
+
/** Opens or creates a typed KV bucket. */
|
|
61
|
+
static open<T>(nats: NatsConnection, name: string, representation: KvRepresentation<T>, options?: KvOpenOptions<T>): AsyncResult<TypedKV<T>, KVError>;
|
|
62
|
+
/** Returns the current value, or `undefined` when absent or deleted. */
|
|
63
|
+
get(key: string): AsyncResult<T | undefined, KVError | ValidationError>;
|
|
64
|
+
/** Returns the latest value or tombstone with authoritative revision metadata. */
|
|
65
|
+
getEntry(key: string): AsyncResult<TypedKvEntry<T> | undefined, KVError | ValidationError>;
|
|
66
|
+
/** Creates a value only when the key has no current value. */
|
|
67
|
+
create(key: string, value: T): AsyncResult<TypedKvEntry<T>, KVError>;
|
|
68
|
+
/** Writes a value without a revision precondition. */
|
|
69
|
+
put(key: string, value: T): AsyncResult<TypedKvEntry<T>, KVError>;
|
|
70
|
+
/** Replaces a value only when its current revision matches. */
|
|
71
|
+
replace(key: string, revision: ResourceRevision, value: T): AsyncResult<TypedKvEntry<T>, KVError>;
|
|
72
|
+
/** Deletes a key, optionally requiring its current revision. */
|
|
73
|
+
delete(key: string, revision?: ResourceRevision): AsyncResult<void, KVError>;
|
|
74
|
+
/** Returns all retained revisions for a key, including tombstones. */
|
|
75
|
+
history(key: string): AsyncResult<readonly TypedKvEntry<T>[], KVError | ValidationError>;
|
|
76
|
+
/** Watches retained initialization and subsequent revisions for one key. */
|
|
77
|
+
watch(key: string): AsyncResult<AsyncIterable<KvWatchItem<T>>, KVError>;
|
|
78
|
+
/** Lists live keys using the backend's bounded iterator. */
|
|
79
|
+
keys(filter?: string | string[]): AsyncResult<AsyncIterable<string>, KVError>;
|
|
80
|
+
/** Returns the backend live-value count. */
|
|
81
|
+
status(): AsyncResult<{
|
|
82
|
+
values: number;
|
|
83
|
+
}, KVError>;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
package/kv.js
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { Kvm } from "@nats-io/kv";
|
|
2
|
+
import { AsyncResult, Result } from "@oatscenter/result";
|
|
3
|
+
import { KVError, ValidationError } from "./errors/index.js";
|
|
4
|
+
import { decodeSubject, escapeKvKey } from "./helpers.js";
|
|
5
|
+
const KV_MAGIC = new Uint8Array([0x54, 0x52, 0x4b, 0x56]);
|
|
6
|
+
const KV_ENVELOPE_FORMAT = 1;
|
|
7
|
+
const KV_ENVELOPE_HEADER_BYTES = 9;
|
|
8
|
+
const textEncoder = new TextEncoder();
|
|
9
|
+
const textDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
10
|
+
function revisionFromBackend(revision) {
|
|
11
|
+
return revision;
|
|
12
|
+
}
|
|
13
|
+
/** Verifies that an existing physical bucket satisfies the requested limits. */
|
|
14
|
+
export async function ensureExistingBucketOptions(kv, name, options) {
|
|
15
|
+
const status = await kv.status();
|
|
16
|
+
const history = options.history ?? 1;
|
|
17
|
+
const ttl = options.ttl ?? 0;
|
|
18
|
+
if (status.bucket !== name) {
|
|
19
|
+
throw new Error(`KV bucket '${name}' opened physical bucket '${status.bucket}'`);
|
|
20
|
+
}
|
|
21
|
+
if (status.history < history) {
|
|
22
|
+
throw new Error(`KV bucket '${name}' history ${status.history} is less than requested ${history}`);
|
|
23
|
+
}
|
|
24
|
+
if (status.ttl !== ttl) {
|
|
25
|
+
throw new Error(`KV bucket '${name}' TTL does not match requested TTL`);
|
|
26
|
+
}
|
|
27
|
+
if (status.max_bytes > 0) {
|
|
28
|
+
throw new Error(`KV bucket '${name}' has an uncommitted provider total size limit`);
|
|
29
|
+
}
|
|
30
|
+
const maxValueBytes = options.maxValueBytes;
|
|
31
|
+
if (maxValueBytes === undefined && status.maxValueSize > 0) {
|
|
32
|
+
throw new Error(`KV bucket '${name}' has an uncommitted provider value size limit`);
|
|
33
|
+
}
|
|
34
|
+
if (maxValueBytes !== undefined &&
|
|
35
|
+
status.maxValueSize > 0 && status.maxValueSize < maxValueBytes) {
|
|
36
|
+
throw new Error(`KV bucket '${name}' provider size limit is less than requested`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function kvError(operation, key, cause) {
|
|
40
|
+
return new KVError({
|
|
41
|
+
operation,
|
|
42
|
+
cause,
|
|
43
|
+
context: key === undefined ? undefined : { key },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function validationError(entry, message, cause) {
|
|
47
|
+
return new ValidationError({
|
|
48
|
+
errors: [{ path: "", message }],
|
|
49
|
+
cause,
|
|
50
|
+
context: {
|
|
51
|
+
key: decodeSubject(entry.key),
|
|
52
|
+
revision: entry.revision,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** Encode a current value in the strict TRKV envelope. */
|
|
57
|
+
export function encodeResourceValue(representation, value) {
|
|
58
|
+
if (!Number.isInteger(representation.version) || representation.version <= 0 ||
|
|
59
|
+
representation.version > 0xffff_ffff) {
|
|
60
|
+
throw new RangeError("KV representation version must be a positive u32");
|
|
61
|
+
}
|
|
62
|
+
const body = textEncoder.encode(JSON.stringify(representation.codec.encode(value)));
|
|
63
|
+
const bytes = new Uint8Array(KV_ENVELOPE_HEADER_BYTES + body.length);
|
|
64
|
+
bytes.set(KV_MAGIC);
|
|
65
|
+
bytes[4] = KV_ENVELOPE_FORMAT;
|
|
66
|
+
new DataView(bytes.buffer).setUint32(5, representation.version);
|
|
67
|
+
bytes.set(body, KV_ENVELOPE_HEADER_BYTES);
|
|
68
|
+
return bytes;
|
|
69
|
+
}
|
|
70
|
+
/** Decode and optionally migrate one envelope without writing it back. */
|
|
71
|
+
export async function decodeResourceValue(representation, migrations, bytes) {
|
|
72
|
+
if (bytes.length < KV_ENVELOPE_HEADER_BYTES ||
|
|
73
|
+
KV_MAGIC.some((byte, index) => bytes[index] !== byte) ||
|
|
74
|
+
bytes[4] !== KV_ENVELOPE_FORMAT)
|
|
75
|
+
throw new Error("Invalid TRKV envelope");
|
|
76
|
+
const version = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(5);
|
|
77
|
+
const encoded = JSON.parse(textDecoder.decode(bytes.subarray(KV_ENVELOPE_HEADER_BYTES)));
|
|
78
|
+
if (version === representation.version) {
|
|
79
|
+
return representation.codec.decode(encoded);
|
|
80
|
+
}
|
|
81
|
+
const historicCodec = representation.migrations[version];
|
|
82
|
+
const migrate = migrations[version];
|
|
83
|
+
if (!historicCodec || !migrate) {
|
|
84
|
+
throw new Error(`Unsupported resource representation version ${version}`);
|
|
85
|
+
}
|
|
86
|
+
const migrated = await migrate(historicCodec.decode(encoded));
|
|
87
|
+
if (migrated instanceof Result) {
|
|
88
|
+
if (migrated.isErr())
|
|
89
|
+
throw migrated.error;
|
|
90
|
+
return representation.codec.decode(representation.codec.encode(migrated.unwrapOrElse(() => {
|
|
91
|
+
throw new Error("Resource migration unexpectedly failed");
|
|
92
|
+
})));
|
|
93
|
+
}
|
|
94
|
+
return representation.codec.decode(representation.codec.encode(migrated));
|
|
95
|
+
}
|
|
96
|
+
async function decodeEntry(representation, migrations, entry) {
|
|
97
|
+
const base = {
|
|
98
|
+
key: decodeSubject(entry.key),
|
|
99
|
+
revision: revisionFromBackend(entry.revision),
|
|
100
|
+
timestamp: entry.created,
|
|
101
|
+
};
|
|
102
|
+
if (entry.operation === "DEL" || entry.operation === "PURGE") {
|
|
103
|
+
return Result.ok({ ...base, operation: "delete" });
|
|
104
|
+
}
|
|
105
|
+
const bytes = entry.value;
|
|
106
|
+
if (bytes.length < KV_ENVELOPE_HEADER_BYTES ||
|
|
107
|
+
KV_MAGIC.some((byte, index) => bytes[index] !== byte) ||
|
|
108
|
+
bytes[4] !== KV_ENVELOPE_FORMAT) {
|
|
109
|
+
return Result.err(validationError(entry, "Invalid TRKV envelope"));
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const value = await decodeResourceValue(representation, migrations, bytes);
|
|
113
|
+
return Result.ok({ ...base, operation: "put", value });
|
|
114
|
+
}
|
|
115
|
+
catch (cause) {
|
|
116
|
+
return Result.err(validationError(entry, "Failed to decode or migrate KV value", cause));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Typed access to a generated, versioned KV resource. */
|
|
120
|
+
export class TypedKV {
|
|
121
|
+
representation;
|
|
122
|
+
kv;
|
|
123
|
+
migrations;
|
|
124
|
+
isCurrent;
|
|
125
|
+
constructor(representation, kv, migrations, isCurrent) {
|
|
126
|
+
this.representation = representation;
|
|
127
|
+
this.kv = kv;
|
|
128
|
+
this.migrations = migrations;
|
|
129
|
+
this.isCurrent = isCurrent;
|
|
130
|
+
}
|
|
131
|
+
/** Opens or creates a typed KV bucket. */
|
|
132
|
+
static open(nats, name, representation, options = {}) {
|
|
133
|
+
return AsyncResult.from((async () => {
|
|
134
|
+
try {
|
|
135
|
+
const kvm = new Kvm(nats);
|
|
136
|
+
const kv = options.bindOnly
|
|
137
|
+
? await kvm.open(name)
|
|
138
|
+
: await kvm.create(name, {
|
|
139
|
+
history: options.history ?? 1,
|
|
140
|
+
ttl: options.ttl ?? 0,
|
|
141
|
+
...(options.replicas === undefined
|
|
142
|
+
? {}
|
|
143
|
+
: { replicas: options.replicas }),
|
|
144
|
+
...(options.maxValueBytes === undefined
|
|
145
|
+
? {}
|
|
146
|
+
: { maxValueSize: options.maxValueBytes }),
|
|
147
|
+
});
|
|
148
|
+
await ensureExistingBucketOptions(kv, name, options);
|
|
149
|
+
return Result.ok(new TypedKV(representation, kv, options.migrations ?? {}, options.isCurrent ?? (() => true)));
|
|
150
|
+
}
|
|
151
|
+
catch (cause) {
|
|
152
|
+
return Result.err(kvError("open", undefined, cause));
|
|
153
|
+
}
|
|
154
|
+
})());
|
|
155
|
+
}
|
|
156
|
+
/** Returns the current value, or `undefined` when absent or deleted. */
|
|
157
|
+
get(key) {
|
|
158
|
+
return this.getEntry(key).map((entry) => entry?.operation === "put" ? entry.value : undefined);
|
|
159
|
+
}
|
|
160
|
+
/** Returns the latest value or tombstone with authoritative revision metadata. */
|
|
161
|
+
getEntry(key) {
|
|
162
|
+
return AsyncResult.from((async () => {
|
|
163
|
+
try {
|
|
164
|
+
this.#assertCurrent();
|
|
165
|
+
const entry = await this.kv.get(escapeKvKey(key));
|
|
166
|
+
return entry
|
|
167
|
+
? await decodeEntry(this.representation, this.migrations, entry)
|
|
168
|
+
: Result.ok(undefined);
|
|
169
|
+
}
|
|
170
|
+
catch (cause) {
|
|
171
|
+
return Result.err(kvError("get", key, cause));
|
|
172
|
+
}
|
|
173
|
+
})());
|
|
174
|
+
}
|
|
175
|
+
/** Creates a value only when the key has no current value. */
|
|
176
|
+
create(key, value) {
|
|
177
|
+
return AsyncResult.from((async () => {
|
|
178
|
+
try {
|
|
179
|
+
this.#assertCurrent();
|
|
180
|
+
const revision = await this.kv.create(escapeKvKey(key), encodeResourceValue(this.representation, value));
|
|
181
|
+
return Result.ok({
|
|
182
|
+
key,
|
|
183
|
+
value,
|
|
184
|
+
revision: revisionFromBackend(revision),
|
|
185
|
+
timestamp: new Date(),
|
|
186
|
+
operation: "put",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch (cause) {
|
|
190
|
+
return Result.err(kvError("create", key, cause));
|
|
191
|
+
}
|
|
192
|
+
})());
|
|
193
|
+
}
|
|
194
|
+
/** Writes a value without a revision precondition. */
|
|
195
|
+
put(key, value) {
|
|
196
|
+
return AsyncResult.from((async () => {
|
|
197
|
+
try {
|
|
198
|
+
this.#assertCurrent();
|
|
199
|
+
const revision = await this.kv.put(escapeKvKey(key), encodeResourceValue(this.representation, value));
|
|
200
|
+
return Result.ok({
|
|
201
|
+
key,
|
|
202
|
+
value,
|
|
203
|
+
revision: revisionFromBackend(revision),
|
|
204
|
+
timestamp: new Date(),
|
|
205
|
+
operation: "put",
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (cause) {
|
|
209
|
+
return Result.err(kvError("put", key, cause));
|
|
210
|
+
}
|
|
211
|
+
})());
|
|
212
|
+
}
|
|
213
|
+
/** Replaces a value only when its current revision matches. */
|
|
214
|
+
replace(key, revision, value) {
|
|
215
|
+
return AsyncResult.from((async () => {
|
|
216
|
+
try {
|
|
217
|
+
this.#assertCurrent();
|
|
218
|
+
const nextRevision = await this.kv.update(escapeKvKey(key), encodeResourceValue(this.representation, value), revision);
|
|
219
|
+
return Result.ok({
|
|
220
|
+
key,
|
|
221
|
+
value,
|
|
222
|
+
revision: revisionFromBackend(nextRevision),
|
|
223
|
+
timestamp: new Date(),
|
|
224
|
+
operation: "put",
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
catch (cause) {
|
|
228
|
+
return Result.err(kvError("replace", key, cause));
|
|
229
|
+
}
|
|
230
|
+
})());
|
|
231
|
+
}
|
|
232
|
+
/** Deletes a key, optionally requiring its current revision. */
|
|
233
|
+
delete(key, revision) {
|
|
234
|
+
return AsyncResult.from((async () => {
|
|
235
|
+
try {
|
|
236
|
+
this.#assertCurrent();
|
|
237
|
+
await this.kv.delete(escapeKvKey(key), revision === undefined ? {} : { previousSeq: revision });
|
|
238
|
+
return Result.ok(undefined);
|
|
239
|
+
}
|
|
240
|
+
catch (cause) {
|
|
241
|
+
return Result.err(kvError("delete", key, cause));
|
|
242
|
+
}
|
|
243
|
+
})());
|
|
244
|
+
}
|
|
245
|
+
/** Returns all retained revisions for a key, including tombstones. */
|
|
246
|
+
history(key) {
|
|
247
|
+
return AsyncResult.from((async () => {
|
|
248
|
+
try {
|
|
249
|
+
this.#assertCurrent();
|
|
250
|
+
const history = await this.kv.history({ key: escapeKvKey(key) });
|
|
251
|
+
const entries = [];
|
|
252
|
+
for await (const entry of history) {
|
|
253
|
+
this.#assertCurrent();
|
|
254
|
+
const decoded = await decodeEntry(this.representation, this.migrations, entry);
|
|
255
|
+
if (decoded.isErr())
|
|
256
|
+
return decoded;
|
|
257
|
+
entries.push(decoded.unwrapOrElse(() => {
|
|
258
|
+
throw new Error("KV history decode unexpectedly failed");
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
entries.sort((left, right) => left.revision - right.revision);
|
|
262
|
+
return Result.ok(entries);
|
|
263
|
+
}
|
|
264
|
+
catch (cause) {
|
|
265
|
+
return Result.err(kvError("history", key, cause));
|
|
266
|
+
}
|
|
267
|
+
})());
|
|
268
|
+
}
|
|
269
|
+
/** Watches retained initialization and subsequent revisions for one key. */
|
|
270
|
+
watch(key) {
|
|
271
|
+
return AsyncResult.from((async () => {
|
|
272
|
+
try {
|
|
273
|
+
this.#assertCurrent();
|
|
274
|
+
const watcher = await this.kv.watch({
|
|
275
|
+
key: escapeKvKey(key),
|
|
276
|
+
include: "history",
|
|
277
|
+
});
|
|
278
|
+
const representation = this.representation;
|
|
279
|
+
const migrations = this.migrations;
|
|
280
|
+
const isCurrent = this.isCurrent;
|
|
281
|
+
return Result.ok({
|
|
282
|
+
async *[Symbol.asyncIterator]() {
|
|
283
|
+
try {
|
|
284
|
+
for await (const entry of watcher) {
|
|
285
|
+
if (!isCurrent()) {
|
|
286
|
+
throw new Error("KV resource binding is stale");
|
|
287
|
+
}
|
|
288
|
+
yield await decodeEntry(representation, migrations, entry);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
watcher.stop();
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
catch (cause) {
|
|
298
|
+
return Result.err(kvError("watch", key, cause));
|
|
299
|
+
}
|
|
300
|
+
})());
|
|
301
|
+
}
|
|
302
|
+
/** Lists live keys using the backend's bounded iterator. */
|
|
303
|
+
keys(filter = ">") {
|
|
304
|
+
return AsyncResult.from((async () => {
|
|
305
|
+
try {
|
|
306
|
+
this.#assertCurrent();
|
|
307
|
+
return Result.ok(await this.kv.keys(filter));
|
|
308
|
+
}
|
|
309
|
+
catch (cause) {
|
|
310
|
+
return Result.err(kvError("keys", undefined, cause));
|
|
311
|
+
}
|
|
312
|
+
})());
|
|
313
|
+
}
|
|
314
|
+
/** Returns the backend live-value count. */
|
|
315
|
+
status() {
|
|
316
|
+
return AsyncResult.from((async () => {
|
|
317
|
+
try {
|
|
318
|
+
this.#assertCurrent();
|
|
319
|
+
return Result.ok({ values: (await this.kv.status()).values });
|
|
320
|
+
}
|
|
321
|
+
catch (cause) {
|
|
322
|
+
return Result.err(kvError("status", undefined, cause));
|
|
323
|
+
}
|
|
324
|
+
})());
|
|
325
|
+
}
|
|
326
|
+
#assertCurrent() {
|
|
327
|
+
if (!this.isCurrent())
|
|
328
|
+
throw new Error("KV resource binding is stale");
|
|
329
|
+
}
|
|
330
|
+
}
|
package/operations.d.ts
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { AsyncResult, type Result } from "@oatscenter/result";
|
|
2
|
+
import { type JsonValue } from "./codec.ts";
|
|
3
|
+
import type { InferSchemaType } from "./participant.ts";
|
|
4
|
+
import { OperationAlreadyTerminalError, OperationMismatchError, OperationNotFoundError, TransferError, TransportError, UnexpectedError } from "./errors/index.ts";
|
|
5
|
+
import type { FileInfo, SendTransferGrant, TransferBody } from "./transfer.ts";
|
|
6
|
+
export type OperationState = "pending" | "running" | "completed" | "failed" | "cancelled";
|
|
7
|
+
export type OperationRefData = {
|
|
8
|
+
id: string;
|
|
9
|
+
service: string;
|
|
10
|
+
operation: string;
|
|
11
|
+
};
|
|
12
|
+
export type OperationSnapshot<TProgress = unknown, TOutput = unknown> = {
|
|
13
|
+
id: string;
|
|
14
|
+
service: string;
|
|
15
|
+
operation: string;
|
|
16
|
+
revision: number;
|
|
17
|
+
state: OperationState;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
completedAt?: string;
|
|
21
|
+
progress?: TProgress;
|
|
22
|
+
transfer?: OperationTransferProgress;
|
|
23
|
+
output?: TOutput;
|
|
24
|
+
error?: {
|
|
25
|
+
type: string;
|
|
26
|
+
message: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type OperationTransferProgress = {
|
|
30
|
+
chunkIndex: number;
|
|
31
|
+
chunkBytes: number;
|
|
32
|
+
transferredBytes: number;
|
|
33
|
+
};
|
|
34
|
+
/** Errors returned when an operation control request violates lifecycle state. */
|
|
35
|
+
export type OperationLifecycleError = OperationNotFoundError | OperationAlreadyTerminalError | OperationMismatchError;
|
|
36
|
+
/** Errors returned when an operation control request fails before producing a snapshot or ack. */
|
|
37
|
+
export type OperationControlError = TransportError | OperationLifecycleError;
|
|
38
|
+
export type TerminalOperation<TProgress = unknown, TOutput = unknown> = (OperationSnapshot<TProgress, TOutput> & {
|
|
39
|
+
state: "completed";
|
|
40
|
+
}) | (OperationSnapshot<TProgress, TOutput> & {
|
|
41
|
+
state: "failed";
|
|
42
|
+
}) | (OperationSnapshot<TProgress, TOutput> & {
|
|
43
|
+
state: "cancelled";
|
|
44
|
+
});
|
|
45
|
+
export type OperationSignalAck<TProgress = unknown, TOutput = unknown> = {
|
|
46
|
+
kind: "signal-accepted";
|
|
47
|
+
operationId: string;
|
|
48
|
+
signal: string;
|
|
49
|
+
signalSequence: number;
|
|
50
|
+
acceptedAt: string;
|
|
51
|
+
snapshot: OperationSnapshot<TProgress, TOutput>;
|
|
52
|
+
};
|
|
53
|
+
export type CompletedTransfer<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>> = {
|
|
54
|
+
transferred: FileInfo;
|
|
55
|
+
terminal: TerminalOperation<TProgress, TOutput>;
|
|
56
|
+
};
|
|
57
|
+
export type StartedTransfer<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> = {
|
|
58
|
+
operation: OperationRef<TDesc, TProgress, TOutput, TUpdate>;
|
|
59
|
+
wait(): AsyncResult<CompletedTransfer<TDesc, TProgress, TOutput>, OperationControlError | UnexpectedError | TransferError>;
|
|
60
|
+
};
|
|
61
|
+
export type OperationRef<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> = {
|
|
62
|
+
id: string;
|
|
63
|
+
service: string;
|
|
64
|
+
operation: string;
|
|
65
|
+
get(): AsyncResult<OperationSnapshot<TProgress, TOutput>, OperationControlError | UnexpectedError>;
|
|
66
|
+
wait(): AsyncResult<TerminalOperation<TProgress, TOutput>, OperationControlError | UnexpectedError>;
|
|
67
|
+
watch(options?: OperationWatchOptions): AsyncResult<AsyncIterable<OperationEvent<TProgress, TOutput, TUpdate>>, OperationControlError | UnexpectedError>;
|
|
68
|
+
cancel(): AsyncResult<OperationSnapshot<TProgress, TOutput>, OperationControlError | UnexpectedError>;
|
|
69
|
+
signal(signal: string, input?: unknown): AsyncResult<OperationSignalAck<TProgress, TOutput>, OperationControlError | UnexpectedError>;
|
|
70
|
+
};
|
|
71
|
+
/** Options controlling optional operation watch event classes. */
|
|
72
|
+
export type OperationWatchOptions = {
|
|
73
|
+
/** Include transient typed update events. */
|
|
74
|
+
updates?: boolean;
|
|
75
|
+
};
|
|
76
|
+
/** Options that identify an idempotent operation invocation. */
|
|
77
|
+
export type OperationStartOptions = {
|
|
78
|
+
invocationId?: string;
|
|
79
|
+
};
|
|
80
|
+
export type AcceptedOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
81
|
+
type: "accepted";
|
|
82
|
+
snapshot: OperationSnapshot<TProgress, TOutput>;
|
|
83
|
+
};
|
|
84
|
+
export type StartedOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
85
|
+
type: "started";
|
|
86
|
+
snapshot: OperationSnapshot<TProgress, TOutput>;
|
|
87
|
+
};
|
|
88
|
+
export type TransferOperationSnapshot<TProgress = unknown, TOutput = unknown> = OperationSnapshot<TProgress, TOutput> & {
|
|
89
|
+
transfer: OperationTransferProgress;
|
|
90
|
+
};
|
|
91
|
+
export type TransferOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
92
|
+
type: "transfer";
|
|
93
|
+
snapshot: TransferOperationSnapshot<TProgress, TOutput>;
|
|
94
|
+
transfer: OperationTransferProgress;
|
|
95
|
+
};
|
|
96
|
+
export type ProgressOperationSnapshot<TProgress = unknown, TOutput = unknown> = OperationSnapshot<TProgress, TOutput> & {
|
|
97
|
+
progress: TProgress;
|
|
98
|
+
};
|
|
99
|
+
export type ProgressOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
100
|
+
type: "progress";
|
|
101
|
+
snapshot: ProgressOperationSnapshot<TProgress, TOutput>;
|
|
102
|
+
progress: TProgress;
|
|
103
|
+
};
|
|
104
|
+
/** A transient operation update paired with the unchanged current snapshot. */
|
|
105
|
+
export type UpdateOperationEvent<TProgress = unknown, TOutput = unknown, TUpdate = unknown> = {
|
|
106
|
+
type: "update";
|
|
107
|
+
update: TUpdate;
|
|
108
|
+
snapshot: OperationSnapshot<TProgress, TOutput>;
|
|
109
|
+
};
|
|
110
|
+
export type CompletedOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
111
|
+
type: "completed";
|
|
112
|
+
snapshot: TerminalOperation<TProgress, TOutput>;
|
|
113
|
+
};
|
|
114
|
+
export type FailedOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
115
|
+
type: "failed";
|
|
116
|
+
snapshot: TerminalOperation<TProgress, TOutput>;
|
|
117
|
+
};
|
|
118
|
+
export type CancelledOperationEvent<TProgress = unknown, TOutput = unknown> = {
|
|
119
|
+
type: "cancelled";
|
|
120
|
+
snapshot: TerminalOperation<TProgress, TOutput>;
|
|
121
|
+
};
|
|
122
|
+
export type OperationEvent<TProgress = unknown, TOutput = unknown, TUpdate = unknown> = AcceptedOperationEvent<TProgress, TOutput> | StartedOperationEvent<TProgress, TOutput> | TransferOperationEvent<TProgress, TOutput> | ProgressOperationEvent<TProgress, TOutput> | UpdateOperationEvent<TProgress, TOutput, TUpdate> | CompletedOperationEvent<TProgress, TOutput> | FailedOperationEvent<TProgress, TOutput> | CancelledOperationEvent<TProgress, TOutput>;
|
|
123
|
+
export type OperationObserverCallbacks<TProgress = unknown, TOutput = unknown, TUpdate = unknown> = {
|
|
124
|
+
onAccepted?: (event: AcceptedOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
125
|
+
onStarted?: (event: StartedOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
126
|
+
onTransfer?: (event: TransferOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
127
|
+
onProgress?: (event: ProgressOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
128
|
+
onUpdate?: (event: UpdateOperationEvent<TProgress, TOutput, TUpdate>) => void | Promise<void>;
|
|
129
|
+
onCompleted?: (event: CompletedOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
130
|
+
onFailed?: (event: FailedOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
131
|
+
onCancelled?: (event: CancelledOperationEvent<TProgress, TOutput>) => void | Promise<void>;
|
|
132
|
+
onEvent?: (event: OperationEvent<TProgress, TOutput, TUpdate>) => void | Promise<void>;
|
|
133
|
+
};
|
|
134
|
+
interface OperationObserverBuilderBase<TBuilder, TProgress = unknown, TOutput = unknown, TUpdate = unknown> {
|
|
135
|
+
onAccepted(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onAccepted"]>): TBuilder;
|
|
136
|
+
onStarted(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onStarted"]>): TBuilder;
|
|
137
|
+
onProgress(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onProgress"]>): TBuilder;
|
|
138
|
+
onUpdate(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput, TUpdate>["onUpdate"]>): TBuilder;
|
|
139
|
+
onCompleted(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onCompleted"]>): TBuilder;
|
|
140
|
+
onFailed(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onFailed"]>): TBuilder;
|
|
141
|
+
onCancelled(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onCancelled"]>): TBuilder;
|
|
142
|
+
onEvent(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput, TUpdate>["onEvent"]>): TBuilder;
|
|
143
|
+
}
|
|
144
|
+
interface OperationInputBuilderBase<TDesc extends OperationShape, TProgress, TOutput, TUpdate, TBuilder> extends OperationObserverBuilderBase<TBuilder, TProgress, TOutput, TUpdate> {
|
|
145
|
+
start(callbacks?: OperationObserverCallbacks<TProgress, TOutput, TUpdate>, options?: OperationStartOptions): AsyncResult<OperationRef<TDesc, TProgress, TOutput, TUpdate>, OperationControlError | UnexpectedError>;
|
|
146
|
+
}
|
|
147
|
+
export interface TransferOperationBuilder<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> extends OperationObserverBuilderBase<TransferOperationBuilder<TDesc, TProgress, TOutput, TUpdate>, TProgress, TOutput, TUpdate> {
|
|
148
|
+
onTransfer(handler: NonNullable<OperationObserverCallbacks<TProgress, TOutput>["onTransfer"]>): TransferOperationBuilder<TDesc, TProgress, TOutput, TUpdate>;
|
|
149
|
+
start(callbacks?: OperationObserverCallbacks<TProgress, TOutput, TUpdate>, options?: OperationStartOptions): AsyncResult<StartedTransfer<TDesc, TProgress, TOutput, TUpdate>, OperationControlError | UnexpectedError | TransferError>;
|
|
150
|
+
}
|
|
151
|
+
export interface OperationInputBuilder<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> extends OperationInputBuilderBase<TDesc, TProgress, TOutput, TUpdate, OperationInputBuilder<TDesc, TProgress, TOutput, TUpdate>> {
|
|
152
|
+
}
|
|
153
|
+
export interface TransferCapableOperationInputBuilder<TDesc extends OperationShape, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> extends OperationInputBuilderBase<TDesc, TProgress, TOutput, TUpdate, TransferCapableOperationInputBuilder<TDesc, TProgress, TOutput, TUpdate>> {
|
|
154
|
+
transfer(body: TransferBody): TransferOperationBuilder<TDesc, TProgress, TOutput>;
|
|
155
|
+
}
|
|
156
|
+
type OperationShape = {
|
|
157
|
+
subject: string;
|
|
158
|
+
input: unknown;
|
|
159
|
+
progress?: unknown;
|
|
160
|
+
update?: unknown;
|
|
161
|
+
output?: unknown;
|
|
162
|
+
transfer?: {
|
|
163
|
+
store?: string;
|
|
164
|
+
key?: `/${string}`;
|
|
165
|
+
contentType?: `/${string}`;
|
|
166
|
+
metadata?: `/${string}`;
|
|
167
|
+
expiresInMs?: number;
|
|
168
|
+
maxBytes?: number;
|
|
169
|
+
};
|
|
170
|
+
cancel?: boolean;
|
|
171
|
+
};
|
|
172
|
+
type OperationInputOf<TDesc extends OperationShape> = InferSchemaType<TDesc["input"]>;
|
|
173
|
+
type OperationProgressOf<TDesc extends OperationShape> = TDesc["progress"] extends undefined ? unknown : InferSchemaType<NonNullable<TDesc["progress"]>>;
|
|
174
|
+
type OperationUpdateOf<TDesc extends OperationShape> = TDesc["update"] extends undefined ? unknown : InferSchemaType<NonNullable<TDesc["update"]>>;
|
|
175
|
+
type OperationOutputOf<TDesc extends OperationShape> = TDesc["output"] extends undefined ? unknown : InferSchemaType<NonNullable<TDesc["output"]>>;
|
|
176
|
+
export interface OperationTransport {
|
|
177
|
+
requestJson(subject: string, body: JsonValue): AsyncResult<JsonValue, TransportError | UnexpectedError>;
|
|
178
|
+
watchJson(subject: string, body: JsonValue): AsyncResult<AsyncIterable<Result<JsonValue, TransportError | UnexpectedError>>, TransportError | UnexpectedError>;
|
|
179
|
+
putTransfer(grant: SendTransferGrant, body: TransferBody): AsyncResult<FileInfo, TransferError>;
|
|
180
|
+
}
|
|
181
|
+
export declare function controlSubject(subject: string): string;
|
|
182
|
+
export declare class OperationInvoker<TDesc extends OperationShape, TInput = OperationInputOf<TDesc>, TProgress = OperationProgressOf<TDesc>, TOutput = OperationOutputOf<TDesc>, TUpdate = OperationUpdateOf<TDesc>> {
|
|
183
|
+
#private;
|
|
184
|
+
constructor(transport: OperationTransport, descriptor: TDesc);
|
|
185
|
+
resume(ref: OperationRefData): OperationRef<TDesc, TProgress, TOutput, TUpdate>;
|
|
186
|
+
start(input: TInput, callbacks?: OperationObserverCallbacks<TProgress, TOutput, TUpdate>): AsyncResult<OperationRef<TDesc, TProgress, TOutput, TUpdate>, OperationControlError | UnexpectedError>;
|
|
187
|
+
input(input: TInput): TDesc["transfer"] extends undefined ? OperationInputBuilder<TDesc, TProgress, TOutput, TUpdate> : TransferCapableOperationInputBuilder<TDesc, TProgress, TOutput, TUpdate>;
|
|
188
|
+
}
|
|
189
|
+
export {};
|