@voltro/runtime 0.56.0 → 0.58.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 +395 -0
- package/dist/index.d.ts +134 -32
- package/dist/index.js +2204 -2091
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -2971,6 +2971,12 @@ export declare const DEFAULT_MAX_IDLE_INTERVAL_MS = 30000;
|
|
|
2971
2971
|
* small enough to stop a pathological body being buffered into memory. */
|
|
2972
2972
|
export declare const DEFAULT_MAX_RPC_BODY_BYTES: number;
|
|
2973
2973
|
|
|
2974
|
+
/** The watchdog bound a schedule gets when it declares none. Exported
|
|
2975
|
+
* because the overlap guard dates an un-beating run against it — see
|
|
2976
|
+
* `peerRunIsAlive`; a second copy of the number there would be a second
|
|
2977
|
+
* definition nothing keeps in step. */
|
|
2978
|
+
export declare const DEFAULT_MAX_RUNTIME_MS: number;
|
|
2979
|
+
|
|
2974
2980
|
/** See {@link DrainDeps.claimLeaseMs}. */
|
|
2975
2981
|
export declare const DEFAULT_OUTBOX_CLAIM_LEASE_MS: number;
|
|
2976
2982
|
|
|
@@ -3002,6 +3008,25 @@ export declare const DEFAULT_RESUME_WINDOW_MS = 60000;
|
|
|
3002
3008
|
*/
|
|
3003
3009
|
export declare const DEFAULT_ROW_FILTER_RETRY: Schedule.Schedule<unknown, unknown>;
|
|
3004
3010
|
|
|
3011
|
+
/**
|
|
3012
|
+
* How often a run in flight bumps `heartbeatAt`.
|
|
3013
|
+
*
|
|
3014
|
+
* The default lives HERE, next to the only code that reads it, and
|
|
3015
|
+
* `cli/src/schedulingConfig.ts` imports it as the default of the
|
|
3016
|
+
* `scheduling.scheduleHeartbeatMs` field. One definition — a second one in the
|
|
3017
|
+
* resolver is how a config default and a library default come to disagree
|
|
3018
|
+
* about a number neither of them prints.
|
|
3019
|
+
*
|
|
3020
|
+
* 30 s rather than the couple of seconds `_voltro_replace_in_progress` beats
|
|
3021
|
+
* at, because the two are bounding different things. A bulk load's beat decides
|
|
3022
|
+
* whether a boot may DROP staging tables, so its cost is worth paying to keep
|
|
3023
|
+
* the window tight. This one decides how long a dead run holds its schedule
|
|
3024
|
+
* shut, measured against a cron period — a minute and a half of latency on a
|
|
3025
|
+
* half-hourly job is one slot, and a run shorter than one interval writes no
|
|
3026
|
+
* beat at all and costs nothing.
|
|
3027
|
+
*/
|
|
3028
|
+
export declare const DEFAULT_SCHEDULE_HEARTBEAT_MS = 30000;
|
|
3029
|
+
|
|
3005
3030
|
/** Defaults, overridable via `app.config.ts` `reactive.socket.*` (+ env) —
|
|
3006
3031
|
* resolved by the boot paths' tunables resolver. */
|
|
3007
3032
|
export declare const DEFAULT_SOCKET_MAX_BUFFERED_BYTES = 1048576;
|
|
@@ -4616,6 +4641,28 @@ export declare interface FleetMergeResult<T> {
|
|
|
4616
4641
|
readonly replicaId: string;
|
|
4617
4642
|
readonly ageMs: number;
|
|
4618
4643
|
}>;
|
|
4644
|
+
/**
|
|
4645
|
+
* Rows left behind by replicas the roster no longer lists.
|
|
4646
|
+
*
|
|
4647
|
+
* Reported rather than deleted, and separately from `stale`, because the two
|
|
4648
|
+
* are different facts with different next steps: a stale row belongs to a
|
|
4649
|
+
* process that is RUNNING and has stopped refreshing — a fault — while a
|
|
4650
|
+
* departed one belongs to a process that is gone, which is what a scale-down
|
|
4651
|
+
* looks like and needs no action.
|
|
4652
|
+
*
|
|
4653
|
+
* Conflating them cost both readings. Every corpse landed in `stale`, so
|
|
4654
|
+
* `complete` could never be true again after the first scale-down; and they
|
|
4655
|
+
* were counted as responders, so a row from the release before last reported
|
|
4656
|
+
* a version SPLIT across a fleet that had none.
|
|
4657
|
+
*
|
|
4658
|
+
* Empty when no membership is wired: with no roster there is no evidence of
|
|
4659
|
+
* departure, and assuming it would empty a single-process answer.
|
|
4660
|
+
*/
|
|
4661
|
+
readonly departed: ReadonlyArray<{
|
|
4662
|
+
readonly replicaId: string;
|
|
4663
|
+
readonly ageMs: number;
|
|
4664
|
+
readonly version: string | undefined;
|
|
4665
|
+
}>;
|
|
4619
4666
|
/** Framework versions among the responders, counted. Present only when they
|
|
4620
4667
|
* DIFFER — a single-version fleet needs no such note, and a note nobody
|
|
4621
4668
|
* needs is one everybody learns to skip. */
|
|
@@ -6456,6 +6503,15 @@ export declare const noteRead: (descriptor: QueryDescriptor) => void;
|
|
|
6456
6503
|
*/
|
|
6457
6504
|
export declare const noteResumeVerdict: (rawLabel: string, verdict: true | ResumeExclusion) => void;
|
|
6458
6505
|
|
|
6506
|
+
/**
|
|
6507
|
+
* Note that a row filter was resolved on `arm`, and say so the FIRST time.
|
|
6508
|
+
*
|
|
6509
|
+
* Exported so the arms that are not in this module (the serve pipeline) report
|
|
6510
|
+
* through the same counter — four arms reporting four ways is how a reader comes
|
|
6511
|
+
* to believe three of them are covered.
|
|
6512
|
+
*/
|
|
6513
|
+
export declare const noteRowFilterResolved: (arm: string, tables: number | undefined) => void;
|
|
6514
|
+
|
|
6459
6515
|
export declare interface Notification {
|
|
6460
6516
|
readonly subscriberId: string;
|
|
6461
6517
|
readonly fingerprint: string;
|
|
@@ -6793,6 +6849,42 @@ export declare const payloadPropertyNames: (schema: Schema.Schema.Any) => {
|
|
|
6793
6849
|
readonly optional: ReadonlyArray<string>;
|
|
6794
6850
|
};
|
|
6795
6851
|
|
|
6852
|
+
/**
|
|
6853
|
+
* Is a `running` row on ANOTHER replica a live run, or a corpse?
|
|
6854
|
+
*
|
|
6855
|
+
* Pure, and separated from the query for the same reason
|
|
6856
|
+
* `stagingLeftovers` is: the rule is four lines and each of them has a way to
|
|
6857
|
+
* be quietly wrong in a direction nobody sees. Wrong towards "alive" and a
|
|
6858
|
+
* schedule stops firing with `overlap skip` in the log; wrong towards "dead"
|
|
6859
|
+
* and two replicas run the same occurrence.
|
|
6860
|
+
*
|
|
6861
|
+
* ── The two cases, and why there are two ───────────────────────────────────
|
|
6862
|
+
*
|
|
6863
|
+
* **A beat is present.** Then the answer is the beat and nothing else: a live
|
|
6864
|
+
* handler bumps it every `heartbeatMs`, so silence longer than `STALE_BEATS`
|
|
6865
|
+
* of them is a process that is not coming back.
|
|
6866
|
+
*
|
|
6867
|
+
* **No beat.** A row written before this column existed — i.e. by a process
|
|
6868
|
+
* still running the previous version during a rolling deploy. `firedAt` is all
|
|
6869
|
+
* there is, and the honest bound on it is the schedule's OWN `maxRuntimeMs`:
|
|
6870
|
+
* the watchdog records a run that exceeds it as `failed`, so a row older than
|
|
6871
|
+
* that plus the stale window cannot belong to a process that is still going to
|
|
6872
|
+
* write a terminal status.
|
|
6873
|
+
*
|
|
6874
|
+
* **Neither is a usable instant** → NOT alive. Fail-open, deliberately, and it
|
|
6875
|
+
* is the pre-existing reading (`firedAt != null &&`). A row nobody can date
|
|
6876
|
+
* must not hold a schedule shut forever, and the counterweight is the claim
|
|
6877
|
+
* coordinator, which is what actually guarantees once-only for a clock firing —
|
|
6878
|
+
* this guard is the second line, not the first.
|
|
6879
|
+
*/
|
|
6880
|
+
export declare const peerRunIsAlive: (row: {
|
|
6881
|
+
readonly firedAt: Date | string | null;
|
|
6882
|
+
readonly heartbeatAt?: Date | string | null;
|
|
6883
|
+
}, now: number, bounds: {
|
|
6884
|
+
readonly heartbeatMs: number;
|
|
6885
|
+
readonly maxRuntimeMs: number;
|
|
6886
|
+
}) => boolean;
|
|
6887
|
+
|
|
6796
6888
|
/**
|
|
6797
6889
|
* The calling subject's approval work: intents they may DECIDE, plus intents
|
|
6798
6890
|
* they REQUESTED that are still live.
|
|
@@ -7939,12 +8031,21 @@ export declare const resetEventMetricTagCacheForTests: () => void;
|
|
|
7939
8031
|
/** Drop everything recorded. For tests; not called by the runtime. */
|
|
7940
8032
|
export declare const resetObservedGraph: () => void;
|
|
7941
8033
|
|
|
8034
|
+
/** Test seam — a process only ever warns once, which would make the second
|
|
8035
|
+
* assertion in a suite vacuous. */
|
|
8036
|
+
export declare const resetReplicaObservationWarnings: () => void;
|
|
8037
|
+
|
|
7942
8038
|
/** Clear the census. For tests; a running app has no reason to forget. */
|
|
7943
8039
|
export declare const resetResumeCensus: () => void;
|
|
7944
8040
|
|
|
7945
8041
|
/** Test seam. */
|
|
7946
8042
|
export declare const resetResumeRingsForTest: () => void;
|
|
7947
8043
|
|
|
8044
|
+
/** Test helper: forget which arms have reported. Not for production — the set
|
|
8045
|
+
* is a record of what this PROCESS has proven, and forgetting it would make
|
|
8046
|
+
* the line repeat and the list lie. */
|
|
8047
|
+
export declare const resetRowFilterResolvedArms: () => void;
|
|
8048
|
+
|
|
7948
8049
|
/** Reset to the env default (tests). */
|
|
7949
8050
|
export declare const resetSecretsBackend: () => void;
|
|
7950
8051
|
|
|
@@ -8089,6 +8190,25 @@ export declare interface ResolvedWorkflowCallerContext extends WorkflowCallerCon
|
|
|
8089
8190
|
readonly subject: unknown;
|
|
8090
8191
|
/** Never absent — the caller's trace id, or `'workflow-bootstrap'`. */
|
|
8091
8192
|
readonly traceId: string;
|
|
8193
|
+
/**
|
|
8194
|
+
* Never absent — the row-filter scope this run's steps read through,
|
|
8195
|
+
* resolved for the subject above at EXECUTION time.
|
|
8196
|
+
*
|
|
8197
|
+
* It is here for the same reason `resolveAuthority` exists, and the wording
|
|
8198
|
+
* carries over: authority re-read from the app's live source is what a
|
|
8199
|
+
* three-day-old run may DO, and this is what it may SEE. Restoring either
|
|
8200
|
+
* from the start-context row would be a frozen fact made durable.
|
|
8201
|
+
*
|
|
8202
|
+
* It is also what makes such a run possible at all. The store refuses a
|
|
8203
|
+
* scope-less context whose subject is not the system, so a workflow started
|
|
8204
|
+
* BY A USER — the common case — threw before its executor ran in any app that
|
|
8205
|
+
* calls `setRowFilter`. A bootstrap run passed, because its subject IS the
|
|
8206
|
+
* system, which is why the gap was invisible from the framework's own tests.
|
|
8207
|
+
*
|
|
8208
|
+
* `NO_ROW_FILTER` when the app registered none: the resolution short-circuits
|
|
8209
|
+
* without touching a store, so a filter-less app pays nothing.
|
|
8210
|
+
*/
|
|
8211
|
+
readonly rowFilter: RowFilterScope;
|
|
8092
8212
|
}
|
|
8093
8213
|
|
|
8094
8214
|
export declare const resolveKeepAlive: (config: KeepAliveConfig | null | undefined) => KeepAliveTimeouts;
|
|
@@ -8131,31 +8251,6 @@ export declare const resolveRequestIsHttps: (input: {
|
|
|
8131
8251
|
* current table (or at least every row in the rescan groups). */
|
|
8132
8252
|
export declare const resolveRescan: (shape: AggregateShape, state: IvmState, rescanGroups: ReadonlyArray<string>, baseRows: ReadonlyArray<Row_3>) => IvmState;
|
|
8133
8253
|
|
|
8134
|
-
/**
|
|
8135
|
-
* Resolve the request-scoped filter for `subject`.
|
|
8136
|
-
*
|
|
8137
|
-
* Three stages, in order, and the order is the design:
|
|
8138
|
-
*
|
|
8139
|
-
* 1. **Bypass** — no registered filter, or a `system` subject: `NO_ROW_FILTER`,
|
|
8140
|
-
* zero cost, no `load` call.
|
|
8141
|
-
* 2. **Retry** — `load` runs under the filter's `retry` schedule
|
|
8142
|
-
* (`DEFAULT_ROW_FILTER_RETRY` unless overridden). A transient failure must
|
|
8143
|
-
* never reach stage 3, because at stage 3 it is indistinguishable from an
|
|
8144
|
-
* authorization answer.
|
|
8145
|
-
* 3. **Refuse** — a failure that survived retry is reported through `onError`
|
|
8146
|
-
* and then, per `onLoadError`, either FAILS with `RowFilterUnavailable`
|
|
8147
|
-
* (default) or degrades to `DENY_ALL`.
|
|
8148
|
-
*
|
|
8149
|
-
* Fails CLOSED, never open: a `load` failure never yields an unfiltered read.
|
|
8150
|
-
* A row filter that degrades to "no filter" under load failure is worse than
|
|
8151
|
-
* none, because the system keeps serving and nothing looks wrong.
|
|
8152
|
-
*
|
|
8153
|
-
* And refusal is an ERROR by default, not an empty result. An empty result for
|
|
8154
|
-
* an infrastructure failure is the most misleading outcome available: it is
|
|
8155
|
-
* byte-identical to legitimate emptiness, so the user reads "you have no
|
|
8156
|
-
* tickets" and the operator reads a healthy 200. Every constrained page IS
|
|
8157
|
-
* broken when this happens; the honest thing is to say so.
|
|
8158
|
-
*/
|
|
8159
8254
|
export declare const resolveRowFilterScope: (subject: Subject, onError?: (error: unknown) => void) => Effect.Effect<RowFilterScope, RowFilterUnavailable>;
|
|
8160
8255
|
|
|
8161
8256
|
/**
|
|
@@ -8614,6 +8709,10 @@ export declare const rowFilterMayNarrow: (tables: ReadonlyArray<string>) => bool
|
|
|
8614
8709
|
*/
|
|
8615
8710
|
export declare const rowFilterRegistered: () => boolean;
|
|
8616
8711
|
|
|
8712
|
+
/** Which arms have been proven to resolve the filter in this process. Read by
|
|
8713
|
+
* the inspect surface; a test reads it to assert an arm was exercised. */
|
|
8714
|
+
export declare const rowFilterResolvedArms: () => ReadonlyArray<string>;
|
|
8715
|
+
|
|
8617
8716
|
/** What a scoped store needs: a sync `table → Predicate?` lookup. */
|
|
8618
8717
|
export declare type RowFilterScope = (table: string) => Predicate | undefined;
|
|
8619
8718
|
|
|
@@ -9194,6 +9293,16 @@ export declare interface SchedulerDeps {
|
|
|
9194
9293
|
/** Stable id of this process/replica (pod name, pid, …) recorded on
|
|
9195
9294
|
* every run row for debugging "which instance fired this." */
|
|
9196
9295
|
readonly replicaId: string;
|
|
9296
|
+
/**
|
|
9297
|
+
* How often a run in flight bumps `heartbeatAt` — the signal the
|
|
9298
|
+
* cross-instance overlap guard reads to tell a live run from a corpse.
|
|
9299
|
+
*
|
|
9300
|
+
* Omitted → {@link DEFAULT_SCHEDULE_HEARTBEAT_MS}. Both boot paths pass the
|
|
9301
|
+
* resolved `scheduling.scheduleHeartbeatMs`, so a deployment changes it in
|
|
9302
|
+
* one place; a non-positive value falls back to the default rather than
|
|
9303
|
+
* turning the beat into a spin.
|
|
9304
|
+
*/
|
|
9305
|
+
readonly runHeartbeatMs?: number;
|
|
9197
9306
|
readonly log: SchedulerLogger;
|
|
9198
9307
|
/** Notify on every run-row insert/update so the SSE bridge can
|
|
9199
9308
|
* mirror schedule runs to the cloud dashboard in real time. */
|
|
@@ -11720,13 +11829,6 @@ export declare const wrapStoreWithBootCodec: (underlying: DataStore, dialectId:
|
|
|
11720
11829
|
|
|
11721
11830
|
export declare const wrapStoreWithMixinBehaviour: (rawUnderlying: DataStore, ctx: StoreMiddlewareContext) => FluentStore;
|
|
11722
11831
|
|
|
11723
|
-
/**
|
|
11724
|
-
* Write (upsert) this replica's counters for one kind.
|
|
11725
|
-
*
|
|
11726
|
-
* Best-effort throughout: a diagnostic that can fail a request, or a boot, is a
|
|
11727
|
-
* new way to be down. A failure logs at debug and leaves the previous row —
|
|
11728
|
-
* which then reads as stale, which is the truth.
|
|
11729
|
-
*/
|
|
11730
11832
|
export declare const writeReplicaObservation: (store: DataStore, kind: ReplicaObservationKind, payload: unknown) => Promise<void>;
|
|
11731
11833
|
|
|
11732
11834
|
export { }
|