@voltro/runtime 0.71.0 → 0.72.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 +435 -0
- package/THIRD-PARTY-NOTICES.md +29 -1
- package/dist/index.d.ts +332 -2
- package/dist/index.js +3066 -2529
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ import { KvStoreShape } from '@voltro/kv';
|
|
|
57
57
|
import { Layer } from 'effect';
|
|
58
58
|
import { listRetentionConflicts } from '@voltro/database';
|
|
59
59
|
import { listRetentions } from '@voltro/database';
|
|
60
|
+
import { Membership } from '@voltro/protocol';
|
|
60
61
|
import { Metric } from 'effect';
|
|
61
62
|
import { MetricBoundaries } from 'effect';
|
|
62
63
|
import { MetricReader } from '@opentelemetry/sdk-metrics';
|
|
@@ -107,8 +108,11 @@ import { TableLike } from '@voltro/database';
|
|
|
107
108
|
import { TableName } from '@voltro/protocol';
|
|
108
109
|
import { TableValidationFailed } from '@voltro/protocol';
|
|
109
110
|
import { TargetRelation } from '@voltro/protocol';
|
|
111
|
+
import { TENANT_SELECTIONS_TABLE } from '@voltro/database';
|
|
110
112
|
import { TenantRowNotFound } from '@voltro/protocol';
|
|
111
113
|
import { TenantScopeViolation } from '@voltro/protocol';
|
|
114
|
+
import { tenantSelectionId } from '@voltro/database';
|
|
115
|
+
import { TenantSelectionStore } from '@voltro/protocol';
|
|
112
116
|
import { Tracer } from 'effect';
|
|
113
117
|
import { Unauthenticated } from '@voltro/protocol';
|
|
114
118
|
import { UpsertOptions } from '@voltro/database';
|
|
@@ -2134,6 +2138,11 @@ export { clearRetentions }
|
|
|
2134
2138
|
/** Clear the process-wide handle (test teardown). */
|
|
2135
2139
|
export declare const clearSystemStoreHandle: () => void;
|
|
2136
2140
|
|
|
2141
|
+
/** Forget the subject's selection: the next request resolves in the tenant
|
|
2142
|
+
* its credential names. A no-op for a subject with none, and for the types
|
|
2143
|
+
* that cannot hold one. */
|
|
2144
|
+
export declare const clearTenantSelection: (store: DataStore, subject: Subject) => Promise<void>;
|
|
2145
|
+
|
|
2137
2146
|
export declare interface ClientAddressInput {
|
|
2138
2147
|
/** `socket.remoteAddress` — the only unforgeable value in the request. */
|
|
2139
2148
|
readonly socketAddress: string | undefined;
|
|
@@ -3054,6 +3063,8 @@ export declare interface DataStoreApiKeyStoreOptions {
|
|
|
3054
3063
|
readonly ensureActor?: ((actor: ApiKeyActor, store: DataStore) => Promise<void>) | undefined;
|
|
3055
3064
|
}
|
|
3056
3065
|
|
|
3066
|
+
export declare const dataStoreDeviceStore: (store: DataStore) => DeviceStore;
|
|
3067
|
+
|
|
3057
3068
|
export declare const dataStoreIdempotencyStore: (store: DataStore) => IdempotencyStore;
|
|
3058
3069
|
|
|
3059
3070
|
/** Build a durable `KvStoreShape` over a raw `DataStore`. */
|
|
@@ -3474,6 +3485,128 @@ export declare const detachForResume: (identity: ResumeIdentity, handle: {
|
|
|
3474
3485
|
readonly unsubscribe: () => void;
|
|
3475
3486
|
}, tunables?: ResumeTunables, now?: () => number) => void;
|
|
3476
3487
|
|
|
3488
|
+
export declare interface DeviceActor {
|
|
3489
|
+
readonly id: string;
|
|
3490
|
+
readonly displayName: string;
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
/** The device routes. Mounted under `basePath` (default `/v1/devices`) when
|
|
3494
|
+
* `devices` is on. `pair`, list and `revoke` need `admin:full` or
|
|
3495
|
+
* `devices:manage`; `exchange` and `rotate` are the device's own calls and
|
|
3496
|
+
* carry no session — the one-time code and the refresh token ARE the
|
|
3497
|
+
* credential, and a wrong one is `401` with one reason for every cause. */
|
|
3498
|
+
export declare const deviceManagementRoutes: (service: DeviceServiceShape, basePath?: string) => ReadonlyArray<RestRouteDescriptor<any, any>>;
|
|
3499
|
+
|
|
3500
|
+
export declare interface DeviceRow {
|
|
3501
|
+
readonly id: string;
|
|
3502
|
+
readonly tenantId: string;
|
|
3503
|
+
readonly name: string;
|
|
3504
|
+
readonly scopes: ReadonlyArray<string> | null;
|
|
3505
|
+
readonly pairingHash: string | null;
|
|
3506
|
+
readonly pairingExpiresAt: number | null;
|
|
3507
|
+
readonly accessHash: string | null;
|
|
3508
|
+
readonly accessExpiresAt: number | null;
|
|
3509
|
+
readonly refreshHash: string | null;
|
|
3510
|
+
readonly refreshExpiresAt: number | null;
|
|
3511
|
+
/** The refresh hash rotated OUT by the last rotation — what a replay
|
|
3512
|
+
* presents. One generation back is what a stolen-then-rotated token looks
|
|
3513
|
+
* like; older replays fail as unknown, which is refusal enough. */
|
|
3514
|
+
readonly previousRefreshHash: string | null;
|
|
3515
|
+
readonly generation: number;
|
|
3516
|
+
readonly pairedAt: number | null;
|
|
3517
|
+
readonly lastSeenAt: number | null;
|
|
3518
|
+
readonly revokedAt: number | null;
|
|
3519
|
+
readonly revokedReason: string | null;
|
|
3520
|
+
readonly createdBy: string | null;
|
|
3521
|
+
readonly createdAt: number;
|
|
3522
|
+
readonly metadata?: Readonly<Record<string, unknown>> | null;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
export declare const DEVICES_TABLE = "_voltro_devices";
|
|
3526
|
+
|
|
3527
|
+
export declare interface DeviceServiceOptions {
|
|
3528
|
+
readonly prefix?: string;
|
|
3529
|
+
/** Access token lifetime. Default 15 minutes — long enough that a device
|
|
3530
|
+
* polling every minute rotates rarely, short enough that a leaked token is
|
|
3531
|
+
* a bounded problem. */
|
|
3532
|
+
readonly accessTtlSeconds?: number;
|
|
3533
|
+
/** Refresh token lifetime — how long a device may stay silent and still
|
|
3534
|
+
* come back. Default 30 days. */
|
|
3535
|
+
readonly refreshTtlSeconds?: number;
|
|
3536
|
+
/** How long an admin has between pairing and the device's exchange. Default
|
|
3537
|
+
* 10 minutes. */
|
|
3538
|
+
readonly pairingTtlSeconds?: number;
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3541
|
+
export declare interface DeviceServiceShape {
|
|
3542
|
+
/** Admin-side: create the device and its one-time pairing code. */
|
|
3543
|
+
readonly pair: (input: PairInput) => Promise<PairedDevice>;
|
|
3544
|
+
/** Device-side, once: the pairing code for the first token pair. Null when
|
|
3545
|
+
* the code is unknown, expired, already exchanged, or the device revoked —
|
|
3546
|
+
* one answer, so the route cannot be used to tell those apart. */
|
|
3547
|
+
readonly exchange: (pairingCode: string, now?: number) => Promise<DeviceTokens | null>;
|
|
3548
|
+
/** Device-side, repeatedly: the current refresh token for a new pair
|
|
3549
|
+
* (`generation + 1`). A refresh token that was already rotated out is a
|
|
3550
|
+
* REPLAY: the device is revoked with reason `refresh-replay` and null is
|
|
3551
|
+
* returned. Null also for unknown / expired / revoked. */
|
|
3552
|
+
readonly rotate: (refreshToken: string, now?: number) => Promise<DeviceTokens | null>;
|
|
3553
|
+
/** Hash lookup used by the auth strategy: the device's identity while its
|
|
3554
|
+
* access token is live. No write — see the module note. */
|
|
3555
|
+
readonly resolveAccess: (accessHash: string, now?: number) => Promise<ResolvedDevice | null>;
|
|
3556
|
+
/** Revoke (irreversible). `tenantId` is the CALLER's tenant and required for
|
|
3557
|
+
* the same reason as the api-key service's: ids leak, and an admin of one
|
|
3558
|
+
* tenant must not revoke another's device by id. */
|
|
3559
|
+
readonly revoke: (id: string, tenantId: string, now?: number) => Promise<boolean>;
|
|
3560
|
+
readonly list: (tenantId: string) => Promise<ReadonlyArray<PublicDevice>>;
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
export declare interface DeviceStore {
|
|
3564
|
+
readonly insert: (row: DeviceRow) => Promise<void>;
|
|
3565
|
+
readonly findById: (id: string) => Promise<DeviceRow | null>;
|
|
3566
|
+
readonly findByPairingHash: (hash: string) => Promise<DeviceRow | null>;
|
|
3567
|
+
readonly findByAccessHash: (hash: string) => Promise<DeviceRow | null>;
|
|
3568
|
+
readonly findByRefreshHash: (hash: string) => Promise<DeviceRow | null>;
|
|
3569
|
+
readonly findByPreviousRefreshHash: (hash: string) => Promise<DeviceRow | null>;
|
|
3570
|
+
readonly listByTenant: (tenantId: string) => Promise<ReadonlyArray<DeviceRow>>;
|
|
3571
|
+
readonly patch: (id: string, fields: Partial<DeviceRow>) => Promise<void>;
|
|
3572
|
+
/**
|
|
3573
|
+
* A FENCED patch: applies `fields` only while `column` still equals
|
|
3574
|
+
* `expected`, and says whether it did. Exchange and rotation are claims on
|
|
3575
|
+
* a one-time secret — two exchanges of one pairing code, two rotations of
|
|
3576
|
+
* one refresh token — and the claim has to be decided by the row, not by a
|
|
3577
|
+
* read that both callers made a moment ago.
|
|
3578
|
+
*/
|
|
3579
|
+
readonly claim: (id: string, column: 'pairingHash' | 'refreshHash', expected: string, fields: Partial<DeviceRow>) => Promise<boolean>;
|
|
3580
|
+
/** Plant the device's `actors` row (kind `serviceAccount`) — the audit
|
|
3581
|
+
* subject its writes point at. Required, like the api-key store's: an
|
|
3582
|
+
* omitted actor row is the foreign-key failure on the first audited
|
|
3583
|
+
* insert. Idempotent. */
|
|
3584
|
+
readonly ensureActor: (actor: DeviceActor) => Promise<void>;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
/** The three token shapes, derived from ONE configured prefix so a bearer
|
|
3588
|
+
* prefix collision check (`assertNoBearerPrefixCollision`) sees one claim:
|
|
3589
|
+
* `dev_` → access `dev_…`, refresh `devr_…`, pairing `devp_…`. Refresh and
|
|
3590
|
+
* pairing tokens are never presented as bearers; their prefixes exist so a
|
|
3591
|
+
* token pasted into the wrong field is refused by shape, not by luck. */
|
|
3592
|
+
export declare interface DeviceTokenPrefixes {
|
|
3593
|
+
readonly access: string;
|
|
3594
|
+
readonly refresh: string;
|
|
3595
|
+
readonly pairing: string;
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
export declare const deviceTokenPrefixes: (prefix?: string) => DeviceTokenPrefixes;
|
|
3599
|
+
|
|
3600
|
+
/** What an exchange or a rotation hands the device. Shown once. */
|
|
3601
|
+
export declare interface DeviceTokens {
|
|
3602
|
+
readonly deviceId: string;
|
|
3603
|
+
readonly accessToken: string;
|
|
3604
|
+
readonly accessExpiresAt: number;
|
|
3605
|
+
readonly refreshToken: string;
|
|
3606
|
+
readonly refreshExpiresAt: number;
|
|
3607
|
+
readonly generation: number;
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3477
3610
|
export { DialectReplicationAdapter }
|
|
3478
3611
|
|
|
3479
3612
|
/** Field-level diff for one change. Insert → every field `undefined→value`;
|
|
@@ -5213,6 +5346,15 @@ export declare const frameworkApiKeyStrategy: (service: ApiKeyServiceShape, opts
|
|
|
5213
5346
|
prefix?: string;
|
|
5214
5347
|
}) => AuthStrategy;
|
|
5215
5348
|
|
|
5349
|
+
/** The framework device auth strategy. A device is a machine caller WITH a
|
|
5350
|
+
* tenant — a `serviceAccount` subject whose id is the device id, so audit
|
|
5351
|
+
* columns point at the device's own `actors` row. `credentialExpiresAt` is
|
|
5352
|
+
* the access token's expiry: a standing subscription opened with it ends
|
|
5353
|
+
* when the token does, and the device's next rotation re-opens it. */
|
|
5354
|
+
export declare const frameworkDeviceStrategy: (service: DeviceServiceShape, opts?: {
|
|
5355
|
+
prefix?: string;
|
|
5356
|
+
}) => AuthStrategy;
|
|
5357
|
+
|
|
5216
5358
|
/** Define a gauge (set with `setMetric`). */
|
|
5217
5359
|
export declare const gauge: (name: string, description?: string) => Metric.Metric.Gauge<number>;
|
|
5218
5360
|
|
|
@@ -6156,6 +6298,8 @@ export declare const makeDataLoader: (deps: LoaderDeps) => DataLoader;
|
|
|
6156
6298
|
*/
|
|
6157
6299
|
export declare const makeDefaultRefilter: (subject: Subject, onError?: (error: unknown) => void) => (() => Promise<RowFilterScope>) | undefined;
|
|
6158
6300
|
|
|
6301
|
+
export declare const makeDeviceService: (store: DeviceStore, opts?: DeviceServiceOptions) => DeviceServiceShape;
|
|
6302
|
+
|
|
6159
6303
|
/** `__voltro.connections.disconnect` — forget the caller's credential. */
|
|
6160
6304
|
export declare const makeDisconnectConnectionExecutor: (deps: ConnectionBuiltinDeps) => (input: {
|
|
6161
6305
|
readonly connectionId: string;
|
|
@@ -6573,6 +6717,10 @@ export declare const memoryApiKeyStore: () => ApiKeyStore & {
|
|
|
6573
6717
|
readonly actors: ReadonlyMap<string, MemoryActorRow>;
|
|
6574
6718
|
};
|
|
6575
6719
|
|
|
6720
|
+
export declare const memoryDeviceStore: () => DeviceStore & {
|
|
6721
|
+
readonly actors: ReadonlyMap<string, DeviceActor>;
|
|
6722
|
+
};
|
|
6723
|
+
|
|
6576
6724
|
/**
|
|
6577
6725
|
* Adapter for in-memory testing. The "position" is a monotonically-
|
|
6578
6726
|
* increasing integer tick the test controls. Primary writes bump the
|
|
@@ -6991,10 +7139,10 @@ export declare interface OAuth2ConnectionDefinition extends ConnectionDefinition
|
|
|
6991
7139
|
readonly kind: 'oauth2';
|
|
6992
7140
|
readonly authorizeUrl: string;
|
|
6993
7141
|
readonly tokenUrl: string;
|
|
6994
|
-
readonly clientId:
|
|
7142
|
+
readonly clientId: OAuthClientCredential;
|
|
6995
7143
|
/** Runtime secret. Never logged, never sent to the browser, never bundled —
|
|
6996
7144
|
* `*.connection.ts` is server-only and is NOT part of the rpcGroup codegen. */
|
|
6997
|
-
readonly clientSecret:
|
|
7145
|
+
readonly clientSecret: OAuthClientCredential;
|
|
6998
7146
|
readonly scopes?: ReadonlyArray<string>;
|
|
6999
7147
|
/** Exact redirect URI registered with the provider. Defaults to
|
|
7000
7148
|
* `<publicUrl>/_voltro/connections/<id>/callback`. */
|
|
@@ -7013,6 +7161,20 @@ export declare interface OAuth2ConnectionDefinition extends ConnectionDefinition
|
|
|
7013
7161
|
readonly identify?: (tokens: ConnectionTokens) => Promise<ConnectionAccount>;
|
|
7014
7162
|
}
|
|
7015
7163
|
|
|
7164
|
+
/**
|
|
7165
|
+
* A credential as the file states it: the string, or a thunk that produces it.
|
|
7166
|
+
*
|
|
7167
|
+
* The thunk exists because of WHEN a `*.connection.ts` is evaluated. Discovery
|
|
7168
|
+
* imports it before the env gate has run — `voltro doctor` runs no gate at all —
|
|
7169
|
+
* and `serverEnv.X` read at module top level throws there by design. A thunk
|
|
7170
|
+
* defers the read to the moment the connection is used (an authorize URL, a
|
|
7171
|
+
* token exchange), which is always after the gate. `oauthCredentialValue` is the
|
|
7172
|
+
* one reader.
|
|
7173
|
+
*/
|
|
7174
|
+
export declare type OAuthClientCredential = string | (() => string);
|
|
7175
|
+
|
|
7176
|
+
export declare const oauthCredentialValue: (credential: OAuthClientCredential) => string;
|
|
7177
|
+
|
|
7016
7178
|
/** One recorded `(procedure → table, op)` edge. */
|
|
7017
7179
|
export declare interface ObservedEdge {
|
|
7018
7180
|
readonly tag: string;
|
|
@@ -7336,6 +7498,25 @@ declare interface P2COptions {
|
|
|
7336
7498
|
readonly random?: () => number;
|
|
7337
7499
|
}
|
|
7338
7500
|
|
|
7501
|
+
export declare interface PairedDevice {
|
|
7502
|
+
readonly id: string;
|
|
7503
|
+
readonly name: string;
|
|
7504
|
+
readonly tenantId: string;
|
|
7505
|
+
readonly scopes: ReadonlyArray<string>;
|
|
7506
|
+
/** Shown ONCE. Exchanged for the first token pair, then gone. */
|
|
7507
|
+
readonly pairingCode: string;
|
|
7508
|
+
readonly pairingExpiresAt: number;
|
|
7509
|
+
}
|
|
7510
|
+
|
|
7511
|
+
export declare interface PairInput {
|
|
7512
|
+
readonly tenantId: string;
|
|
7513
|
+
readonly name: string;
|
|
7514
|
+
readonly scopes?: ReadonlyArray<string>;
|
|
7515
|
+
/** WHO PAIRED IT. Provenance. */
|
|
7516
|
+
readonly createdBy?: string | null;
|
|
7517
|
+
readonly metadata?: Readonly<Record<string, unknown>> | null;
|
|
7518
|
+
}
|
|
7519
|
+
|
|
7339
7520
|
/**
|
|
7340
7521
|
* Parse an interval string (`'30m'`, `'4h'`, `'7d'`) to ms, or `null`.
|
|
7341
7522
|
* A local copy for the same reason `finops.ts` keeps one — this module must not
|
|
@@ -7602,6 +7783,22 @@ export declare interface PublicApiKey {
|
|
|
7602
7783
|
readonly metadata?: Readonly<Record<string, unknown>> | null;
|
|
7603
7784
|
}
|
|
7604
7785
|
|
|
7786
|
+
export declare interface PublicDevice {
|
|
7787
|
+
readonly id: string;
|
|
7788
|
+
readonly name: string;
|
|
7789
|
+
readonly tenantId: string;
|
|
7790
|
+
readonly scopes: ReadonlyArray<string>;
|
|
7791
|
+
readonly generation: number;
|
|
7792
|
+
readonly pairedAt: number | null;
|
|
7793
|
+
readonly lastSeenAt: number | null;
|
|
7794
|
+
readonly accessExpiresAt: number | null;
|
|
7795
|
+
readonly revokedAt: number | null;
|
|
7796
|
+
readonly revokedReason: string | null;
|
|
7797
|
+
readonly createdAt: number;
|
|
7798
|
+
readonly createdBy: string | null;
|
|
7799
|
+
readonly metadata?: Readonly<Record<string, unknown>> | null;
|
|
7800
|
+
}
|
|
7801
|
+
|
|
7605
7802
|
/**
|
|
7606
7803
|
* Validate, size-check and publish one event.
|
|
7607
7804
|
*
|
|
@@ -8831,6 +9028,17 @@ export declare interface ResolvedConnection {
|
|
|
8831
9028
|
readonly accountLabel: string | null;
|
|
8832
9029
|
}
|
|
8833
9030
|
|
|
9031
|
+
/** What the auth strategy learns from a presented access token. */
|
|
9032
|
+
export declare interface ResolvedDevice {
|
|
9033
|
+
readonly id: string;
|
|
9034
|
+
readonly tenantId: string;
|
|
9035
|
+
readonly name: string;
|
|
9036
|
+
readonly scopes: ReadonlyArray<string>;
|
|
9037
|
+
readonly generation: number;
|
|
9038
|
+
readonly accessExpiresAt: number;
|
|
9039
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
9040
|
+
}
|
|
9041
|
+
|
|
8834
9042
|
/**
|
|
8835
9043
|
* Walk a query descriptor's eager-load tree and return the FULL set
|
|
8836
9044
|
* of tables whose changes could affect the resolved snapshot.
|
|
@@ -10547,6 +10755,20 @@ export declare class SelectBuilder {
|
|
|
10547
10755
|
get descriptor(): QueryDescriptor;
|
|
10548
10756
|
}
|
|
10549
10757
|
|
|
10758
|
+
/**
|
|
10759
|
+
* Select `tenantId` as the subject's active tenant — verified against
|
|
10760
|
+
* `memberships` through the one rule (`selectSubjectTenant`), then stored.
|
|
10761
|
+
* Returns the subject as it will resolve on the next request. Throws
|
|
10762
|
+
* `TenantSelectionRefused` when the target is not among the memberships or
|
|
10763
|
+
* the subject is of a type that has no tenant; nothing is written then.
|
|
10764
|
+
*
|
|
10765
|
+
* Three lines in an app's mutation:
|
|
10766
|
+
*
|
|
10767
|
+
* const memberships = await myMemberships(ctx.subject)
|
|
10768
|
+
* return selectTenant(ctx.store, ctx.subject, input.tenantId, memberships)
|
|
10769
|
+
*/
|
|
10770
|
+
export declare const selectTenant: (store: DataStore, subject: Subject, tenantId: string, memberships: ReadonlyArray<Membership>) => Promise<Subject>;
|
|
10771
|
+
|
|
10550
10772
|
/** A guard, flattened to something a row can hold. */
|
|
10551
10773
|
export declare type SerializedGuard = {
|
|
10552
10774
|
readonly kind: 'scope';
|
|
@@ -10714,6 +10936,8 @@ export declare const setTupleSource: (source: TupleSource | undefined) => void;
|
|
|
10714
10936
|
|
|
10715
10937
|
export declare const sha256Hex: (input: string) => string;
|
|
10716
10938
|
|
|
10939
|
+
export declare const sha256HexOf: (input: string) => string;
|
|
10940
|
+
|
|
10717
10941
|
export declare type ShapeClassification = {
|
|
10718
10942
|
readonly maintainable: true;
|
|
10719
10943
|
readonly shape: AggregateShape;
|
|
@@ -11360,6 +11584,8 @@ export declare interface TableRoutingStats {
|
|
|
11360
11584
|
|
|
11361
11585
|
export { TableValidationFailed }
|
|
11362
11586
|
|
|
11587
|
+
export { TENANT_SELECTIONS_TABLE }
|
|
11588
|
+
|
|
11363
11589
|
/** The standing compute-cost attribution for one tenant — the chargeback /
|
|
11364
11590
|
* showback row + the "why is my bill high" breakdown. Maintained incrementally:
|
|
11365
11591
|
* every `CostEvent` folds into `total`, `byUnit`, and `bySubscription` in O(1).
|
|
@@ -11380,6 +11606,14 @@ export { TenantRowNotFound }
|
|
|
11380
11606
|
|
|
11381
11607
|
export { TenantScopeViolation }
|
|
11382
11608
|
|
|
11609
|
+
export { tenantSelectionId }
|
|
11610
|
+
|
|
11611
|
+
/** The framework's `TenantSelectionStore` over `_voltro_tenant_selections`.
|
|
11612
|
+
* Lazy on the store for the same reason the resolver is: dev builds the
|
|
11613
|
+
* store after the auth chain. A read before the store exists throws, and
|
|
11614
|
+
* the composer turns that into a fail-closed `Unauthenticated`. */
|
|
11615
|
+
export declare const tenantSelectionStore: (getStore: () => DataStore | undefined) => TenantSelectionStore;
|
|
11616
|
+
|
|
11383
11617
|
/** The statuses a run never leaves — where a poller stops.
|
|
11384
11618
|
*
|
|
11385
11619
|
* `skipped` is terminal and is NOT a failure: it means the overlap policy
|
|
@@ -12311,6 +12545,17 @@ export declare interface WorkflowDefinitionLike {
|
|
|
12311
12545
|
toLayer(execute: (payload: never, executionId: string) => Effect.Effect<unknown, unknown, unknown>): Layer.Layer<unknown, unknown, unknown>;
|
|
12312
12546
|
}
|
|
12313
12547
|
|
|
12548
|
+
/** `__voltro.workflow.domainEvents` — the caller's domain events, newest first. */
|
|
12549
|
+
export declare const workflowDomainEventsExecutor: (input: {
|
|
12550
|
+
readonly name?: string;
|
|
12551
|
+
readonly limit?: number;
|
|
12552
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12553
|
+
|
|
12554
|
+
/** `__voltro.workflow.event.deliveries` — the deliveries of one visible event. */
|
|
12555
|
+
export declare const workflowEventDeliveriesExecutor: (input: {
|
|
12556
|
+
readonly eventId: string;
|
|
12557
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12558
|
+
|
|
12314
12559
|
export declare interface WorkflowEventEmitOptions {
|
|
12315
12560
|
readonly id?: string;
|
|
12316
12561
|
readonly source?: string;
|
|
@@ -12494,6 +12739,20 @@ export declare interface WorkflowLayerOptions<Context> {
|
|
|
12494
12739
|
* whose business logic said no.
|
|
12495
12740
|
*/
|
|
12496
12741
|
readonly resolveAuthority?: (identity: unknown) => Promise<unknown>;
|
|
12742
|
+
/**
|
|
12743
|
+
* Told when an execution is refused BEFORE its body — the start context
|
|
12744
|
+
* could not be resolved, the identity was missing, the authority or row
|
|
12745
|
+
* filter resolver rejected. The engine already fails the attempt; what a
|
|
12746
|
+
* discarded start does NOT do is tell anyone, and a run refused here has no
|
|
12747
|
+
* row yet, so nothing else can. Measured: an acknowledged start whose
|
|
12748
|
+
* resident context was filed under another id died with a debug-level
|
|
12749
|
+
* "Fiber terminated" and nothing else. Hosts wire this to an error log.
|
|
12750
|
+
*/
|
|
12751
|
+
readonly reportExecutionRefusal?: (refusal: {
|
|
12752
|
+
readonly workflowName: string;
|
|
12753
|
+
readonly executionId: string;
|
|
12754
|
+
readonly reason: string;
|
|
12755
|
+
}) => void;
|
|
12497
12756
|
}
|
|
12498
12757
|
|
|
12499
12758
|
/**
|
|
@@ -12547,6 +12806,14 @@ export declare class WorkflowRateLimitedError extends Error {
|
|
|
12547
12806
|
constructor(workflowName: string, retryAfterMs: number);
|
|
12548
12807
|
}
|
|
12549
12808
|
|
|
12809
|
+
/** The slice of AppContext these executors need. */
|
|
12810
|
+
export declare interface WorkflowReadCtx {
|
|
12811
|
+
readonly store: Pick<DataStore, 'query'>;
|
|
12812
|
+
readonly request?: {
|
|
12813
|
+
readonly subject?: Subject | null;
|
|
12814
|
+
} | undefined;
|
|
12815
|
+
}
|
|
12816
|
+
|
|
12550
12817
|
/** Result of {@link WorkflowsAppContext.redrive} — whether the failed run's
|
|
12551
12818
|
* durable journal was re-driven, how many failed step attempts were reset so
|
|
12552
12819
|
* they re-execute, and a `reason` when it declined (no journal / still
|
|
@@ -12571,6 +12838,22 @@ export declare interface WorkflowRetryResult {
|
|
|
12571
12838
|
readonly executionId: string;
|
|
12572
12839
|
}
|
|
12573
12840
|
|
|
12841
|
+
/**
|
|
12842
|
+
* May `caller` read a row owned by `rowSubject`? Exported so the rule has one
|
|
12843
|
+
* spelling and a test can pin it without a store.
|
|
12844
|
+
*/
|
|
12845
|
+
export declare const workflowRowVisibleTo: (caller: Subject | null, rowSubject: unknown) => boolean;
|
|
12846
|
+
|
|
12847
|
+
/** `__voltro.workflow.run.events` — the lifecycle events of one visible run. */
|
|
12848
|
+
export declare const workflowRunEventsExecutor: (input: {
|
|
12849
|
+
readonly runId: string;
|
|
12850
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12851
|
+
|
|
12852
|
+
/** `__voltro.workflow.run` — one run by id or execution id. */
|
|
12853
|
+
export declare const workflowRunExecutor: (input: {
|
|
12854
|
+
readonly id: string;
|
|
12855
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12856
|
+
|
|
12574
12857
|
/** Filter passed to {@link WorkflowsAppContext.listRuns}. All fields are
|
|
12575
12858
|
* optional; an empty filter returns the most-recent runs across every
|
|
12576
12859
|
* workflow. `workflowName` and `tag` are aliases for the same column. */
|
|
@@ -12625,12 +12908,24 @@ export declare interface WorkflowRunRecord {
|
|
|
12625
12908
|
* stored column exactly. */
|
|
12626
12909
|
export declare type WorkflowRunRecordStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'suspended';
|
|
12627
12910
|
|
|
12911
|
+
/** `__voltro.workflow.runs` — the caller's runs, newest first. */
|
|
12912
|
+
export declare const workflowRunsExecutor: (input: {
|
|
12913
|
+
readonly tag?: string;
|
|
12914
|
+
readonly status?: string;
|
|
12915
|
+
readonly limit?: number;
|
|
12916
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12917
|
+
|
|
12628
12918
|
export declare type WorkflowRunSnapshot<Success = unknown> = Omit<WorkflowRunSnapshot_2, 'output'> & {
|
|
12629
12919
|
readonly output?: Success;
|
|
12630
12920
|
};
|
|
12631
12921
|
|
|
12632
12922
|
export declare type WorkflowRunStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'suspended' | 'unknown';
|
|
12633
12923
|
|
|
12924
|
+
/** `__voltro.workflow.run.steps` — the steps of one visible run. */
|
|
12925
|
+
export declare const workflowRunStepsExecutor: (input: {
|
|
12926
|
+
readonly runId: string;
|
|
12927
|
+
}, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
|
|
12928
|
+
|
|
12634
12929
|
/** Typed projection of a `_voltro_workflow_runs` row, returned by
|
|
12635
12930
|
* {@link WorkflowsAppContext.listRuns}. Timestamps are `Date`s (the SDK
|
|
12636
12931
|
* hydrates the stored values for app code; the wire/inspect path keeps
|
|
@@ -12670,6 +12965,20 @@ export declare interface WorkflowsAppContext {
|
|
|
12670
12965
|
readControl(target: WorkflowControlTarget): Promise<WorkflowControlResult>;
|
|
12671
12966
|
cancelQueued(target: WorkflowQueuedControlTarget, options?: WorkflowQueuedControlOptions): Promise<WorkflowQueuedCancellationResult>;
|
|
12672
12967
|
readQueuedCancellation(target: WorkflowQueuedControlTarget, options?: Pick<WorkflowQueuedControlOptions, 'callerContext'>): Promise<WorkflowQueuedCancellationResult>;
|
|
12968
|
+
/** What a recorded start handle has become — queued, accepted under an
|
|
12969
|
+
* execution, or never to run — read once, without waiting. A queued handle
|
|
12970
|
+
* is resolved through its durable receipt, so the answer survives the
|
|
12971
|
+
* process that recorded the handle. */
|
|
12972
|
+
readStart(handle: WorkflowRunHandle, options?: Pick<WorkflowWaitOptions, 'callerContext'>): Promise<WorkflowStartObservation>;
|
|
12973
|
+
/**
|
|
12974
|
+
* Set on the facade a mutation TRANSACTION hands out: every start it records
|
|
12975
|
+
* is provisional until the transaction commits, so nothing about a start can
|
|
12976
|
+
* be observed through it — `readStart` refuses. A reconciler that would
|
|
12977
|
+
* otherwise read pending starts (the flow cadence tick) checks this and
|
|
12978
|
+
* leaves them to the next tick that runs outside a transaction, rather than
|
|
12979
|
+
* reporting the refusal as a failure of each row.
|
|
12980
|
+
*/
|
|
12981
|
+
readonly startsDeferredUntilCommit?: true;
|
|
12673
12982
|
signal(target: WorkflowSignalTarget, signalName: string, payload?: unknown): Promise<{
|
|
12674
12983
|
readonly eventId: string;
|
|
12675
12984
|
}>;
|
|
@@ -12740,6 +13049,27 @@ declare const WorkflowStartNotExecuted_base: Schema.TaggedErrorClass<WorkflowSta
|
|
|
12740
13049
|
incumbentExecutionId: Schema.NullOr<typeof Schema.String>;
|
|
12741
13050
|
}>;
|
|
12742
13051
|
|
|
13052
|
+
/**
|
|
13053
|
+
* What a start handle has become, read once and without waiting.
|
|
13054
|
+
*
|
|
13055
|
+
* `pending` — still queued (or submitted and not yet acknowledged). `accepted`
|
|
13056
|
+
* — the engine owns it under `executionId`; poll that. `not-executed` — it will
|
|
13057
|
+
* never run: the same reasons `WorkflowStartNotExecuted` carries, as a value
|
|
13058
|
+
* rather than a throw, because a reconciler asking "what happened to the start
|
|
13059
|
+
* I recorded" wants an answer, not an exception per row.
|
|
13060
|
+
*/
|
|
13061
|
+
export declare type WorkflowStartObservation = {
|
|
13062
|
+
readonly kind: 'pending';
|
|
13063
|
+
} | {
|
|
13064
|
+
readonly kind: 'accepted';
|
|
13065
|
+
readonly executionId: string;
|
|
13066
|
+
} | {
|
|
13067
|
+
readonly kind: 'not-executed';
|
|
13068
|
+
readonly reason: WorkflowStartNotExecuted['reason'];
|
|
13069
|
+
readonly failureId: string | null;
|
|
13070
|
+
readonly incumbentExecutionId: string | null;
|
|
13071
|
+
};
|
|
13072
|
+
|
|
12743
13073
|
export declare interface WorkflowStartOptions {
|
|
12744
13074
|
/* Excluded from this release type: preparedExecutionId */
|
|
12745
13075
|
readonly wait?: boolean;
|