@voltro/runtime 0.22.1 → 0.24.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/CHANGELOG.md +427 -0
- package/dist/index.d.ts +124 -3
- package/dist/index.js +1951 -1889
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1117,7 +1117,7 @@ export declare interface BeginOAuthResult {
|
|
|
1117
1117
|
*/
|
|
1118
1118
|
export declare const bindConnectionSubject: (clientId: number, subject: Subject) => void;
|
|
1119
1119
|
|
|
1120
|
-
export declare const bindMutation: <Input, Output, E = never>(execute: (input: Input, context: RuntimeContext) => Output | Promise<Output> | Effect.Effect<Output, E, never>, input: Input, spanName?: string) => Effect.Effect<Output, E, SubjectService | ConnectionInfo>;
|
|
1120
|
+
export declare const bindMutation: <Input, Output, E = never>(execute: (input: Input, context: RuntimeContext) => Output | Promise<Output> | Effect.Effect<Output, E, never>, input: Input, spanName?: string, codec?: MutationOutputCodec<unknown>, idempotency?: IdempotencyBinding) => Effect.Effect<Output, E, SubjectService | ConnectionInfo>;
|
|
1121
1121
|
|
|
1122
1122
|
/**
|
|
1123
1123
|
* Bind a non-reactive server→client stream (A3). The executor builds a
|
|
@@ -2170,6 +2170,13 @@ export declare const drainForShutdown: (options: {
|
|
|
2170
2170
|
readonly hooks: ReadonlyArray<() => void | Promise<void>>;
|
|
2171
2171
|
readonly deadlineMs: number;
|
|
2172
2172
|
readonly exit: () => void;
|
|
2173
|
+
/** How the drain ended, for the caller to report. A completed drain and one
|
|
2174
|
+
* CUT at the deadline are different incidents and were indistinguishable in
|
|
2175
|
+
* the log — asked for by a consumer who could see neither. */
|
|
2176
|
+
readonly onOutcome?: (outcome: {
|
|
2177
|
+
readonly reason: "drained" | "deadline";
|
|
2178
|
+
readonly ms: number;
|
|
2179
|
+
}) => void;
|
|
2173
2180
|
}) => void;
|
|
2174
2181
|
|
|
2175
2182
|
/**
|
|
@@ -2504,6 +2511,9 @@ export declare interface GroupState {
|
|
|
2504
2511
|
readonly extreme?: number;
|
|
2505
2512
|
}
|
|
2506
2513
|
|
|
2514
|
+
/** What a user handler may return. */
|
|
2515
|
+
export declare type HandlerBody = void | Promise<unknown> | Effect.Effect<unknown, unknown, never>;
|
|
2516
|
+
|
|
2507
2517
|
/** Define a histogram. `boundaries` default to the framework duration buckets. */
|
|
2508
2518
|
export declare const histogramMetric: (name: string, boundaries?: MetricBoundaries.MetricBoundaries, description?: string) => Metric.Metric.Histogram<number>;
|
|
2509
2519
|
|
|
@@ -2530,6 +2540,21 @@ export declare interface HttpSecretsOptions {
|
|
|
2530
2540
|
readonly ttlMs?: number;
|
|
2531
2541
|
}
|
|
2532
2542
|
|
|
2543
|
+
/**
|
|
2544
|
+
* WS-rpc idempotency store + TTL, passed to `bindMutation` as a closure param by
|
|
2545
|
+
* the boot path (`serveApi`/`dev`) — NOT a service. @effect/rpc runs a handler in
|
|
2546
|
+
* a NARROWED context (only the middleware `provides` + declared deps), so a plain
|
|
2547
|
+
* merged service is invisible to `Effect.serviceOption` inside the handler; the
|
|
2548
|
+
* store+ttl are boot-time constants the bind site already holds, so a closure is
|
|
2549
|
+
* both correct and simpler. Omitted → WS mutation dedup is off (the default).
|
|
2550
|
+
* Reuses the SAME `dataStoreIdempotencyStore` + `_voltro_idempotency` table as
|
|
2551
|
+
* the REST path — enable once, protect both.
|
|
2552
|
+
*/
|
|
2553
|
+
export declare interface IdempotencyBinding {
|
|
2554
|
+
readonly store: IdempotencyStore;
|
|
2555
|
+
readonly ttlMs: number;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2533
2558
|
export declare interface IdleCheckOptions {
|
|
2534
2559
|
readonly store: DataStore;
|
|
2535
2560
|
readonly signals: ActivitySignals;
|
|
@@ -2775,6 +2800,15 @@ export declare const isOrglessUserSubject: (subject: {
|
|
|
2775
2800
|
readonly tenantId?: string | null;
|
|
2776
2801
|
} | null | undefined) => boolean;
|
|
2777
2802
|
|
|
2803
|
+
/** A query cancelled for exceeding the `statementTimeoutMs` deadline, across
|
|
2804
|
+
* dialects: pg `57014` (query_canceled — what `statement_timeout` raises),
|
|
2805
|
+
* MySQL `3024` (ER_QUERY_TIMEOUT), MariaDB `1969` (ER_STATEMENT_TIMEOUT), mssql
|
|
2806
|
+
* `ETIMEOUT` (tedious request timeout), sqlite `SQLITE_INTERRUPT`. NOT a
|
|
2807
|
+
* transient error — a re-run just repeats the runaway, so it must not retry
|
|
2808
|
+
* (`servePipeline`'s transient set deliberately excludes it). Lets a consumer /
|
|
2809
|
+
* observability layer name the failure instead of reading an opaque SqlError. */
|
|
2810
|
+
export declare const isQueryTimeout: (dbCause: Record<string, unknown>) => boolean;
|
|
2811
|
+
|
|
2778
2812
|
/**
|
|
2779
2813
|
* Optimistic-concurrency guard: an undo is safe only when the row still looks
|
|
2780
2814
|
* like what the forward mutation left (`next`). If another writer changed it
|
|
@@ -3143,6 +3177,14 @@ export declare const makeLazyWorkflowFacade: (resolve: () => WorkflowsAppContext
|
|
|
3143
3177
|
/** `__voltro.connections.list` — every declared connection, for the caller. */
|
|
3144
3178
|
export declare const makeListConnectionsExecutor: (deps: ConnectionBuiltinDeps) => (_input: Record<string, never>, ctx: ConnectionExecutorCtx) => Promise<ReadonlyArray<ConnectionState>>;
|
|
3145
3179
|
|
|
3180
|
+
/**
|
|
3181
|
+
* Build the replay codec from a mutation's `descriptor.output` Schema (call it at
|
|
3182
|
+
* the bind site). Both directions fall back to the raw value if the Schema can't
|
|
3183
|
+
* round-trip it — a guard for exotic schemas; for a value the handler actually
|
|
3184
|
+
* produced, `encodeUnknownSync` never throws. `undefined` schema → no codec.
|
|
3185
|
+
*/
|
|
3186
|
+
export declare const makeMutationOutputCodec: (outputSchema: Schema.Schema.AnyNoContext | undefined) => MutationOutputCodec<unknown> | undefined;
|
|
3187
|
+
|
|
3146
3188
|
/**
|
|
3147
3189
|
* Build the shared mutation runner. Used by BOTH the rpc WS handler and
|
|
3148
3190
|
* the `/_voltro/inspect/invoke` endpoint (and the prod entrypoint) so they
|
|
@@ -3438,6 +3480,20 @@ export declare interface MutationLike {
|
|
|
3438
3480
|
executor(input: unknown, ctx: unknown): unknown;
|
|
3439
3481
|
}
|
|
3440
3482
|
|
|
3483
|
+
/**
|
|
3484
|
+
* Encode/decode a mutation's output for idempotent replay. On a FRESH call the
|
|
3485
|
+
* WIRE form (`encode`) is stored, so a later replay `decode`s it back to the exact
|
|
3486
|
+
* Output the handler would have returned and the rpc layer re-encodes it
|
|
3487
|
+
* identically. Storing the DECODED Output directly would corrupt `Date`/etc.
|
|
3488
|
+
* fields through the store's JSON round-trip (encode there expects a `Date`, not
|
|
3489
|
+
* the ISO string a round-trip produced). Built from `descriptor.output` at the
|
|
3490
|
+
* call site; both fns fall back to the raw value if the Schema can't round-trip.
|
|
3491
|
+
*/
|
|
3492
|
+
export declare interface MutationOutputCodec<Output> {
|
|
3493
|
+
readonly encode: (output: Output) => unknown;
|
|
3494
|
+
readonly decode: (stored: unknown) => Output;
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3441
3497
|
export declare interface MutationRunnerDeps {
|
|
3442
3498
|
readonly store: TransactionalStore;
|
|
3443
3499
|
/** Build the per-call `AppContext` bound to the transactional `tx`. */
|
|
@@ -4928,6 +4984,27 @@ export declare interface RpcServerOptions<Rpcs extends Rpc.Any> {
|
|
|
4928
4984
|
* stream. Absent → falls back to `handlersLayer`. */
|
|
4929
4985
|
readonly httpHandlersLayer?: Layer.Layer<Rpc.ToHandler<Rpcs>>;
|
|
4930
4986
|
readonly port?: number;
|
|
4987
|
+
/**
|
|
4988
|
+
* Interface to bind. Absent → the wildcard, which is what a container needs
|
|
4989
|
+
* and stays the production default.
|
|
4990
|
+
*
|
|
4991
|
+
* Pass `127.0.0.1` when a caller in the SAME PROCESS will connect over IPv4,
|
|
4992
|
+
* which is every test that boots a server and fetches it. A wildcard bind
|
|
4993
|
+
* lands on `:::<port>` (IPv6), and IPv4 and IPv6 are separate binds of the
|
|
4994
|
+
* same number — so a lingering IPv4 socket on that port from an earlier
|
|
4995
|
+
* server accepts the connection instead. The kernel completes the handshake
|
|
4996
|
+
* into ITS backlog, `lsof` reports ESTABLISHED, and the new server never sees
|
|
4997
|
+
* a `connection` event. The request then waits forever against a peer that
|
|
4998
|
+
* will never answer.
|
|
4999
|
+
*
|
|
5000
|
+
* That is not hypothetical: it is the mechanism behind this repo's
|
|
5001
|
+
* long-running "flaky integration test" — measured by instrumenting
|
|
5002
|
+
* `net.Server` and catching a hung run with
|
|
5003
|
+
* `listener#3 bound :::53011 … closed after 0 connection(s)` while its client
|
|
5004
|
+
* sat in `fetch`. Binding the family the client will use turns a silent hang
|
|
5005
|
+
* into an ordinary `EADDRINUSE`.
|
|
5006
|
+
*/
|
|
5007
|
+
readonly host?: string;
|
|
4931
5008
|
readonly path?: `/${string}`;
|
|
4932
5009
|
/** Optional tracer layer (`buildTracingLayer().layer`). Merged into the
|
|
4933
5010
|
* server's layer scope so every `Effect.withSpan` on the handler path
|
|
@@ -5319,7 +5396,20 @@ export declare interface ScheduleFireContext {
|
|
|
5319
5396
|
*/
|
|
5320
5397
|
export declare type ScheduleFireInterceptor = (next: () => Promise<void>, ctx: ScheduleFireContext) => Promise<void>;
|
|
5321
5398
|
|
|
5322
|
-
|
|
5399
|
+
/**
|
|
5400
|
+
* A schedule body. Promise-form or Effect-form; both run.
|
|
5401
|
+
*
|
|
5402
|
+
* The Effect arm is not sugar. Before it existed the call site was
|
|
5403
|
+
* `await def.handler(ctx)`, and an Effect is not a thenable — so `await`
|
|
5404
|
+
* returned it unchanged, the body never executed, and the firing was recorded
|
|
5405
|
+
* as a success. In an Effect-first framework the natural thing to write was the
|
|
5406
|
+
* thing that silently did nothing. Same bridge a file-based migration's `up`
|
|
5407
|
+
* has carried since it shipped.
|
|
5408
|
+
*
|
|
5409
|
+
* `R = never`: the effect must carry its own requirements. Everything a
|
|
5410
|
+
* schedule needs is on `ctx.app`.
|
|
5411
|
+
*/
|
|
5412
|
+
export declare type ScheduleHandler = (ctx: ScheduleContext) => void | Promise<void> | Effect.Effect<unknown, unknown, never>;
|
|
5323
5413
|
|
|
5324
5414
|
/** What happens when a firing arrives while the previous run of the
|
|
5325
5415
|
* same schedule is still in flight. */
|
|
@@ -5677,6 +5767,14 @@ export declare const setSystemStoreHandle: (handle: SystemStoreHandle) => void;
|
|
|
5677
5767
|
/** Test seam — swap (or reset with `undefined`) the process recorder. */
|
|
5678
5768
|
export declare const setTimelineRecorderForTest: (recorder: TimelineRecorder | undefined) => void;
|
|
5679
5769
|
|
|
5770
|
+
/**
|
|
5771
|
+
* Normalise a handler's return value to "a promise, or nothing to wait for".
|
|
5772
|
+
*
|
|
5773
|
+
* `undefined` means the body was synchronous and has already run. Anything else
|
|
5774
|
+
* is a promise the caller disposes of as its context requires.
|
|
5775
|
+
*/
|
|
5776
|
+
export declare const settleHandlerBody: (body: HandlerBody) => Promise<unknown> | undefined;
|
|
5777
|
+
|
|
5680
5778
|
/**
|
|
5681
5779
|
* Register (or clear) the process-global tuple source. Last write wins.
|
|
5682
5780
|
*
|
|
@@ -5695,6 +5793,18 @@ export declare type ShapeClassification = {
|
|
|
5695
5793
|
readonly reason: string;
|
|
5696
5794
|
};
|
|
5697
5795
|
|
|
5796
|
+
/**
|
|
5797
|
+
* The teardown deadline, from `VOLTRO_SHUTDOWN_GRACE_MS` (milliseconds), clamped
|
|
5798
|
+
* to `[1s, 5min]`. Operators set it to sit JUST UNDER their orchestrator's hard
|
|
5799
|
+
* kill — k8s `terminationGracePeriodSeconds`, ECS `stopTimeout` — so the process
|
|
5800
|
+
* drains in-flight work and exits cleanly on its own BEFORE SIGKILL truncates it
|
|
5801
|
+
* mid-drain (which would strand exactly the finalizers this path exists to run:
|
|
5802
|
+
* connection-pool close, plugin `onDeactivate`, analytics flush, trace persist).
|
|
5803
|
+
* A non-numeric / non-positive value falls back to the 10s default rather than
|
|
5804
|
+
* producing a `setTimeout(…, NaN)` that fires immediately and defeats the drain.
|
|
5805
|
+
*/
|
|
5806
|
+
export declare const shutdownGraceMsFromEnv: () => number;
|
|
5807
|
+
|
|
5698
5808
|
/** No-coordination gate for single-instance deployments (PM2,
|
|
5699
5809
|
* single pod, dev). */
|
|
5700
5810
|
export declare const singleCoordinator: Coordinator;
|
|
@@ -5952,7 +6062,18 @@ export declare interface SubscribeContext {
|
|
|
5952
6062
|
* framework's CDC `ChangeEvent` re-exported for ergonomics. */
|
|
5953
6063
|
export declare type SubscribeEvent = ChangeEvent;
|
|
5954
6064
|
|
|
5955
|
-
|
|
6065
|
+
/**
|
|
6066
|
+
* A subscriber body. Promise-form or Effect-form; both run.
|
|
6067
|
+
*
|
|
6068
|
+
* The Effect arm is not sugar — see `ScheduleHandler`. The runner tested
|
|
6069
|
+
* `result instanceof Promise`, an Effect is not one, so the branch was skipped
|
|
6070
|
+
* and the body never executed. No error, no log line, the change event handled
|
|
6071
|
+
* "successfully".
|
|
6072
|
+
*
|
|
6073
|
+
* `R = never`: the effect must carry its own requirements. Everything a
|
|
6074
|
+
* subscriber needs is on `ctx`.
|
|
6075
|
+
*/
|
|
6076
|
+
export declare type SubscribeHandler = (event: SubscribeEvent, ctx: SubscribeContext) => void | Promise<void> | Effect.Effect<unknown, unknown, never>;
|
|
5956
6077
|
|
|
5957
6078
|
/** Which row op(s) the subscriber listens on. `'any'` matches every
|
|
5958
6079
|
* op; an array enumerates the concrete ops. */
|