@voltro/runtime 0.71.1 → 0.73.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.
@@ -5,7 +5,7 @@ property of its respective copyright holders and is used under the terms of
5
5
  its license. This file is provided for attribution; it grants no rights in
6
6
  @voltro/runtime itself, which is proprietary (see LICENSE).
7
7
 
8
- Generated from the resolved runtime dependency closure (52 packages).
8
+ Generated from the resolved runtime dependency closure (53 packages).
9
9
 
10
10
  ---
11
11
 
@@ -37,6 +37,34 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
37
  SOFTWARE.
38
38
  ```
39
39
 
40
+ ## @effect/experimental@0.61.1
41
+
42
+ License: MIT
43
+
44
+ ```
45
+ MIT License
46
+
47
+ Copyright (c) 2023-present The Contributors
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining a copy
50
+ of this software and associated documentation files (the "Software"), to deal
51
+ in the Software without restriction, including without limitation the rights
52
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53
+ copies of the Software, and to permit persons to whom the Software is
54
+ furnished to do so, subject to the following conditions:
55
+
56
+ The above copyright notice and this permission notice shall be included in all
57
+ copies or substantial portions of the Software.
58
+
59
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65
+ SOFTWARE.
66
+ ```
67
+
40
68
  ## @effect/platform-node@0.108.1
41
69
 
42
70
  License: MIT
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ import { ChangeEvent } from '@voltro/database';
8
8
  import { classifyConstraintViolation } from '@voltro/database';
9
9
  import { clearRetentions } from '@voltro/database';
10
10
  import { ColumnBuilder } from '@voltro/database';
11
+ import { ColumnDefinition } from '@voltro/database';
11
12
  import { ConnectionCredential } from '@voltro/protocol';
12
13
  import { ConnectionInfo } from '@voltro/protocol';
13
14
  import { ConnectionInfoMiddleware } from '@voltro/protocol';
@@ -43,6 +44,8 @@ import { HttpRequestInterceptor } from '@voltro/protocol';
43
44
  import { HttpRouteObserver } from '@voltro/protocol';
44
45
  import { IdempotencyStore } from '@voltro/protocol';
45
46
  import { IdScheme } from '@voltro/database';
47
+ import { InferInsertRow } from '@voltro/database';
48
+ import { InferRow } from '@voltro/database';
46
49
  import { InMemoryMetricExporter } from '@opentelemetry/sdk-metrics';
47
50
  import { InMemorySpanExporter } from '@opentelemetry/sdk-trace-base';
48
51
  import { InsertIgnoreResult } from '@voltro/database';
@@ -57,6 +60,7 @@ import { KvStoreShape } from '@voltro/kv';
57
60
  import { Layer } from 'effect';
58
61
  import { listRetentionConflicts } from '@voltro/database';
59
62
  import { listRetentions } from '@voltro/database';
63
+ import { Membership } from '@voltro/protocol';
60
64
  import { Metric } from 'effect';
61
65
  import { MetricBoundaries } from 'effect';
62
66
  import { MetricReader } from '@opentelemetry/sdk-metrics';
@@ -107,8 +111,11 @@ import { TableLike } from '@voltro/database';
107
111
  import { TableName } from '@voltro/protocol';
108
112
  import { TableValidationFailed } from '@voltro/protocol';
109
113
  import { TargetRelation } from '@voltro/protocol';
114
+ import { TENANT_SELECTIONS_TABLE } from '@voltro/database';
110
115
  import { TenantRowNotFound } from '@voltro/protocol';
111
116
  import { TenantScopeViolation } from '@voltro/protocol';
117
+ import { tenantSelectionId } from '@voltro/database';
118
+ import { TenantSelectionStore } from '@voltro/protocol';
112
119
  import { Tracer } from 'effect';
113
120
  import { Unauthenticated } from '@voltro/protocol';
114
121
  import { UpsertOptions } from '@voltro/database';
@@ -872,6 +879,9 @@ declare type AnyRow = Record<string, unknown>;
872
879
 
873
880
  declare type AnyRow_2 = Record<string, unknown>;
874
881
 
882
+ /** Any table — the loose shape these helpers accept structurally. */
883
+ declare type AnyWritableTable = Table<string, Record<string, ColumnDefinition<unknown>>, boolean, string>;
884
+
875
885
  /** Locked-down policy for an API response. Nothing loads, nothing frames it. */
876
886
  export declare const API_CSP = "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'";
877
887
 
@@ -2134,6 +2144,11 @@ export { clearRetentions }
2134
2144
  /** Clear the process-wide handle (test teardown). */
2135
2145
  export declare const clearSystemStoreHandle: () => void;
2136
2146
 
2147
+ /** Forget the subject's selection: the next request resolves in the tenant
2148
+ * its credential names. A no-op for a subject with none, and for the types
2149
+ * that cannot hold one. */
2150
+ export declare const clearTenantSelection: (store: DataStore, subject: Subject) => Promise<void>;
2151
+
2137
2152
  export declare interface ClientAddressInput {
2138
2153
  /** `socket.remoteAddress` — the only unforgeable value in the request. */
2139
2154
  readonly socketAddress: string | undefined;
@@ -3054,6 +3069,8 @@ export declare interface DataStoreApiKeyStoreOptions {
3054
3069
  readonly ensureActor?: ((actor: ApiKeyActor, store: DataStore) => Promise<void>) | undefined;
3055
3070
  }
3056
3071
 
3072
+ export declare const dataStoreDeviceStore: (store: DataStore) => DeviceStore;
3073
+
3057
3074
  export declare const dataStoreIdempotencyStore: (store: DataStore) => IdempotencyStore;
3058
3075
 
3059
3076
  /** Build a durable `KvStoreShape` over a raw `DataStore`. */
@@ -3474,6 +3491,128 @@ export declare const detachForResume: (identity: ResumeIdentity, handle: {
3474
3491
  readonly unsubscribe: () => void;
3475
3492
  }, tunables?: ResumeTunables, now?: () => number) => void;
3476
3493
 
3494
+ export declare interface DeviceActor {
3495
+ readonly id: string;
3496
+ readonly displayName: string;
3497
+ }
3498
+
3499
+ /** The device routes. Mounted under `basePath` (default `/v1/devices`) when
3500
+ * `devices` is on. `pair`, list and `revoke` need `admin:full` or
3501
+ * `devices:manage`; `exchange` and `rotate` are the device's own calls and
3502
+ * carry no session — the one-time code and the refresh token ARE the
3503
+ * credential, and a wrong one is `401` with one reason for every cause. */
3504
+ export declare const deviceManagementRoutes: (service: DeviceServiceShape, basePath?: string) => ReadonlyArray<RestRouteDescriptor<any, any>>;
3505
+
3506
+ export declare interface DeviceRow {
3507
+ readonly id: string;
3508
+ readonly tenantId: string;
3509
+ readonly name: string;
3510
+ readonly scopes: ReadonlyArray<string> | null;
3511
+ readonly pairingHash: string | null;
3512
+ readonly pairingExpiresAt: number | null;
3513
+ readonly accessHash: string | null;
3514
+ readonly accessExpiresAt: number | null;
3515
+ readonly refreshHash: string | null;
3516
+ readonly refreshExpiresAt: number | null;
3517
+ /** The refresh hash rotated OUT by the last rotation — what a replay
3518
+ * presents. One generation back is what a stolen-then-rotated token looks
3519
+ * like; older replays fail as unknown, which is refusal enough. */
3520
+ readonly previousRefreshHash: string | null;
3521
+ readonly generation: number;
3522
+ readonly pairedAt: number | null;
3523
+ readonly lastSeenAt: number | null;
3524
+ readonly revokedAt: number | null;
3525
+ readonly revokedReason: string | null;
3526
+ readonly createdBy: string | null;
3527
+ readonly createdAt: number;
3528
+ readonly metadata?: Readonly<Record<string, unknown>> | null;
3529
+ }
3530
+
3531
+ export declare const DEVICES_TABLE = "_voltro_devices";
3532
+
3533
+ export declare interface DeviceServiceOptions {
3534
+ readonly prefix?: string;
3535
+ /** Access token lifetime. Default 15 minutes — long enough that a device
3536
+ * polling every minute rotates rarely, short enough that a leaked token is
3537
+ * a bounded problem. */
3538
+ readonly accessTtlSeconds?: number;
3539
+ /** Refresh token lifetime — how long a device may stay silent and still
3540
+ * come back. Default 30 days. */
3541
+ readonly refreshTtlSeconds?: number;
3542
+ /** How long an admin has between pairing and the device's exchange. Default
3543
+ * 10 minutes. */
3544
+ readonly pairingTtlSeconds?: number;
3545
+ }
3546
+
3547
+ export declare interface DeviceServiceShape {
3548
+ /** Admin-side: create the device and its one-time pairing code. */
3549
+ readonly pair: (input: PairInput) => Promise<PairedDevice>;
3550
+ /** Device-side, once: the pairing code for the first token pair. Null when
3551
+ * the code is unknown, expired, already exchanged, or the device revoked —
3552
+ * one answer, so the route cannot be used to tell those apart. */
3553
+ readonly exchange: (pairingCode: string, now?: number) => Promise<DeviceTokens | null>;
3554
+ /** Device-side, repeatedly: the current refresh token for a new pair
3555
+ * (`generation + 1`). A refresh token that was already rotated out is a
3556
+ * REPLAY: the device is revoked with reason `refresh-replay` and null is
3557
+ * returned. Null also for unknown / expired / revoked. */
3558
+ readonly rotate: (refreshToken: string, now?: number) => Promise<DeviceTokens | null>;
3559
+ /** Hash lookup used by the auth strategy: the device's identity while its
3560
+ * access token is live. No write — see the module note. */
3561
+ readonly resolveAccess: (accessHash: string, now?: number) => Promise<ResolvedDevice | null>;
3562
+ /** Revoke (irreversible). `tenantId` is the CALLER's tenant and required for
3563
+ * the same reason as the api-key service's: ids leak, and an admin of one
3564
+ * tenant must not revoke another's device by id. */
3565
+ readonly revoke: (id: string, tenantId: string, now?: number) => Promise<boolean>;
3566
+ readonly list: (tenantId: string) => Promise<ReadonlyArray<PublicDevice>>;
3567
+ }
3568
+
3569
+ export declare interface DeviceStore {
3570
+ readonly insert: (row: DeviceRow) => Promise<void>;
3571
+ readonly findById: (id: string) => Promise<DeviceRow | null>;
3572
+ readonly findByPairingHash: (hash: string) => Promise<DeviceRow | null>;
3573
+ readonly findByAccessHash: (hash: string) => Promise<DeviceRow | null>;
3574
+ readonly findByRefreshHash: (hash: string) => Promise<DeviceRow | null>;
3575
+ readonly findByPreviousRefreshHash: (hash: string) => Promise<DeviceRow | null>;
3576
+ readonly listByTenant: (tenantId: string) => Promise<ReadonlyArray<DeviceRow>>;
3577
+ readonly patch: (id: string, fields: Partial<DeviceRow>) => Promise<void>;
3578
+ /**
3579
+ * A FENCED patch: applies `fields` only while `column` still equals
3580
+ * `expected`, and says whether it did. Exchange and rotation are claims on
3581
+ * a one-time secret — two exchanges of one pairing code, two rotations of
3582
+ * one refresh token — and the claim has to be decided by the row, not by a
3583
+ * read that both callers made a moment ago.
3584
+ */
3585
+ readonly claim: (id: string, column: 'pairingHash' | 'refreshHash', expected: string, fields: Partial<DeviceRow>) => Promise<boolean>;
3586
+ /** Plant the device's `actors` row (kind `serviceAccount`) — the audit
3587
+ * subject its writes point at. Required, like the api-key store's: an
3588
+ * omitted actor row is the foreign-key failure on the first audited
3589
+ * insert. Idempotent. */
3590
+ readonly ensureActor: (actor: DeviceActor) => Promise<void>;
3591
+ }
3592
+
3593
+ /** The three token shapes, derived from ONE configured prefix so a bearer
3594
+ * prefix collision check (`assertNoBearerPrefixCollision`) sees one claim:
3595
+ * `dev_` → access `dev_…`, refresh `devr_…`, pairing `devp_…`. Refresh and
3596
+ * pairing tokens are never presented as bearers; their prefixes exist so a
3597
+ * token pasted into the wrong field is refused by shape, not by luck. */
3598
+ export declare interface DeviceTokenPrefixes {
3599
+ readonly access: string;
3600
+ readonly refresh: string;
3601
+ readonly pairing: string;
3602
+ }
3603
+
3604
+ export declare const deviceTokenPrefixes: (prefix?: string) => DeviceTokenPrefixes;
3605
+
3606
+ /** What an exchange or a rotation hands the device. Shown once. */
3607
+ export declare interface DeviceTokens {
3608
+ readonly deviceId: string;
3609
+ readonly accessToken: string;
3610
+ readonly accessExpiresAt: number;
3611
+ readonly refreshToken: string;
3612
+ readonly refreshExpiresAt: number;
3613
+ readonly generation: number;
3614
+ }
3615
+
3477
3616
  export { DialectReplicationAdapter }
3478
3617
 
3479
3618
  /** Field-level diff for one change. Insert → every field `undefined→value`;
@@ -3809,6 +3948,23 @@ export declare interface DrainResult {
3809
3948
  */
3810
3949
  export declare const dueWakeups: (store: DataStore, now: Date, limit?: number) => Promise<ReadonlyArray<Wakeup>>;
3811
3950
 
3951
+ /** The minimal Effect-store surface `insertIgnoreRowOutcomeEffect` needs. */
3952
+ export declare interface EffectInsertIgnoreOutcomeStore {
3953
+ readonly insertIgnoreWithOutcome: (table: string, row: Row, options: {
3954
+ readonly conflictColumns: ReadonlyArray<string>;
3955
+ }) => Effect.Effect<InsertIgnoreResult, StoreError>;
3956
+ }
3957
+
3958
+ /** The minimal Effect-store surface `insertManyRowsEffect` needs. */
3959
+ export declare interface EffectInsertManyStore {
3960
+ readonly insertMany: (table: string, rows: ReadonlyArray<Row>) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
3961
+ }
3962
+
3963
+ /** The minimal Effect-store surface `insertRowEffect` needs. */
3964
+ export declare interface EffectInsertStore {
3965
+ readonly insert: (table: string, row: Row) => Effect.Effect<Row, StoreError>;
3966
+ }
3967
+
3812
3968
  /** The subject's effective relations on the resource — direct tuples expanded
3813
3969
  * by the policy's implications. */
3814
3970
  export declare const effectiveRelations: (subject: RebacSubject, resource: RebacResource, tuples: ReadonlyArray<RelationTuple>, policy: ResourcePolicy) => ReadonlySet<string>;
@@ -3886,6 +4042,24 @@ export declare interface EffectStoreOps {
3886
4042
  readonly transactional: <A, E, R>(work: (transaction: EffectStoreOps) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StoreError, R>;
3887
4043
  }
3888
4044
 
4045
+ /**
4046
+ * The minimal Effect-store surface `upsertRowOutcomeEffect` needs.
4047
+ *
4048
+ * NOT optional, unlike `TypedUpsertOutcomeStore.upsertWithOutcome`. The Promise
4049
+ * form has to tolerate a hand-written `DataStore` that lacks the method and
4050
+ * throws when it does; `EffectStoreOps` always provides it, so the refusal has
4051
+ * no state to describe. An error case for an unreachable condition is one every
4052
+ * caller must handle and none can trigger.
4053
+ */
4054
+ export declare interface EffectUpsertOutcomeStore {
4055
+ readonly upsertWithOutcome: (table: string, row: Row, options: UpsertOptions) => Effect.Effect<UpsertResult, StoreError>;
4056
+ }
4057
+
4058
+ /** The minimal Effect-store surface `upsertRowEffect` needs. */
4059
+ export declare interface EffectUpsertStore {
4060
+ readonly upsert: (table: string, row: Row, options: UpsertOptions) => Effect.Effect<Row, StoreError>;
4061
+ }
4062
+
3889
4063
  /** Empty registry — handy for tests + the rare bootstrap path with no
3890
4064
  * discovered tables. */
3891
4065
  export declare const emptySchemaRegistry: SchemaRegistry;
@@ -5213,6 +5387,15 @@ export declare const frameworkApiKeyStrategy: (service: ApiKeyServiceShape, opts
5213
5387
  prefix?: string;
5214
5388
  }) => AuthStrategy;
5215
5389
 
5390
+ /** The framework device auth strategy. A device is a machine caller WITH a
5391
+ * tenant — a `serviceAccount` subject whose id is the device id, so audit
5392
+ * columns point at the device's own `actors` row. `credentialExpiresAt` is
5393
+ * the access token's expiry: a standing subscription opened with it ends
5394
+ * when the token does, and the device's next rotation re-opens it. */
5395
+ export declare const frameworkDeviceStrategy: (service: DeviceServiceShape, opts?: {
5396
+ prefix?: string;
5397
+ }) => AuthStrategy;
5398
+
5216
5399
  /** Define a gauge (set with `setMetric`). */
5217
5400
  export declare const gauge: (name: string, description?: string) => Metric.Metric.Gauge<number>;
5218
5401
 
@@ -5449,6 +5632,25 @@ export declare class InMemoryDataStore implements DataStore {
5449
5632
  injectExternalChange(event: ChangeEvent): void;
5450
5633
  }
5451
5634
 
5635
+ /** `insertIgnore`, typed against the table, plus whether it inserted or found the row. */
5636
+ export declare const insertIgnoreRowOutcomeEffect: <T extends AnyWritableTable>(store: EffectInsertIgnoreOutcomeStore, table: T, row: InferInsertRow<T>, options: {
5637
+ readonly conflictColumns: ReadonlyArray<keyof InferRow<T> & string>;
5638
+ }) => Effect.Effect<{
5639
+ readonly row: InferRow<T>;
5640
+ readonly outcome: "inserted" | "ignored";
5641
+ }, StoreError>;
5642
+
5643
+ /** `insertRowEffect`'s batch — every element checked against `InferInsertRow<T>`. */
5644
+ export declare const insertManyRowsEffect: <T extends AnyWritableTable>(store: EffectInsertManyStore, table: T, rows: ReadonlyArray<InferInsertRow<T>>) => Effect.Effect<ReadonlyArray<InferRow<T>>, StoreError>;
5645
+
5646
+ /**
5647
+ * Insert a row, typed against the table, on the Effect channel.
5648
+ *
5649
+ * const store = yield* EffectStore
5650
+ * const saved = yield* insertRowEffect(store, players, { tenantId, name })
5651
+ */
5652
+ export declare const insertRowEffect: <T extends AnyWritableTable>(store: EffectInsertStore, table: T, row: InferInsertRow<T>) => Effect.Effect<InferRow<T>, StoreError>;
5653
+
5452
5654
  export { InspectedStep }
5453
5655
 
5454
5656
  export { InspectedWorkflow }
@@ -6156,6 +6358,8 @@ export declare const makeDataLoader: (deps: LoaderDeps) => DataLoader;
6156
6358
  */
6157
6359
  export declare const makeDefaultRefilter: (subject: Subject, onError?: (error: unknown) => void) => (() => Promise<RowFilterScope>) | undefined;
6158
6360
 
6361
+ export declare const makeDeviceService: (store: DeviceStore, opts?: DeviceServiceOptions) => DeviceServiceShape;
6362
+
6159
6363
  /** `__voltro.connections.disconnect` — forget the caller's credential. */
6160
6364
  export declare const makeDisconnectConnectionExecutor: (deps: ConnectionBuiltinDeps) => (input: {
6161
6365
  readonly connectionId: string;
@@ -6573,6 +6777,10 @@ export declare const memoryApiKeyStore: () => ApiKeyStore & {
6573
6777
  readonly actors: ReadonlyMap<string, MemoryActorRow>;
6574
6778
  };
6575
6779
 
6780
+ export declare const memoryDeviceStore: () => DeviceStore & {
6781
+ readonly actors: ReadonlyMap<string, DeviceActor>;
6782
+ };
6783
+
6576
6784
  /**
6577
6785
  * Adapter for in-memory testing. The "position" is a monotonically-
6578
6786
  * increasing integer tick the test controls. Primary writes bump the
@@ -6991,10 +7199,10 @@ export declare interface OAuth2ConnectionDefinition extends ConnectionDefinition
6991
7199
  readonly kind: 'oauth2';
6992
7200
  readonly authorizeUrl: string;
6993
7201
  readonly tokenUrl: string;
6994
- readonly clientId: string;
7202
+ readonly clientId: OAuthClientCredential;
6995
7203
  /** Runtime secret. Never logged, never sent to the browser, never bundled —
6996
7204
  * `*.connection.ts` is server-only and is NOT part of the rpcGroup codegen. */
6997
- readonly clientSecret: string;
7205
+ readonly clientSecret: OAuthClientCredential;
6998
7206
  readonly scopes?: ReadonlyArray<string>;
6999
7207
  /** Exact redirect URI registered with the provider. Defaults to
7000
7208
  * `<publicUrl>/_voltro/connections/<id>/callback`. */
@@ -7013,6 +7221,20 @@ export declare interface OAuth2ConnectionDefinition extends ConnectionDefinition
7013
7221
  readonly identify?: (tokens: ConnectionTokens) => Promise<ConnectionAccount>;
7014
7222
  }
7015
7223
 
7224
+ /**
7225
+ * A credential as the file states it: the string, or a thunk that produces it.
7226
+ *
7227
+ * The thunk exists because of WHEN a `*.connection.ts` is evaluated. Discovery
7228
+ * imports it before the env gate has run — `voltro doctor` runs no gate at all —
7229
+ * and `serverEnv.X` read at module top level throws there by design. A thunk
7230
+ * defers the read to the moment the connection is used (an authorize URL, a
7231
+ * token exchange), which is always after the gate. `oauthCredentialValue` is the
7232
+ * one reader.
7233
+ */
7234
+ export declare type OAuthClientCredential = string | (() => string);
7235
+
7236
+ export declare const oauthCredentialValue: (credential: OAuthClientCredential) => string;
7237
+
7016
7238
  /** One recorded `(procedure → table, op)` edge. */
7017
7239
  export declare interface ObservedEdge {
7018
7240
  readonly tag: string;
@@ -7336,6 +7558,25 @@ declare interface P2COptions {
7336
7558
  readonly random?: () => number;
7337
7559
  }
7338
7560
 
7561
+ export declare interface PairedDevice {
7562
+ readonly id: string;
7563
+ readonly name: string;
7564
+ readonly tenantId: string;
7565
+ readonly scopes: ReadonlyArray<string>;
7566
+ /** Shown ONCE. Exchanged for the first token pair, then gone. */
7567
+ readonly pairingCode: string;
7568
+ readonly pairingExpiresAt: number;
7569
+ }
7570
+
7571
+ export declare interface PairInput {
7572
+ readonly tenantId: string;
7573
+ readonly name: string;
7574
+ readonly scopes?: ReadonlyArray<string>;
7575
+ /** WHO PAIRED IT. Provenance. */
7576
+ readonly createdBy?: string | null;
7577
+ readonly metadata?: Readonly<Record<string, unknown>> | null;
7578
+ }
7579
+
7339
7580
  /**
7340
7581
  * Parse an interval string (`'30m'`, `'4h'`, `'7d'`) to ms, or `null`.
7341
7582
  * A local copy for the same reason `finops.ts` keeps one — this module must not
@@ -7602,6 +7843,22 @@ export declare interface PublicApiKey {
7602
7843
  readonly metadata?: Readonly<Record<string, unknown>> | null;
7603
7844
  }
7604
7845
 
7846
+ export declare interface PublicDevice {
7847
+ readonly id: string;
7848
+ readonly name: string;
7849
+ readonly tenantId: string;
7850
+ readonly scopes: ReadonlyArray<string>;
7851
+ readonly generation: number;
7852
+ readonly pairedAt: number | null;
7853
+ readonly lastSeenAt: number | null;
7854
+ readonly accessExpiresAt: number | null;
7855
+ readonly revokedAt: number | null;
7856
+ readonly revokedReason: string | null;
7857
+ readonly createdAt: number;
7858
+ readonly createdBy: string | null;
7859
+ readonly metadata?: Readonly<Record<string, unknown>> | null;
7860
+ }
7861
+
7605
7862
  /**
7606
7863
  * Validate, size-check and publish one event.
7607
7864
  *
@@ -8831,6 +9088,17 @@ export declare interface ResolvedConnection {
8831
9088
  readonly accountLabel: string | null;
8832
9089
  }
8833
9090
 
9091
+ /** What the auth strategy learns from a presented access token. */
9092
+ export declare interface ResolvedDevice {
9093
+ readonly id: string;
9094
+ readonly tenantId: string;
9095
+ readonly name: string;
9096
+ readonly scopes: ReadonlyArray<string>;
9097
+ readonly generation: number;
9098
+ readonly accessExpiresAt: number;
9099
+ readonly metadata?: Readonly<Record<string, unknown>>;
9100
+ }
9101
+
8834
9102
  /**
8835
9103
  * Walk a query descriptor's eager-load tree and return the FULL set
8836
9104
  * of tables whose changes could affect the resolved snapshot.
@@ -10547,6 +10815,20 @@ export declare class SelectBuilder {
10547
10815
  get descriptor(): QueryDescriptor;
10548
10816
  }
10549
10817
 
10818
+ /**
10819
+ * Select `tenantId` as the subject's active tenant — verified against
10820
+ * `memberships` through the one rule (`selectSubjectTenant`), then stored.
10821
+ * Returns the subject as it will resolve on the next request. Throws
10822
+ * `TenantSelectionRefused` when the target is not among the memberships or
10823
+ * the subject is of a type that has no tenant; nothing is written then.
10824
+ *
10825
+ * Three lines in an app's mutation:
10826
+ *
10827
+ * const memberships = await myMemberships(ctx.subject)
10828
+ * return selectTenant(ctx.store, ctx.subject, input.tenantId, memberships)
10829
+ */
10830
+ export declare const selectTenant: (store: DataStore, subject: Subject, tenantId: string, memberships: ReadonlyArray<Membership>) => Promise<Subject>;
10831
+
10550
10832
  /** A guard, flattened to something a row can hold. */
10551
10833
  export declare type SerializedGuard = {
10552
10834
  readonly kind: 'scope';
@@ -10714,6 +10996,8 @@ export declare const setTupleSource: (source: TupleSource | undefined) => void;
10714
10996
 
10715
10997
  export declare const sha256Hex: (input: string) => string;
10716
10998
 
10999
+ export declare const sha256HexOf: (input: string) => string;
11000
+
10717
11001
  export declare type ShapeClassification = {
10718
11002
  readonly maintainable: true;
10719
11003
  readonly shape: AggregateShape;
@@ -11360,6 +11644,8 @@ export declare interface TableRoutingStats {
11360
11644
 
11361
11645
  export { TableValidationFailed }
11362
11646
 
11647
+ export { TENANT_SELECTIONS_TABLE }
11648
+
11363
11649
  /** The standing compute-cost attribution for one tenant — the chargeback /
11364
11650
  * showback row + the "why is my bill high" breakdown. Maintained incrementally:
11365
11651
  * every `CostEvent` folds into `total`, `byUnit`, and `bySubscription` in O(1).
@@ -11380,6 +11666,14 @@ export { TenantRowNotFound }
11380
11666
 
11381
11667
  export { TenantScopeViolation }
11382
11668
 
11669
+ export { tenantSelectionId }
11670
+
11671
+ /** The framework's `TenantSelectionStore` over `_voltro_tenant_selections`.
11672
+ * Lazy on the store for the same reason the resolver is: dev builds the
11673
+ * store after the auth chain. A read before the store exists throws, and
11674
+ * the composer turns that into a fail-closed `Unauthenticated`. */
11675
+ export declare const tenantSelectionStore: (getStore: () => DataStore | undefined) => TenantSelectionStore;
11676
+
11383
11677
  /** The statuses a run never leaves — where a poller stops.
11384
11678
  *
11385
11679
  * `skipped` is terminal and is NOT a failure: it means the overlap policy
@@ -11749,6 +12043,13 @@ export declare type TupleSource = (req: {
11749
12043
  * view it obtained from the dialect store directly. */
11750
12044
  export declare const TX_READ_VERSIONS_KEY: unique symbol;
11751
12045
 
12046
+ /** `conflictColumns` / `update` / `updateValues`, constrained to the table's own columns. */
12047
+ declare interface TypedUpsertOptions<T extends AnyWritableTable> {
12048
+ readonly conflictColumns: ReadonlyArray<keyof InferRow<T> & string>;
12049
+ readonly update?: ReadonlyArray<keyof InferRow<T> & string> | ((existing: InferRow<T>) => Readonly<Partial<InferRow<T>>>);
12050
+ readonly updateValues?: Readonly<Partial<Omit<InferRow<T>, 'id'>>>;
12051
+ }
12052
+
11752
12053
  /**
11753
12054
  * Drop everything this connection accumulated. Called by the transport finalizer
11754
12055
  * and by explicit sign-out flows. Idempotent.
@@ -11906,6 +12207,15 @@ export declare class UpdateBuilder {
11906
12207
  restore(): Promise<number>;
11907
12208
  }
11908
12209
 
12210
+ /** Upsert a row, typed against the table, on the Effect channel. */
12211
+ export declare const upsertRowEffect: <T extends AnyWritableTable>(store: EffectUpsertStore, table: T, row: InferInsertRow<T>, options: TypedUpsertOptions<T>) => Effect.Effect<InferRow<T>, StoreError>;
12212
+
12213
+ /** `upsertRowEffect`, plus whether the row was INSERTED or UPDATED. */
12214
+ export declare const upsertRowOutcomeEffect: <T extends AnyWritableTable>(store: EffectUpsertOutcomeStore, table: T, row: InferInsertRow<T>, options: TypedUpsertOptions<T>) => Effect.Effect<{
12215
+ readonly row: InferRow<T>;
12216
+ readonly outcome: "inserted" | "updated";
12217
+ }, StoreError>;
12218
+
11909
12219
  /**
11910
12220
  * Sugar for `yield* AggregateRegistry` + `.getHandle(def)`. The
11911
12221
  * type-safe entry point for reading an aggregate from a handler.
@@ -12311,6 +12621,17 @@ export declare interface WorkflowDefinitionLike {
12311
12621
  toLayer(execute: (payload: never, executionId: string) => Effect.Effect<unknown, unknown, unknown>): Layer.Layer<unknown, unknown, unknown>;
12312
12622
  }
12313
12623
 
12624
+ /** `__voltro.workflow.domainEvents` — the caller's domain events, newest first. */
12625
+ export declare const workflowDomainEventsExecutor: (input: {
12626
+ readonly name?: string;
12627
+ readonly limit?: number;
12628
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
12629
+
12630
+ /** `__voltro.workflow.event.deliveries` — the deliveries of one visible event. */
12631
+ export declare const workflowEventDeliveriesExecutor: (input: {
12632
+ readonly eventId: string;
12633
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
12634
+
12314
12635
  export declare interface WorkflowEventEmitOptions {
12315
12636
  readonly id?: string;
12316
12637
  readonly source?: string;
@@ -12494,6 +12815,20 @@ export declare interface WorkflowLayerOptions<Context> {
12494
12815
  * whose business logic said no.
12495
12816
  */
12496
12817
  readonly resolveAuthority?: (identity: unknown) => Promise<unknown>;
12818
+ /**
12819
+ * Told when an execution is refused BEFORE its body — the start context
12820
+ * could not be resolved, the identity was missing, the authority or row
12821
+ * filter resolver rejected. The engine already fails the attempt; what a
12822
+ * discarded start does NOT do is tell anyone, and a run refused here has no
12823
+ * row yet, so nothing else can. Measured: an acknowledged start whose
12824
+ * resident context was filed under another id died with a debug-level
12825
+ * "Fiber terminated" and nothing else. Hosts wire this to an error log.
12826
+ */
12827
+ readonly reportExecutionRefusal?: (refusal: {
12828
+ readonly workflowName: string;
12829
+ readonly executionId: string;
12830
+ readonly reason: string;
12831
+ }) => void;
12497
12832
  }
12498
12833
 
12499
12834
  /**
@@ -12547,6 +12882,14 @@ export declare class WorkflowRateLimitedError extends Error {
12547
12882
  constructor(workflowName: string, retryAfterMs: number);
12548
12883
  }
12549
12884
 
12885
+ /** The slice of AppContext these executors need. */
12886
+ export declare interface WorkflowReadCtx {
12887
+ readonly store: Pick<DataStore, 'query'>;
12888
+ readonly request?: {
12889
+ readonly subject?: Subject | null;
12890
+ } | undefined;
12891
+ }
12892
+
12550
12893
  /** Result of {@link WorkflowsAppContext.redrive} — whether the failed run's
12551
12894
  * durable journal was re-driven, how many failed step attempts were reset so
12552
12895
  * they re-execute, and a `reason` when it declined (no journal / still
@@ -12571,6 +12914,22 @@ export declare interface WorkflowRetryResult {
12571
12914
  readonly executionId: string;
12572
12915
  }
12573
12916
 
12917
+ /**
12918
+ * May `caller` read a row owned by `rowSubject`? Exported so the rule has one
12919
+ * spelling and a test can pin it without a store.
12920
+ */
12921
+ export declare const workflowRowVisibleTo: (caller: Subject | null, rowSubject: unknown) => boolean;
12922
+
12923
+ /** `__voltro.workflow.run.events` — the lifecycle events of one visible run. */
12924
+ export declare const workflowRunEventsExecutor: (input: {
12925
+ readonly runId: string;
12926
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
12927
+
12928
+ /** `__voltro.workflow.run` — one run by id or execution id. */
12929
+ export declare const workflowRunExecutor: (input: {
12930
+ readonly id: string;
12931
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
12932
+
12574
12933
  /** Filter passed to {@link WorkflowsAppContext.listRuns}. All fields are
12575
12934
  * optional; an empty filter returns the most-recent runs across every
12576
12935
  * workflow. `workflowName` and `tag` are aliases for the same column. */
@@ -12625,12 +12984,24 @@ export declare interface WorkflowRunRecord {
12625
12984
  * stored column exactly. */
12626
12985
  export declare type WorkflowRunRecordStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'suspended';
12627
12986
 
12987
+ /** `__voltro.workflow.runs` — the caller's runs, newest first. */
12988
+ export declare const workflowRunsExecutor: (input: {
12989
+ readonly tag?: string;
12990
+ readonly status?: string;
12991
+ readonly limit?: number;
12992
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
12993
+
12628
12994
  export declare type WorkflowRunSnapshot<Success = unknown> = Omit<WorkflowRunSnapshot_2, 'output'> & {
12629
12995
  readonly output?: Success;
12630
12996
  };
12631
12997
 
12632
12998
  export declare type WorkflowRunStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'suspended' | 'unknown';
12633
12999
 
13000
+ /** `__voltro.workflow.run.steps` — the steps of one visible run. */
13001
+ export declare const workflowRunStepsExecutor: (input: {
13002
+ readonly runId: string;
13003
+ }, ctx: WorkflowReadCtx) => Promise<ReadonlyArray<unknown>>;
13004
+
12634
13005
  /** Typed projection of a `_voltro_workflow_runs` row, returned by
12635
13006
  * {@link WorkflowsAppContext.listRuns}. Timestamps are `Date`s (the SDK
12636
13007
  * hydrates the stored values for app code; the wire/inspect path keeps
@@ -12670,6 +13041,20 @@ export declare interface WorkflowsAppContext {
12670
13041
  readControl(target: WorkflowControlTarget): Promise<WorkflowControlResult>;
12671
13042
  cancelQueued(target: WorkflowQueuedControlTarget, options?: WorkflowQueuedControlOptions): Promise<WorkflowQueuedCancellationResult>;
12672
13043
  readQueuedCancellation(target: WorkflowQueuedControlTarget, options?: Pick<WorkflowQueuedControlOptions, 'callerContext'>): Promise<WorkflowQueuedCancellationResult>;
13044
+ /** What a recorded start handle has become — queued, accepted under an
13045
+ * execution, or never to run — read once, without waiting. A queued handle
13046
+ * is resolved through its durable receipt, so the answer survives the
13047
+ * process that recorded the handle. */
13048
+ readStart(handle: WorkflowRunHandle, options?: Pick<WorkflowWaitOptions, 'callerContext'>): Promise<WorkflowStartObservation>;
13049
+ /**
13050
+ * Set on the facade a mutation TRANSACTION hands out: every start it records
13051
+ * is provisional until the transaction commits, so nothing about a start can
13052
+ * be observed through it — `readStart` refuses. A reconciler that would
13053
+ * otherwise read pending starts (the flow cadence tick) checks this and
13054
+ * leaves them to the next tick that runs outside a transaction, rather than
13055
+ * reporting the refusal as a failure of each row.
13056
+ */
13057
+ readonly startsDeferredUntilCommit?: true;
12673
13058
  signal(target: WorkflowSignalTarget, signalName: string, payload?: unknown): Promise<{
12674
13059
  readonly eventId: string;
12675
13060
  }>;
@@ -12740,6 +13125,27 @@ declare const WorkflowStartNotExecuted_base: Schema.TaggedErrorClass<WorkflowSta
12740
13125
  incumbentExecutionId: Schema.NullOr<typeof Schema.String>;
12741
13126
  }>;
12742
13127
 
13128
+ /**
13129
+ * What a start handle has become, read once and without waiting.
13130
+ *
13131
+ * `pending` — still queued (or submitted and not yet acknowledged). `accepted`
13132
+ * — the engine owns it under `executionId`; poll that. `not-executed` — it will
13133
+ * never run: the same reasons `WorkflowStartNotExecuted` carries, as a value
13134
+ * rather than a throw, because a reconciler asking "what happened to the start
13135
+ * I recorded" wants an answer, not an exception per row.
13136
+ */
13137
+ export declare type WorkflowStartObservation = {
13138
+ readonly kind: 'pending';
13139
+ } | {
13140
+ readonly kind: 'accepted';
13141
+ readonly executionId: string;
13142
+ } | {
13143
+ readonly kind: 'not-executed';
13144
+ readonly reason: WorkflowStartNotExecuted['reason'];
13145
+ readonly failureId: string | null;
13146
+ readonly incumbentExecutionId: string | null;
13147
+ };
13148
+
12743
13149
  export declare interface WorkflowStartOptions {
12744
13150
  /* Excluded from this release type: preparedExecutionId */
12745
13151
  readonly wait?: boolean;