@voltro/runtime 0.85.0 → 0.87.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.
Files changed (184) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +43 -0
  3. package/THIRD-PARTY-NOTICES.md +864 -253
  4. package/dist/aggregate.js +42 -0
  5. package/dist/aggregateExtrema.js +80 -0
  6. package/dist/aggregateIvm.js +115 -0
  7. package/dist/analyticsMirror.js +228 -0
  8. package/dist/analyticsSink.js +32 -0
  9. package/dist/apiKeyUsage.js +33 -0
  10. package/dist/apiKeys.js +227 -0
  11. package/dist/apiKeysWiring.js +114 -0
  12. package/dist/apiRoleBucketSampler.js +64 -0
  13. package/dist/apiRoleWorkloadHistory.js +56 -0
  14. package/dist/apiRoleWorkloadMetrics.js +78 -0
  15. package/dist/apiRoleWorkloadStorage.js +95 -0
  16. package/dist/approvalBuiltins.js +10 -0
  17. package/dist/approvals.js +262 -0
  18. package/dist/authMiddlewareLayer.js +48 -0
  19. package/dist/bindEvent.js +92 -0
  20. package/dist/bootListener.js +143 -0
  21. package/dist/bootRefusal.js +7 -0
  22. package/dist/bootStoreCodec.js +71 -0
  23. package/dist/businessRules.js +67 -0
  24. package/dist/changeClaimsTable.js +12 -0
  25. package/dist/circuitBreaker.js +1 -0
  26. package/dist/columnOnUpdate.js +23 -0
  27. package/dist/composeAnalytics.js +129 -0
  28. package/dist/computedQuery.js +4 -0
  29. package/dist/computedQueryCache.js +231 -0
  30. package/dist/connectionBuiltins.js +81 -0
  31. package/dist/connectionCredentials.js +66 -0
  32. package/dist/connectionState.js +34 -0
  33. package/dist/connectionVault.js +410 -0
  34. package/dist/connectionsFacade.js +56 -0
  35. package/dist/coordinatedSchedule.js +145 -0
  36. package/dist/crdtHistory.js +138 -0
  37. package/dist/crdtMerge.js +179 -0
  38. package/dist/crdtVersionsTable.js +25 -0
  39. package/dist/credentialBound.js +12 -0
  40. package/dist/crud.js +72 -0
  41. package/dist/dataStore.js +712 -0
  42. package/dist/dataloader.js +61 -0
  43. package/dist/declaredTablesGuard.js +49 -0
  44. package/dist/defineExecutor.js +4 -0
  45. package/dist/dependencyGraph.js +32 -0
  46. package/dist/devices.js +228 -0
  47. package/dist/devicesWiring.js +168 -0
  48. package/dist/dialectReplicationAdapter.js +29 -0
  49. package/dist/dispatcher.js +522 -0
  50. package/dist/effectStore.js +71 -0
  51. package/dist/engineClients.js +24 -0
  52. package/dist/eventBus.js +260 -0
  53. package/dist/eventPublish.js +49 -0
  54. package/dist/events.js +193 -0
  55. package/dist/expectation.js +52 -0
  56. package/dist/expectationEvaluator.js +308 -0
  57. package/dist/experiment.js +96 -0
  58. package/dist/experimentEvaluator.js +245 -0
  59. package/dist/externalizedTasks.js +38 -0
  60. package/dist/fieldCipher.js +130 -0
  61. package/dist/fieldKeyRegistry.js +295 -0
  62. package/dist/fieldKeyRekey.js +286 -0
  63. package/dist/fieldKeyScan.js +136 -0
  64. package/dist/fieldKeyring.js +77 -0
  65. package/dist/fingerprint.js +21 -0
  66. package/dist/finops.js +42 -0
  67. package/dist/finopsAccountant.js +216 -0
  68. package/dist/handlerBody.js +8 -0
  69. package/dist/healthProbes.js +55 -0
  70. package/dist/hot.d.ts +56 -0
  71. package/dist/hot.js +3 -0
  72. package/dist/hotDataStore.js +148 -0
  73. package/dist/hotDataStoreSnapshot.js +98 -0
  74. package/dist/hotDataStoreTables.js +18 -0
  75. package/dist/http-range.d.ts +53 -0
  76. package/dist/http-range.js +52 -0
  77. package/dist/httpClientSsrf.js +24 -0
  78. package/dist/httpClientTracing.js +14 -0
  79. package/dist/httpCompression.js +76 -0
  80. package/dist/httpInputStream.js +82 -0
  81. package/dist/httpKeepAlive.js +12 -0
  82. package/dist/httpRouteMounts.js +48 -0
  83. package/dist/idempotencyStore.js +110 -0
  84. package/dist/idleDetector.js +21 -0
  85. package/dist/index.d.ts +1249 -517
  86. package/dist/index.js +155 -15292
  87. package/dist/insertRequiredColumns.js +19 -0
  88. package/dist/inspectWorkflow.js +1 -0
  89. package/dist/instanceMembership.js +98 -0
  90. package/dist/ivm.js +125 -0
  91. package/dist/kvDataStore.js +86 -0
  92. package/dist/kvFacade.js +38 -0
  93. package/dist/matcher.js +304 -0
  94. package/dist/memoryColumnDefaults.js +11 -0
  95. package/dist/memoryQueryJoins.js +114 -0
  96. package/dist/memorySetOperations.js +43 -0
  97. package/dist/metrics.js +175 -0
  98. package/dist/observability.js +123 -0
  99. package/dist/observedGraph.js +52 -0
  100. package/dist/originGuard.js +116 -0
  101. package/dist/outbox.js +352 -0
  102. package/dist/pluginRefRules.js +65 -0
  103. package/dist/policyGuardResolver.js +55 -0
  104. package/dist/preview.js +62 -0
  105. package/dist/projectedRows.js +12 -0
  106. package/dist/provenance.js +63 -0
  107. package/dist/rangeIndex.js +89 -0
  108. package/dist/rawReadScope.js +17 -0
  109. package/dist/reaction.js +85 -0
  110. package/dist/reactiveConfig.js +11 -0
  111. package/dist/readClassification.js +57 -0
  112. package/dist/readRecorder.js +67 -0
  113. package/dist/readScopePredicate.js +12 -0
  114. package/dist/rebac.js +104 -0
  115. package/dist/rebacInterceptor.js +81 -0
  116. package/dist/registry.js +29 -0
  117. package/dist/relevantFields.js +65 -0
  118. package/dist/replicaHealth.js +42 -0
  119. package/dist/replicaLocality.js +44 -0
  120. package/dist/replicaObservations.js +121 -0
  121. package/dist/replicaSelection.js +32 -0
  122. package/dist/replicatedDataStore.js +257 -0
  123. package/dist/requestLoader.js +7 -0
  124. package/dist/resumeCensus.js +28 -0
  125. package/dist/revalidation.js +22 -0
  126. package/dist/rowFilter.js +82 -0
  127. package/dist/rowStateBytes.js +45 -0
  128. package/dist/rpcBodyCap.js +63 -0
  129. package/dist/rpcConnections.js +83 -0
  130. package/dist/rpcDefectDiagnostics.js +15 -0
  131. package/dist/rpcServer.js +1065 -0
  132. package/dist/rpcWorkloadAdmission.js +50 -0
  133. package/dist/runAsSystem.js +23 -0
  134. package/dist/rywPositionStore.js +119 -0
  135. package/dist/schedule.js +23 -0
  136. package/dist/scheduleBackfillRequests.js +151 -0
  137. package/dist/scheduleClaimsTable.js +11 -0
  138. package/dist/scheduleRunsTable.js +37 -0
  139. package/dist/scheduler.js +840 -0
  140. package/dist/schemaRegistry.js +65 -0
  141. package/dist/secretsResolver.js +35 -0
  142. package/dist/securityHeaders.js +33 -0
  143. package/dist/servePipeline.js +374 -0
  144. package/dist/serverOnlyAudit.js +66 -0
  145. package/dist/serverTracer.js +15 -0
  146. package/dist/serviceCredentials.js +40 -0
  147. package/dist/setReadScopes.js +28 -0
  148. package/dist/singleNodeOrchestrator.js +91 -0
  149. package/dist/snapshotValueCodec.js +46 -0
  150. package/dist/sourceResolution.js +52 -0
  151. package/dist/storeMiddleware.js +882 -0
  152. package/dist/storeQuery.js +204 -0
  153. package/dist/storeRead.js +10 -0
  154. package/dist/subscriber.js +8 -0
  155. package/dist/subscriptionOutbox.js +139 -0
  156. package/dist/subscriptionRegistry.js +82 -0
  157. package/dist/subscriptionResume.js +132 -0
  158. package/dist/subscriptionSocketMetrics.js +65 -0
  159. package/dist/systemSubject.js +5 -0
  160. package/dist/tenantScope.js +11 -0
  161. package/dist/tenantSelection.js +27 -0
  162. package/dist/timeline.js +105 -0
  163. package/dist/traceContext.js +5 -0
  164. package/dist/traceSink.js +63 -0
  165. package/dist/traceSpansTable.js +29 -0
  166. package/dist/traceparent.js +23 -0
  167. package/dist/transactionSubject.js +12 -0
  168. package/dist/trustedProxy.js +155 -0
  169. package/dist/undo.js +129 -0
  170. package/dist/undoBuiltins.js +69 -0
  171. package/dist/undoCapture.js +74 -0
  172. package/dist/undoLogTable.js +16 -0
  173. package/dist/upsertBinding.js +20 -0
  174. package/dist/wakeOrchestrator.js +34 -0
  175. package/dist/wakeRegistry.js +71 -0
  176. package/dist/wakeRouter.js +63 -0
  177. package/dist/wakeSupervisor.js +62 -0
  178. package/dist/wakeupsTable.js +12 -0
  179. package/dist/webSocketGatewayRuntime.js +154 -0
  180. package/dist/webhookVerification.js +18 -0
  181. package/dist/wireColumnStrip.js +84 -0
  182. package/dist/workflowReadBuiltins.js +87 -0
  183. package/dist/workflowRuntime.js +708 -0
  184. package/package.json +19 -7
package/dist/index.d.ts CHANGED
@@ -1,11 +1,31 @@
1
+ import { AggregateQuery } from '@voltro/kv/analytics';
2
+ import { AnalyticsBucket } from '@voltro/kv/analytics';
3
+ import { AnalyticsCapabilityNotSupported } from '@voltro/kv/analytics';
4
+ import { AnalyticsError } from '@voltro/kv/analytics';
5
+ import { AnalyticsEvent } from '@voltro/kv/analytics';
6
+ import { AnalyticsFailure } from '@voltro/kv/analytics';
7
+ import { AnalyticsMetric } from '@voltro/kv/analytics';
8
+ import { AnalyticsMirrorImpl } from '@voltro/kv/analytics';
9
+ import { AnalyticsMirrorRemove } from '@voltro/kv/analytics';
10
+ import { AnalyticsMirrorUpsert } from '@voltro/kv/analytics';
11
+ import { AnalyticsSinkImpl } from '@voltro/kv/analytics';
12
+ import { AnalyticsSinkInfo } from '@voltro/kv/analytics';
13
+ import { AnalyticsTopEntry } from '@voltro/kv/analytics';
1
14
  import { AnyApprovalPolicy } from '@voltro/protocol';
2
15
  import { AnyCheckSpec } from '@voltro/protocol';
3
16
  import { AnyGuardSpec } from '@voltro/protocol';
17
+ import { ApiRoleWindowAssessment } from '@voltro/protocol';
18
+ import { ApiWorkload } from '@voltro/protocol';
4
19
  import { AuthMiddleware } from '@voltro/protocol';
5
20
  import { AuthStrategy } from '@voltro/protocol';
21
+ import { canonicalJson } from '@voltro/protocol';
6
22
  import { CaughtUpVerdict } from '@voltro/database';
7
23
  import { Cause } from 'effect';
8
24
  import { ChangeEvent } from '@voltro/database';
25
+ import { CircuitBreaker } from '@voltro/shared';
26
+ import { CircuitBreakerOptions } from '@voltro/shared';
27
+ import { CircuitOpen } from '@voltro/shared';
28
+ import { CircuitState } from '@voltro/shared';
9
29
  import { classifyConstraintViolation } from '@voltro/database';
10
30
  import { clearRetentions } from '@voltro/database';
11
31
  import { ColumnBuilder } from '@voltro/database';
@@ -28,8 +48,9 @@ import { DeclaredAccess } from '@voltro/protocol';
28
48
  import { DialectId } from '@voltro/database';
29
49
  import { DialectReplicationAdapter } from '@voltro/database';
30
50
  import { Duplex } from 'node:stream';
31
- import { Duration } from 'effect';
32
51
  import { Effect } from 'effect';
52
+ import { EnqueueOptions } from '@voltro/protocol';
53
+ import { EventClientPolicy } from '@voltro/protocol';
33
54
  import { EventDeliverySemantics } from '@voltro/protocol';
34
55
  import { EventDescriptor } from '@voltro/protocol';
35
56
  import { EventKeyInvalid } from '@voltro/protocol';
@@ -54,6 +75,7 @@ import { InferRow } from '@voltro/database';
54
75
  import { InMemoryMetricExporter } from '@opentelemetry/sdk-metrics';
55
76
  import { InMemorySpanExporter } from '@opentelemetry/sdk-trace-base';
56
77
  import { InsertIgnoreResult } from '@voltro/database';
78
+ import { InsertManyOptions } from '@voltro/database';
57
79
  import { InspectedStep } from '@voltro/workflow';
58
80
  import { InspectedWorkflow } from '@voltro/workflow';
59
81
  import { InspectStore } from '@voltro/workflow';
@@ -61,6 +83,7 @@ import { inspectWorkflow } from '@voltro/workflow';
61
83
  import { isForeignKeyViolation } from '@voltro/database';
62
84
  import { isQueryTimeout } from '@voltro/database';
63
85
  import { Kv } from '@voltro/kv';
86
+ import { KvError } from '@voltro/kv';
64
87
  import { KvStoreShape } from '@voltro/kv';
65
88
  import { Layer } from 'effect';
66
89
  import { listRetentionConflicts } from '@voltro/database';
@@ -68,21 +91,31 @@ import { listRetentions } from '@voltro/database';
68
91
  import { Membership } from '@voltro/protocol';
69
92
  import { Metric } from 'effect';
70
93
  import { MetricReader } from '@opentelemetry/sdk-metrics';
94
+ import { MirrorVersion } from '@voltro/kv/analytics';
71
95
  import { MutationIdempotencyScope } from '@voltro/protocol';
96
+ import { newTraceId } from '@voltro/shared';
72
97
  import { NoRowFound } from '@voltro/protocol';
73
98
  import { NoSuchResource } from '@voltro/protocol';
99
+ import { Option } from 'effect';
100
+ import { OutboxEnqueueFacade } from '@voltro/protocol';
101
+ import { OutboxHandlerContext } from '@voltro/protocol';
102
+ import { OutboxHandlerDefinition } from '@voltro/protocol';
74
103
  import { PendingApproval } from '@voltro/protocol';
75
104
  import { PluginHttpRoute } from '@voltro/protocol';
76
105
  import { PluginHttpRouteByteStream } from '@voltro/protocol';
77
106
  import { PluginRefOrphanPolicy } from '@voltro/database';
78
107
  import { Predicate } from '@voltro/database';
79
108
  import { ProcedureWireError } from '@voltro/protocol';
109
+ import { PropertyFilter } from '@voltro/kv/analytics';
80
110
  import { PublicApiSpec } from '@voltro/protocol';
81
111
  import { Query } from '@voltro/database';
82
112
  import { QueryDescriptor } from '@voltro/database';
83
- import { Redis } from 'ioredis';
113
+ import { RedisPubSub } from '@voltro/kv/connection';
84
114
  import { registerRetention } from '@voltro/database';
115
+ import { RequestedTenantRefused } from '@voltro/protocol';
85
116
  import { ResourceMissing } from '@voltro/protocol';
117
+ import { RespClient } from '@voltro/kv/connection';
118
+ import { RespConnections } from '@voltro/kv/connection';
86
119
  import { RestRouteDescriptor } from '@voltro/protocol/rest';
87
120
  import { RetentionConflict } from '@voltro/database';
88
121
  import { RetentionSource } from '@voltro/database';
@@ -94,6 +127,7 @@ import { RowPatch } from '@voltro/protocol';
94
127
  import { Rpc } from 'effect/rpc';
95
128
  import { RpcGroup } from 'effect/rpc';
96
129
  import { RpcInterceptor } from '@voltro/protocol';
130
+ import { RpcReplayAuthorityBinding } from '@voltro/protocol';
97
131
  import { RuleReadStore } from '@voltro/database';
98
132
  import { Sampler } from '@opentelemetry/sdk-trace-base';
99
133
  import { Schedule } from 'effect';
@@ -105,6 +139,9 @@ import { ServerResponse } from 'node:http';
105
139
  import { SpanProcessor } from '@opentelemetry/sdk-trace-base';
106
140
  import { spawn } from 'node:child_process';
107
141
  import { SqlClient } from 'effect/sql';
142
+ import { SqlError } from 'effect/sql/SqlError';
143
+ import { SsrfPolicy } from '@voltro/protocol';
144
+ import { ssrfReason } from '@voltro/protocol';
108
145
  import { StoredTableShape } from '@voltro/database';
109
146
  import { StoreError } from '@voltro/protocol';
110
147
  import { StoreOperationFailed } from '@voltro/protocol';
@@ -125,6 +162,10 @@ import { TenantRowNotFound } from '@voltro/protocol';
125
162
  import { TenantScopeViolation } from '@voltro/protocol';
126
163
  import { tenantSelectionId } from '@voltro/database';
127
164
  import { TenantSelectionStore } from '@voltro/protocol';
165
+ import { TimeBucket } from '@voltro/kv/analytics';
166
+ import { TimeRange } from '@voltro/kv/analytics';
167
+ import { TimeseriesQuery } from '@voltro/kv/analytics';
168
+ import { TopNQuery } from '@voltro/kv/analytics';
128
169
  import { Tracer } from 'effect';
129
170
  import { Unauthenticated } from '@voltro/protocol';
130
171
  import { UpsertOptions } from '@voltro/database';
@@ -167,6 +208,9 @@ declare const AccessDenied_base: Schema.Class<AccessDenied, Schema.TaggedStruct<
167
208
  export declare const actingUserId: (subject: StoreMiddlewareContext["subject"]) => string | null;
168
209
 
169
210
  export declare interface ActionRunnerDeps {
211
+ /** Measures only the synchronous executor entry, never an awaited result. */
212
+ readonly measureSync?: <A>(run: () => A) => A;
213
+ readonly outcomeOutbox?: MutationRunnerDeps['outcomeOutbox'];
170
214
  /** Build the per-call `AppContext` — NO transactional tx (actions do
171
215
  * external I/O and run outside a txn deliberately). */
172
216
  readonly buildContext: (request: ServeRequestContext) => {
@@ -177,8 +221,23 @@ export declare interface ActionRunnerDeps {
177
221
  readonly recordMetric?: MutationRunnerDeps['recordMetric'];
178
222
  /** See {@link MutationRunnerDeps.defaultDeny} — same flag, same refusal. */
179
223
  readonly defaultDeny?: boolean;
224
+ /** See {@link MutationRunnerDeps.settleCacheInvalidations} — an action's
225
+ * writes are the writer's too. */
226
+ readonly settleCacheInvalidations?: () => Promise<void>;
180
227
  }
181
228
 
229
+ /**
230
+ * Make a key active NOW, without waiting for every live process to hold it —
231
+ * for a key replacing a leaked one, where waiting is the larger risk. The
232
+ * processes that lack it are returned: they cannot read what is sealed under
233
+ * it until they are redeployed with it, and each says so on its heartbeat.
234
+ */
235
+ export declare const activateFieldKeyNow: (store: DataStore, keyId: string, holder?: Pick<FieldKeyHolder, "now">) => Promise<{
236
+ readonly from: string | undefined;
237
+ readonly to: string;
238
+ readonly lacking: ReadonlyArray<string>;
239
+ }>;
240
+
182
241
  /**
183
242
  * Live activity counters the runtime exposes to the idle detector. All
184
243
  * return the CURRENT count (0 = quiescent on that axis).
@@ -449,20 +508,7 @@ declare const AggregateNotFound_base: Schema.Class<AggregateNotFound, Schema.Tag
449
508
  readonly name: Schema.String;
450
509
  }>, YieldableError>;
451
510
 
452
- export declare interface AggregateQuery {
453
- readonly event: string;
454
- readonly filter?: PropertyFilter;
455
- readonly metric: AnalyticsMetric;
456
- readonly range: TimeRange;
457
- /**
458
- * Restrict the read to one tenant's events. `useAnalytics()` injects the
459
- * caller's `subject.tenantId` automatically, so handler code never sets
460
- * this; a sink that honours it (e.g. analytics-postgres) then AND-filters
461
- * by tenant so a query can't read across tenants. `null`/absent = unscoped
462
- * (system/cross-tenant read).
463
- */
464
- readonly tenantId?: string | null;
465
- }
511
+ export { AggregateQuery }
466
512
 
467
513
  export declare interface AggregateReadOptions {
468
514
  /**
@@ -471,11 +517,14 @@ export declare interface AggregateReadOptions {
471
517
  * Without it an aggregate can only ever be "the one global roll-up", so every
472
518
  * tenant-/team-/year-scoped roll-up (most real ones) has to stay client-side.
473
519
  * A row matches when EVERY entry matches: a scalar compares by strict
474
- * equality, an array means "one of" (an IN set).
520
+ * equality, an array means "one of" (an IN set), and an object of `gte` /
521
+ * `gt` / `lte` / `lt` is a range on that column (a `Date` bound compares
522
+ * with `Date` and ISO-string values by instant; `null` never matches).
475
523
  *
476
524
  * ```ts
477
525
  * yield* handle.read({ where: { teamId, year: 2026 } })
478
526
  * yield* handle.read({ where: { status: ['open', 'blocked'] } })
527
+ * yield* handle.read({ where: { teamId, day: { gte: from, lte: to } } })
479
528
  * ```
480
529
  *
481
530
  * Deliberately DATA, not a predicate function: it stays serializable, so the
@@ -500,15 +549,9 @@ export declare interface AggregateReadOptions {
500
549
  * - Interval string (`'5m'`, `'1h'`, `'24h'`): the canonical
501
550
  * simple case.
502
551
  * - Cron expression `{ cron: '0 2 * * *', timezone: 'UTC' }`: for
503
- * business-hours / off-peak refresh windows. **Defer to v2** —
504
- * emitted from the spec but not yet honoured by the runner.
552
+ * business-hours / off-peak refresh windows, in the specified timezone.
505
553
  * - On-change debounced `{ interval: '1h', onChange: ['matches'],
506
- * debounceMs: 30_000 }`: near-realtime, source-table-driven. **Defer
507
- * to v2** — same status.
508
- *
509
- * v1 supports interval only. The other shapes are accepted so consumers
510
- * can declare them today + see them honoured when v2 lands without
511
- * touching the spec.
554
+ * debounceMs: 30_000 }`: near-realtime, source-table-driven.
512
555
  */
513
556
  export declare type AggregateRefreshPolicy = string | {
514
557
  readonly interval?: string;
@@ -557,71 +600,17 @@ declare const AggregateStale_base: Schema.Class<AggregateStale, Schema.TaggedStr
557
600
  readonly maxAgeMs: Schema.Number;
558
601
  }>, YieldableError>;
559
602
 
560
- export declare interface AnalyticsBucket {
561
- readonly bucketStart: Date;
562
- readonly value: number;
563
- }
603
+ export { AnalyticsBucket }
564
604
 
565
- /**
566
- * The sink doesn't implement this capability. PostHog returns this
567
- * for `aggregate`/`timeseries`/`topN`. Callers typically
568
- * `Effect.catchTag('AnalyticsCapabilityNotSupported', ...)` to fall
569
- * back to a different sink or report the missing feature.
570
- */
571
- export declare class AnalyticsCapabilityNotSupported extends AnalyticsCapabilityNotSupported_base {
572
- }
573
-
574
- declare const AnalyticsCapabilityNotSupported_base: Schema.Class<AnalyticsCapabilityNotSupported, Schema.TaggedStruct<"AnalyticsCapabilityNotSupported", {
575
- readonly provider: Schema.String;
576
- readonly capability: Schema.String;
577
- }>, YieldableError>;
578
-
579
- /**
580
- * The underlying sink raised an error. `cause` is stringified for
581
- * round-trip safety across the rpc boundary.
582
- */
583
- export declare class AnalyticsError extends AnalyticsError_base {
584
- }
605
+ export { AnalyticsCapabilityNotSupported }
585
606
 
586
- declare const AnalyticsError_base: Schema.Class<AnalyticsError, Schema.TaggedStruct<"AnalyticsError", {
587
- readonly provider: Schema.String;
588
- readonly operation: Schema.String;
589
- readonly cause: Schema.String;
590
- }>, YieldableError>;
607
+ export { AnalyticsError }
591
608
 
592
- /**
593
- * One analytics event. `properties` must be JSON-serialisable —
594
- * individual sinks validate at write time (Postgres stores as JSONB;
595
- * ClickHouse encodes as a JSON string; PostHog forwards verbatim).
596
- */
597
- export declare interface AnalyticsEvent {
598
- /** Event name (e.g. `'match_completed'`, `'page_viewed'`). */
599
- readonly name: string;
600
- /** Subject id (typically `ctx.request.subject.id`) — anonymous when null. */
601
- readonly subjectId?: string | null;
602
- /**
603
- * Owning tenant. Normally you DON'T set this by hand — `useAnalytics()`
604
- * stamps it from the caller's `subject.tenantId` so every event is
605
- * tenant-attributable + every read is tenant-scoped (the multi-tenant
606
- * isolation default). Set it explicitly only for a cross-tenant system
607
- * write. `null` = no tenant (system/anonymous).
608
- */
609
- readonly tenantId?: string | null;
610
- /** Property bag. Values must be JSON-serialisable. */
611
- readonly properties: Readonly<Record<string, unknown>>;
612
- /** When the event occurred. Defaults to server-now when omitted. */
613
- readonly occurredAt?: Date;
614
- }
609
+ export { AnalyticsEvent }
615
610
 
616
- export declare type AnalyticsFailure = AnalyticsError | AnalyticsCapabilityNotSupported;
611
+ export { AnalyticsFailure }
617
612
 
618
- /** Metric to compute. `count` = row count, `unique` = distinct subjectId,
619
- * `sum` / `avg` = numeric aggregation on a property field. */
620
- export declare type AnalyticsMetric = 'count' | 'unique' | {
621
- readonly sum: string;
622
- } | {
623
- readonly avg: string;
624
- };
613
+ export { AnalyticsMetric }
625
614
 
626
615
  export declare interface AnalyticsMirrorHandle {
627
616
  /** Tables actually being mirrored (the sink's `mirror.tables`). Empty
@@ -643,68 +632,9 @@ export declare interface AnalyticsMirrorHandle {
643
632
  readonly stats: () => AnalyticsMirrorStats;
644
633
  }
645
634
 
646
- /**
647
- * Optional CDC-mirror capability. A sink that declares `mirror` opts in
648
- * to receiving the main DataStore's reactive-table changes, so
649
- * analytical queries can JOIN warehouse events against live user data
650
- * (`SELECT … FROM voltro_events e JOIN users u ON …`).
651
- *
652
- * The framework subscribes to `DataStore.onChange` once at boot, filters
653
- * to the tables the sink lists in `tables`, and routes each change here.
654
- * Inserts/updates `upsert` by primary key; deletes `remove`. Every call
655
- * MUST be idempotent — the same change may be re-delivered after a
656
- * reconnect, and the upsert is keyed on `primaryKey` so re-applying a
657
- * row is a no-op-equivalent overwrite.
658
- *
659
- * Idempotent is not enough on its own: re-delivery can also arrive OUT
660
- * OF ORDER, so both methods additionally receive a {@link MirrorVersion}
661
- * and MUST ignore a write whose version is not greater than the version
662
- * already stored for that key (ClickHouse gets this from
663
- * `ReplacingMergeTree(version)`; DuckDB from an `ON CONFLICT … WHERE
664
- * excluded.version > version` guard).
665
- */
666
- export declare interface AnalyticsMirrorImpl {
667
- /** Reactive tables this sink mirrors. The framework only forwards
668
- * changes whose `table` is in this set. */
669
- readonly tables: ReadonlyArray<string>;
670
- /** Primary-key column the sink upserts/deletes by. Defaults to `'id'`
671
- * when omitted. */
672
- readonly primaryKey?: string;
673
- /** Apply an insert/update. Idempotent upsert keyed on `primaryKey`,
674
- * version-guarded by `write.version`. */
675
- readonly upsert: (write: AnalyticsMirrorUpsert) => Effect.Effect<void, AnalyticsFailure>;
676
- /** Apply a delete. Idempotent — removing an absent key is a no-op —
677
- * and version-guarded by `write.version`. */
678
- readonly remove: (write: AnalyticsMirrorRemove) => Effect.Effect<void, AnalyticsFailure>;
679
- /**
680
- * The highest version this sink has PERSISTED for one key — `null` when
681
- * the key has never been written (a tombstoned key still reports its
682
- * tombstone's version; both warehouse sinks keep tombstones for exactly
683
- * this reason).
684
- *
685
- * This is the fleet-scope seed read: a replica that joins mid-stream has
686
- * no per-key history of its own, so before its first write to a key it
687
- * asks the warehouse where the fleet already is and continues from
688
- * there. Without it a joiner would restart the key's versions low and
689
- * every write it produced would be silently rejected by the sink's own
690
- * `version >` guard. Called at most once per key per process (off the
691
- * commit path, inside the per-key drain worker), never per change.
692
- */
693
- readonly maxVersion: (input: {
694
- readonly table: string;
695
- readonly primaryKeyValue: unknown;
696
- }) => Effect.Effect<MirrorVersion | null, AnalyticsFailure>;
697
- }
635
+ export { AnalyticsMirrorImpl }
698
636
 
699
- /** One delete to apply to the mirror. */
700
- export declare interface AnalyticsMirrorRemove {
701
- readonly table: string;
702
- /** Primary-key value of the removed row. */
703
- readonly primaryKeyValue: unknown;
704
- /** See {@link MirrorVersion}. A delete is ordered against upserts of
705
- * the same key by exactly this number. */
706
- readonly version: MirrorVersion;
707
- }
637
+ export { AnalyticsMirrorRemove }
708
638
 
709
639
  /** Counters a caller (boot log, inspect endpoint, test) can read. */
710
640
  export declare interface AnalyticsMirrorStats {
@@ -765,15 +695,7 @@ export declare interface AnalyticsMirrorTunables {
765
695
  readonly versionStateLimit: number;
766
696
  }
767
697
 
768
- /** One insert/update to apply to the mirror. */
769
- export declare interface AnalyticsMirrorUpsert {
770
- readonly table: string;
771
- /** Post-image of the changed row. */
772
- readonly row: Readonly<Record<string, unknown>>;
773
- /** See {@link MirrorVersion} — persist it, compare against it, never
774
- * replace it with a local clock reading. */
775
- readonly version: MirrorVersion;
776
- }
698
+ export { AnalyticsMirrorUpsert }
777
699
 
778
700
  /**
779
701
  * Context.Tag the framework provides at runtime. Handlers grab it via
@@ -787,50 +709,14 @@ export declare class AnalyticsSink extends AnalyticsSink_base {
787
709
 
788
710
  declare const AnalyticsSink_base: Context.ServiceClass<AnalyticsSink, "@voltro/AnalyticsSink", AnalyticsSinkImpl>;
789
711
 
790
- /**
791
- * The runtime contract every analytics provider implements. Plugins
792
- * build a value of this shape inside their factory function and the
793
- * framework wires it under `AnalyticsSink` for handler code to consume.
794
- */
795
- export declare interface AnalyticsSinkImpl {
796
- readonly info: AnalyticsSinkInfo;
797
- readonly track: (event: AnalyticsEvent) => Effect.Effect<void, AnalyticsFailure>;
798
- readonly aggregate: (query: AggregateQuery) => Effect.Effect<number, AnalyticsFailure>;
799
- readonly timeseries: (query: TimeseriesQuery) => Effect.Effect<ReadonlyArray<AnalyticsBucket>, AnalyticsFailure>;
800
- readonly topN: (query: TopNQuery) => Effect.Effect<ReadonlyArray<AnalyticsTopEntry>, AnalyticsFailure>;
801
- /**
802
- * Present when the sink mirrors reactive tables (opt-in via the
803
- * plugin's `mirrorTables` config). Absent → no mirroring; the
804
- * framework skips wiring `DataStore.onChange` for this sink.
805
- */
806
- readonly mirror?: AnalyticsMirrorImpl;
807
- }
712
+ export { AnalyticsSinkImpl }
808
713
 
809
- /**
810
- * Per-sink metadata surfaced via the manifest endpoint + dashboard.
811
- * Lets the operator see at a glance which provider is wired + what
812
- * it supports without grepping app.config.ts.
813
- */
814
- export declare interface AnalyticsSinkInfo {
815
- readonly provider: string;
816
- readonly capabilities: {
817
- readonly track: boolean;
818
- readonly aggregate: boolean;
819
- readonly timeseries: boolean;
820
- readonly topN: boolean;
821
- /** True when the sink mirrors reactive tables into the warehouse so
822
- * analytical queries can JOIN events against live user data. */
823
- readonly mirror: boolean;
824
- };
825
- /** Optional plugin-supplied detail (`{ ingestBufferDepth: 42 }`,
826
- * `{ url: 'https://eu.posthog.com' }`, etc.) — surfaced verbatim. */
827
- readonly detail?: Readonly<Record<string, unknown>>;
828
- }
714
+ export { AnalyticsSinkInfo }
829
715
 
830
716
  /**
831
717
  * What a plugin factory returns at app.config.ts time. The framework
832
718
  * boot path reads `apiConfig.analytics` (an `AnalyticsSinkSpec`), calls
833
- * `spec.build(sqlClient)` to materialise the `AnalyticsSinkImpl`, and
719
+ * the dependency-specific `spec.build` to materialise the `AnalyticsSinkImpl`, and
834
720
  * provides it under the `AnalyticsSink` Tag.
835
721
  *
836
722
  * Specs can declare `tables` to merge into the framework's schema
@@ -839,16 +725,10 @@ export declare interface AnalyticsSinkInfo {
839
725
  * sink is wired but BEFORE rpc routes open (handshakes, dependency
840
726
  * pings, batch-buffer warmups).
841
727
  */
842
- export declare interface AnalyticsSinkSpec {
728
+ declare interface AnalyticsSinkLifecycle {
843
729
  /** Discriminator surfaced in boot logs + inspect ('postgres-analytics',
844
730
  * 'duckdb', 'clickhouse', 'tinybird', 'posthog', 'compose', 'noop'). */
845
731
  readonly kind: string;
846
- /**
847
- * Materialise the sink at boot. Receives the framework's SqlClient
848
- * (bound to the main DataStore by default). Plugins that don't need
849
- * SqlClient ignore the argument.
850
- */
851
- readonly build: (sqlClient: SqlClient.SqlClient) => AnalyticsSinkImpl;
852
732
  /** Optional schema tables the framework should create on first boot.
853
733
  * Erased to `unknown` — the framework only forwards them to the
854
734
  * schema applier, which accepts opaque table descriptors. */
@@ -871,10 +751,16 @@ export declare interface AnalyticsSinkSpec {
871
751
  readonly dispose?: (impl: AnalyticsSinkImpl) => Effect.Effect<void, never>;
872
752
  }
873
753
 
874
- export declare interface AnalyticsTopEntry {
875
- readonly key: string;
876
- readonly value: number;
877
- }
754
+ /** Explicit SQL dependency: independent sinks boot without an application SQL store. */
755
+ export declare type AnalyticsSinkSpec = AnalyticsSinkLifecycle & ({
756
+ readonly sql: 'required';
757
+ readonly build: (sqlClient: SqlClient.SqlClient) => AnalyticsSinkImpl;
758
+ } | {
759
+ readonly sql: 'none';
760
+ readonly build: () => AnalyticsSinkImpl;
761
+ });
762
+
763
+ export { AnalyticsTopEntry }
878
764
 
879
765
  /**
880
766
  * Answer one probe.
@@ -914,6 +800,12 @@ export declare const API_CSP = "default-src 'none'; frame-ancestors 'none'; base
914
800
 
915
801
  export declare const API_KEYS_TABLE = "_voltro_api_keys";
916
802
 
803
+ export declare const API_ROLE_BUCKET_MS: number;
804
+
805
+ export declare const API_ROLE_WINDOW_MS: number;
806
+
807
+ export declare const API_ROLE_WORKLOAD_BUCKETS_TABLE = "_voltro_api_role_workload_buckets";
808
+
917
809
  /** Caller side: the token this app presents to the api it binds as `name`. */
918
810
  export declare const apiBindingTokenEnv: (name: string) => string;
919
811
 
@@ -1097,6 +989,29 @@ export declare interface ApiKeyUsageDelta {
1097
989
  readonly lastUsedAt: number;
1098
990
  }
1099
991
 
992
+ /** A process can select multiple roles. Attribute once to the canonical role set,
993
+ * never once per role (which would multiply the observed loop time). */
994
+ export declare const apiRoleMetricLabel: (roles: ReadonlyArray<string>) => string;
995
+
996
+ export { ApiRoleWindowAssessment }
997
+
998
+ /** Persist one finalized five-minute interval per process incarnation. Seconds
999
+ * are exclusive active-loop increments, NOT cumulative counter snapshots. */
1000
+ export declare interface ApiRoleWorkloadBucket {
1001
+ readonly replicaId: string;
1002
+ readonly startedAt: number;
1003
+ readonly role: string;
1004
+ readonly from: number;
1005
+ readonly until: number;
1006
+ /** Only actual continuous observation can set this true. */
1007
+ readonly continuous: boolean;
1008
+ /** Each required workload must have explicit complete coverage and a value. */
1009
+ readonly workloads: Readonly<Partial<Record<ApiWorkload, {
1010
+ readonly coverage: 'partial' | 'complete';
1011
+ readonly seconds: number;
1012
+ }>>>;
1013
+ }
1014
+
1100
1015
  /**
1101
1016
  * Typed authorization slice on `ctx.access` — the ergonomic, cast-free face of
1102
1017
  * the caller's EFFECTIVE scope set (raw subject scopes ∪ rbac role-derived
@@ -1112,7 +1027,9 @@ export declare interface AppAccess {
1112
1027
  readonly hasAny: (scopes: ReadonlyArray<string>) => boolean;
1113
1028
  /** Effect guard — fails with a typed `ScopeError` when the caller lacks
1114
1029
  * `scope`. `yield* ctx.access.require('notes:write')` at the top of a
1115
- * handler mirrors a descriptor `guards:` entry for in-body branching. */
1030
+ * handler mirrors a descriptor `guards:` entry for in-body branching.
1031
+ * Reauthenticates bound authority when the Effect executes. Authentication
1032
+ * or authority-source failures abort rather than becoming scope decisions. */
1116
1033
  readonly require: (scope: string) => Effect.Effect<void, ScopeError>;
1117
1034
  /** The caller's effective scope set (live — reflects rbac resolution). */
1118
1035
  readonly scopes: ReadonlyArray<string>;
@@ -1508,6 +1425,18 @@ export declare const assertWebhookRoutesDeclareVerification: (routes: ReadonlyMa
1508
1425
  readonly handle: unknown;
1509
1426
  }> | undefined) => void;
1510
1427
 
1428
+ /** Last 24 COMPLETED hours in five-minute buckets (at most five minutes behind
1429
+ * now). Never interpolate a partial boundary bucket or merge process restarts.
1430
+ * Doctor and panels consume this same decision; unknown work is never zero. */
1431
+ export declare const assessApiRoleWorkloadWindow: (input: {
1432
+ readonly now: number;
1433
+ readonly replicaId: string;
1434
+ readonly startedAt: number;
1435
+ readonly role: string;
1436
+ readonly requiredWorkloads: ReadonlyArray<ApiWorkload>;
1437
+ readonly buckets: ReadonlyArray<ApiRoleWorkloadBucket>;
1438
+ }) => ApiRoleWindowAssessment;
1439
+
1511
1440
  /**
1512
1441
  * Assign a subject to a variant — STABLE (same subject ⇒ same variant, always)
1513
1442
  * and BALANCED (proportions converge to the weights over many subjects). The
@@ -1798,7 +1727,7 @@ export declare const bindConnectionCredential: (clientId: number, credential: Co
1798
1727
  * interrupt registry subscriptions use — so one reconnect policy, one devtools
1799
1728
  * view, one connection lifecycle for both primitives.
1800
1729
  */
1801
- export declare const bindEvent: (input: BindEventInput) => Stream.Stream<EventStreamEvent<unknown>, ScopeError | Unauthenticated | NoSuchResource, SubjectService | ConnectionInfo>;
1730
+ export declare const bindEvent: (input: BindEventInput) => Stream.Stream<EventStreamEvent<unknown>, ScopeError | Unauthenticated | RequestedTenantRefused | NoSuchResource, SubjectService | ConnectionInfo>;
1802
1731
 
1803
1732
  export declare interface BindEventInput {
1804
1733
  readonly bus: EventBus;
@@ -1818,9 +1747,12 @@ export declare interface BindEventInput {
1818
1747
  * this bridge must treat it as "no check", not as a guard.
1819
1748
  */
1820
1749
  readonly guards?: DeclaredAccess<unknown> | undefined;
1750
+ /** The descriptor requirement and captured app policy must match exactly. */
1751
+ readonly requiredClientPolicy?: string;
1752
+ readonly clientPolicy?: EventClientPolicy;
1821
1753
  }
1822
1754
 
1823
- 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,
1755
+ 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?: MutationCodec<unknown>, idempotency?: IdempotencyBinding,
1824
1756
  /**
1825
1757
  * This procedure's DECLARED error union (`descriptor.error`).
1826
1758
  *
@@ -1872,7 +1804,12 @@ guards?: ReadonlyArray<unknown> | undefined,
1872
1804
  * (`{ scope: 'x:read', from: 'id' }`) can see which resource was asked for.
1873
1805
  * Passed explicitly rather than read off RuntimeContext, which does not
1874
1806
  * carry it. */
1875
- guardInput?: unknown) => Stream.Stream<Element, Err, SubjectService | ConnectionInfo>;
1807
+ guardInput?: unknown,
1808
+ /** Plugin admission wraps construction once; element guards remain live. */
1809
+ admission?: {
1810
+ readonly tag: string;
1811
+ readonly interceptor?: ServeRpcInterceptor | undefined;
1812
+ }) => Stream.Stream<Element, Err, SubjectService | ConnectionInfo>;
1876
1813
 
1877
1814
  /**
1878
1815
  * Build a `Stream<SubscriptionEvent<T>>` that an effect/rpc streaming
@@ -1959,6 +1896,16 @@ export declare interface BootListener {
1959
1896
  * Installed by the boot path when its store exists, which is after the
1960
1897
  * bind; an app-declared `health.readiness` replaces the whole check. */
1961
1898
  readonly setDependencyPing: (ping: () => Promise<boolean>) => void;
1899
+ /** Required local runtime conditions, independent of app dependency policy.
1900
+ * Checks must be synchronous and cheap. Release removes only this registration. */
1901
+ /** Enable structured API health using captured role/workload identities. */
1902
+ readonly setRoleHealth: (identity: {
1903
+ readonly roles: ReadonlyArray<string>;
1904
+ readonly workloads: ReadonlyArray<string>;
1905
+ }) => void;
1906
+ readonly addReadinessGate: (name: string, check: () => boolean) => () => void;
1907
+ /** Required local progress conditions. App liveness cannot bypass these gates. */
1908
+ readonly addLivenessGate: (name: string, check: () => boolean) => () => void;
1962
1909
  /** Close the socket. Resolves once node reports the listener closed. */
1963
1910
  readonly close: () => Promise<void>;
1964
1911
  }
@@ -2053,6 +2000,40 @@ export declare const buildTracingLayer: (options?: TracingOptions) => Promise<Tr
2053
2000
  * hit on every read. `now` injectable for tests. */
2054
2001
  export declare const cachedBackend: (backend: SecretsBackend, ttlMs?: number, now?: () => number) => SecretsBackend;
2055
2002
 
2003
+ export declare const cachedComputedCall: (args: CachedComputedCallArgs) => Effect.Effect<CachedComputedResult, unknown, never>;
2004
+
2005
+ declare interface CachedComputedCallArgs {
2006
+ readonly cache: ComputedQueryCacheDeps;
2007
+ readonly policy: ComputedQueryCachePolicy;
2008
+ readonly key: string;
2009
+ readonly name: string;
2010
+ readonly sources: ReadonlyArray<string>;
2011
+ readonly output: Schema.Top | undefined;
2012
+ readonly subject: object;
2013
+ readonly rowFilter: RowFilterScope | undefined;
2014
+ readonly ctx: object;
2015
+ readonly signal?: AbortSignal;
2016
+ /** Run the handler to a value against the OBSERVED context and subject. */
2017
+ readonly execute: (observedCtx: object, observedSubject: object) => Promise<unknown>;
2018
+ /** The handler returned a descriptor — the snapshot cache owns that query. */
2019
+ readonly onDescriptor: () => void;
2020
+ readonly isDescriptor: (value: unknown) => boolean;
2021
+ readonly unwrap: (value: unknown) => unknown;
2022
+ }
2023
+
2024
+ /**
2025
+ * Serve one computed call through the cache: a hit, or the handler run under
2026
+ * observation and its result kept — or not — by `decideComputedStore`. The
2027
+ * caller authorizes BEFORE and re-authorizes the delivered value AFTER; this
2028
+ * function only decides what the cache does.
2029
+ */
2030
+ /** A cached call's value, and the tables a live query built from it must also
2031
+ * recompute on (read by the handler, not named in `source:`). */
2032
+ declare interface CachedComputedResult {
2033
+ readonly value: unknown;
2034
+ readonly dependencies: ReadonlyArray<string>;
2035
+ }
2036
+
2056
2037
  /** One leak: a query caching ONE entry across every caller while reading a
2057
2038
  * table whose rows are scoped per tenant. */
2058
2039
  export declare interface CacheScopeLeak {
@@ -2125,13 +2106,7 @@ export declare interface CandidateShape {
2125
2106
  export declare const canonicalInputKey: (input: unknown) => string;
2126
2107
 
2127
2108
  /* Excluded from this release type: canonicalize */
2128
-
2129
- /**
2130
- * Canonical JSON — object keys sorted recursively, so two structurally equal
2131
- * inputs that differ only in key order digest identically. A retry from a
2132
- * different client build must not mint a second approval.
2133
- */
2134
- export declare const canonicalJson: (value: unknown) => string;
2109
+ export { canonicalJson }
2135
2110
 
2136
2111
  export { CaughtUpVerdict }
2137
2112
 
@@ -2151,6 +2126,29 @@ export declare interface CdcDelta {
2151
2126
  readonly new?: Row_3 | null;
2152
2127
  }
2153
2128
 
2129
+ /** What a cell's envelopes can be bound to. */
2130
+ export declare interface CellContext {
2131
+ readonly table: string;
2132
+ readonly column: string;
2133
+ /** The cell's row: its primary key, and every other column (for ids a copy carries). */
2134
+ readonly rowId: unknown;
2135
+ readonly row: Readonly<Record<string, unknown>>;
2136
+ /** Every `.encrypted()` column the app declares, by table. */
2137
+ readonly declared: ReadonlyMap<string, ReadonlySet<string>>;
2138
+ /** Declared renames (`declaredRenames`): the old names a value of this cell may still be bound to. */
2139
+ readonly renames?: ReadonlyMap<string, DeclaredRename>;
2140
+ }
2141
+
2142
+ /** What a cell's re-key did. */
2143
+ export declare interface CellRekey {
2144
+ /** The cell's new text — equal to the input when nothing changed. */
2145
+ readonly text: string;
2146
+ readonly rekeyed: number;
2147
+ readonly current: number;
2148
+ /** Envelopes no candidate address opened — left as they are. */
2149
+ readonly unresolved: number;
2150
+ }
2151
+
2154
2152
  export { ChangeEvent }
2155
2153
 
2156
2154
  /** A mutation invocation's full change-set — the unit of undo. */
@@ -2166,50 +2164,24 @@ export declare interface ChangeSet {
2166
2164
  readonly crossesAction?: boolean;
2167
2165
  }
2168
2166
 
2169
- export declare interface CircuitBreaker {
2170
- /** Run an effect through the breaker. OPEN ⇒ fails fast with CircuitOpen. */
2171
- <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | CircuitOpen, R>;
2172
- /** Current state — reads the Ref. */
2173
- readonly state: Effect.Effect<CircuitState>;
2174
- /** Force the breaker back to closed (clears counters). */
2175
- readonly reset: Effect.Effect<void>;
2176
- }
2177
-
2178
- export declare const CircuitBreaker: {
2179
- /** Construct a breaker. Effect-returning because it allocates a Ref. */
2180
- readonly make: (options: CircuitBreakerOptions) => Effect.Effect<CircuitBreaker>;
2181
- };
2182
-
2183
- export declare interface CircuitBreakerOptions {
2184
- /** Consecutive failures before the breaker opens. */
2185
- readonly failureThreshold: number;
2186
- /** Wait before transitioning open → half-open (Duration or string). */
2187
- readonly resetTimeout: Duration.Input;
2188
- /** Successes required in half-open before closing again. Default 1. */
2189
- readonly halfOpenSuccessThreshold?: number;
2190
- /** Predicate: does this error count toward the threshold? Default: all
2191
- * typed failures count. Interruptions NEVER count (they're not a
2192
- * downstream failure — the caller went away). */
2193
- readonly isFailure?: (error: unknown) => boolean;
2194
- /** Optional name for inspect / metrics + dashboard surfacing. */
2195
- readonly name?: string;
2196
- }
2197
-
2198
2167
  /**
2199
- * Tagged error the breaker fails with while OPEN. Declarable on a
2200
- * mutation / workflow `error:` schema so it marshals typed to the client.
2168
+ * The same checks as {@link verifyFieldKeyring}, writing nothing — for a dry
2169
+ * run. Answers which key the database records as active (`undefined` before
2170
+ * the first boot recorded any) and which one would wait for the fleet.
2201
2171
  */
2202
- export declare class CircuitOpen extends CircuitOpen_base {
2203
- }
2172
+ export declare const checkFieldKeyring: (store: DataStore, keyring: FieldKeyring, tables: Iterable<unknown>) => Promise<{
2173
+ readonly active: string | undefined;
2174
+ readonly requested?: string;
2175
+ readonly notes: ReadonlyArray<string>;
2176
+ }>;
2204
2177
 
2205
- declare const CircuitOpen_base: Schema.Class<CircuitOpen, Schema.TaggedStruct<"CircuitOpen", {
2206
- /** Breaker name (the `name` option, or `'circuit'` when unnamed). */
2207
- readonly name: Schema.String;
2208
- /** Best-effort ms until the breaker next admits a probe call. */
2209
- readonly retryAfterMs: Schema.Number;
2210
- }>, Cause.YieldableError>;
2178
+ export { CircuitBreaker }
2179
+
2180
+ export { CircuitBreakerOptions }
2181
+
2182
+ export { CircuitOpen }
2211
2183
 
2212
- export declare type CircuitState = 'closed' | 'open' | 'half-open';
2184
+ export { CircuitState }
2213
2185
 
2214
2186
  /** How many bucket widths of predecessors a won claim leaves behind. */
2215
2187
  export declare const CLAIM_RETENTION_BUCKETS = 64;
@@ -2382,7 +2354,7 @@ export declare interface CompleteOAuthResult {
2382
2354
  /**
2383
2355
  * Combine multiple analytics specs into one composite spec at
2384
2356
  * app.config.ts time. The framework's boot path materialises each
2385
- * child spec (calls `child.build(sqlClient)`) and wires them through
2357
+ * child spec with its declared SQL dependency and wires them through
2386
2358
  * `composeAnalyticsSinks` so they behave as one logical sink.
2387
2359
  *
2388
2360
  * `track()` fans out to every child; reads route to the first child
@@ -2390,12 +2362,12 @@ export declare interface CompleteOAuthResult {
2390
2362
  *
2391
2363
  * Tables contributed by ANY child get merged. `initialize` effects
2392
2364
  * run sequentially in declaration order; `dispose` effects (teardown)
2393
- * fan out to every child that declares one — only present on the
2365
+ * await each child in reverse order — only present on the
2394
2366
  * composite when at least one child does.
2395
2367
  *
2396
2368
  * analytics: composeAnalytics([
2397
2369
  * postgresAnalytics(), // primary: handles reads
2398
- * posthogAnalytics({ apiKey: '…' }), // forwards track() too
2370
+ * posthogAnalytics({ apiKey: process.env.POSTHOG_API_KEY! }),
2399
2371
  * ])
2400
2372
  */
2401
2373
  export declare const composeAnalytics: (specs: ReadonlyArray<AnalyticsSinkSpec>) => AnalyticsSinkSpec;
@@ -2439,6 +2411,44 @@ export declare interface CompressionOptions {
2439
2411
  readonly minBytes?: number;
2440
2412
  }
2441
2413
 
2414
+ /** Why a call is not looked up at all. */
2415
+ declare type ComputedCacheBypass = 'input-not-encodable' | 'no-tenant' | 'anonymous-subject';
2416
+
2417
+ /**
2418
+ * The entry one call belongs to — or why it has none.
2419
+ *
2420
+ * Every part is something a different answer could hang on: the query and the
2421
+ * build that runs it (a redis cache outlives a deploy, and two releases share
2422
+ * it during a rolling one), the output shape, the ENCODED input (so a `Date`,
2423
+ * a `bigint` or a branded id keys by its wire form, and two spellings of one
2424
+ * input share an entry), the scope's caller part, and the row-filter
2425
+ * visibility the caller's reads of the declared tables resolve to.
2426
+ */
2427
+ export declare const computedCacheKey: (args: ComputedCacheKeyInput) => {
2428
+ readonly key: string;
2429
+ } | {
2430
+ readonly bypass: ComputedCacheBypass;
2431
+ };
2432
+
2433
+ declare interface ComputedCacheKeyInput {
2434
+ readonly name: string;
2435
+ /** The running build — see `codeIdentity` on the boot side. */
2436
+ readonly codeIdentity: string;
2437
+ readonly output: Schema.Top | undefined;
2438
+ readonly input: Schema.Top | undefined;
2439
+ readonly decodedInput: unknown;
2440
+ readonly scope: ComputedCacheScope;
2441
+ readonly subject: {
2442
+ readonly id?: string | null | undefined;
2443
+ readonly type?: string | undefined;
2444
+ readonly tenantId?: string | null | undefined;
2445
+ };
2446
+ readonly rowFilter: RowFilterScope | undefined;
2447
+ readonly declaredSources: ReadonlyArray<string>;
2448
+ }
2449
+
2450
+ declare type ComputedCacheScope = 'subject' | 'tenant' | 'global';
2451
+
2442
2452
  declare interface ComputedQuery {
2443
2453
  readonly __voltroComputed: true;
2444
2454
  /** The initial computed value — emitted verbatim as the first snapshot. */
@@ -2452,6 +2462,56 @@ declare interface ComputedQuery {
2452
2462
  readonly recompute: () => Promise<unknown>;
2453
2463
  }
2454
2464
 
2465
+ /** Is capture on? The request store builder wraps its store when it is. */
2466
+ export declare const computedQueryCacheCaptureInstalled: () => boolean;
2467
+
2468
+ /**
2469
+ * The cache a COMPUTED query's handler invocation is served through. Both boot
2470
+ * paths build it over the app's `Cache` (`wrapDynamic`), and so does
2471
+ * `@voltro/testing`'s `invoke`; absent ⇒ computed queries are never cached.
2472
+ */
2473
+ export declare interface ComputedQueryCacheDeps {
2474
+ readonly wrapDynamic: <A, E>(key: string, options: {
2475
+ readonly ttlMs: number;
2476
+ readonly swrMs?: number | undefined;
2477
+ readonly leaseMs?: number | undefined;
2478
+ readonly label: string;
2479
+ }, compute: Effect.Effect<{
2480
+ readonly value: A;
2481
+ readonly store?: {
2482
+ readonly stored: unknown;
2483
+ readonly tags: ReadonlyArray<string>;
2484
+ } | undefined;
2485
+ readonly notApplicable?: boolean | undefined;
2486
+ }, E, never>, read: (stored: unknown) => Effect.Effect<Option.Option<A>>) => Effect.Effect<{
2487
+ readonly value: A;
2488
+ readonly served: 'hit' | 'stale' | 'miss';
2489
+ }, E, never>;
2490
+ /** Parse the declared `cache:` (same parser as the descriptor path). */
2491
+ readonly policyFor: (cache: {
2492
+ readonly ttl: number | string;
2493
+ readonly swr?: number | string | undefined;
2494
+ readonly scope: ComputedCacheScope;
2495
+ readonly volatile?: boolean | undefined;
2496
+ }) => ComputedQueryCachePolicy | undefined;
2497
+ /** The running build — part of every key, so a deploy never reads another
2498
+ * release's entries out of a shared cache. */
2499
+ readonly codeIdentity: string;
2500
+ readonly maxEntryBytes: number;
2501
+ /** Cluster single-flight lease, when the backend supports one. */
2502
+ readonly leaseMs?: number | undefined;
2503
+ /** Once-per-(query, reason) notice that a result was not kept. */
2504
+ readonly notice: (query: string, reason: string, message: string) => void;
2505
+ }
2506
+
2507
+ /** A computed query's resolved cache policy — ms, parsed by the boot path. */
2508
+ export declare interface ComputedQueryCachePolicy {
2509
+ readonly ttlMs: number;
2510
+ readonly swrMs: number | undefined;
2511
+ readonly scope: ComputedCacheScope;
2512
+ readonly volatile: boolean;
2513
+ }
2514
+
2455
2515
  export declare const CONNECTION_GRANTS_TABLE = "_voltro_connection_grants";
2456
2516
 
2457
2517
  /** What a declaration can learn about the account it just connected. Optional
@@ -2584,6 +2644,7 @@ export { ConstraintViolation }
2584
2644
  export declare type CoordinatedEffect = () => void | CoordinatedTickOutcome | Promise<void | CoordinatedTickOutcome>;
2585
2645
 
2586
2646
  export declare interface CoordinatedScheduleDeps {
2647
+ readonly externalTasks?: ExternalizedTaskRegistry;
2587
2648
  /** The exactly-once gate. `singleCoordinator` for one-process
2588
2649
  * deployments; `makeAdvisoryLockCoordinator(store, replicaId)` for
2589
2650
  * multi-instance SQL stores. Injected so this stays testable with a
@@ -2674,8 +2735,9 @@ export declare interface CoordinatedScheduleDiagnostics {
2674
2735
  }
2675
2736
 
2676
2737
  export declare interface CoordinatedScheduleHandle {
2677
- /** Stop the periodic task. Idempotent. */
2678
- readonly stop: () => void;
2738
+ /** Stop admission immediately; await the returned completion before releasing
2739
+ * storage. Includes timer and external-trigger claims/effects. Idempotent. */
2740
+ readonly stop: () => void | Promise<void>;
2679
2741
  /** The task name (for logging / dedup diagnostics). */
2680
2742
  readonly name: string;
2681
2743
  /**
@@ -3377,6 +3439,9 @@ export declare const decideApprovalInvocation: (input: {
3377
3439
  readonly status: "approved" | "rejected";
3378
3440
  }>;
3379
3441
 
3442
+ /** The app's `.encrypted()` columns, by table. */
3443
+ export declare const declaredEncryptedColumns: (declared: Iterable<unknown>) => ReadonlyMap<string, ReadonlySet<string>>;
3444
+
3380
3445
  /**
3381
3446
  * `unknown` when the executor's failures are all declared; otherwise a type the
3382
3447
  * handler cannot satisfy, whose one property spells out the undeclared tag(s)
@@ -3389,6 +3454,27 @@ UndeclaredErrorTags<D, R>
3389
3454
  readonly undeclaredFailure: `'${UndeclaredErrorTags<D, R>}' is not in this procedure's wire union — add it to the descriptor's \`error:\`, register it through a plugin's \`errorSchemas\`, or map it away (Effect.orDie for a defect)`;
3390
3455
  };
3391
3456
 
3457
+ /** A declared rename of a table with sealed columns: the names its values may still be bound to. */
3458
+ export declare interface DeclaredRename {
3459
+ readonly previousTable?: string;
3460
+ /** New column name → the name it was renamed from. */
3461
+ readonly columns: ReadonlyMap<string, string>;
3462
+ }
3463
+
3464
+ /**
3465
+ * The renames the app declares on tables with `.encrypted()` columns —
3466
+ * `table('new').renamedFrom('old')`, a column's `.renamedFrom('old')`. A rename
3467
+ * is catalog-only, so the rows keep values bound to the old names; the re-key
3468
+ * opens them there and seals them under the new ones.
3469
+ */
3470
+ export declare const declaredRenames: (declared: Iterable<unknown>) => ReadonlyMap<string, DeclaredRename>;
3471
+
3472
+ /** Decode a stored snapshot; `undefined` for anything this version did not
3473
+ * write (an entry from another build reads as a miss). */
3474
+ export declare const decodeSnapshotValue: (stored: unknown) => {
3475
+ readonly value: unknown;
3476
+ } | undefined;
3477
+
3392
3478
  /**
3393
3479
  * Decrypt a value produced by `encryptField` or by an `.encrypted()` column —
3394
3480
  * one encoding, so that sentence is now true in both directions.
@@ -3954,7 +4040,13 @@ export declare class Dispatcher {
3954
4040
  private readonly subscriptionRegistry;
3955
4041
  private readonly matcher;
3956
4042
  private readonly subscriptions;
3957
- private readonly unsubscribeChange;
4043
+ private unsubscribeChange;
4044
+ private closed;
4045
+ private readonly operations;
4046
+ /** Register synchronously, before user code or the first await can run. */
4047
+ private beginOperation;
4048
+ /** Includes pending initial reads, not only already-visible subscriptions. */
4049
+ private readonly interests;
3958
4050
  /**
3959
4051
  * Reverse index: tableName → set of subscription ids whose
3960
4052
  * dependent-table set INCLUDES that table. A change event on table
@@ -3980,12 +4072,18 @@ export declare class Dispatcher {
3980
4072
  /** Query labels already warned about for an undeclared raw read, so a hot
3981
4073
  * subscription logs once rather than once per subscriber. */
3982
4074
  private readonly rawReadWarned;
4075
+ /** The cache fence each written-through read observed before it started. */
4076
+ private readonly readFences;
3983
4077
  private changeEpoch;
3984
4078
  private readonly committedReads;
3985
4079
  /** The CRDT-managed columns of `table` (empty when it has none) — what a
3986
4080
  * subscription's backpressure outbox folds incrementally. */
3987
4081
  crdtColumnsFor(table: string): ReadonlySet<string>;
3988
4082
  constructor(deps: DispatcherDependencies);
4083
+ private measureLoop;
4084
+ private retainInterest;
4085
+ /** One idempotent terminal path for setup failures, revocation and disconnect. */
4086
+ private removeInterest;
3989
4087
  /**
3990
4088
  * REL-14 — a raw read that nothing can invalidate, said out loud.
3991
4089
  *
@@ -4056,6 +4154,9 @@ export declare class Dispatcher {
4056
4154
  * grant comes back.
4057
4155
  */
4058
4156
  private revokeSubscription;
4157
+ /** Remove once, including a pending retry and its active metric. In-flight
4158
+ * async reads check identity again before emitting or scheduling anything. */
4159
+ private removeComputed;
4059
4160
  /** `revokeSubscription` for the computed path. Same reasoning. */
4060
4161
  private revokeComputed;
4061
4162
  /**
@@ -4066,13 +4167,10 @@ export declare class Dispatcher {
4066
4167
  * Returns an `unsubscribe` the caller MUST invoke on teardown.
4067
4168
  */
4068
4169
  subscribeComputed(computed: ComputedQuery, emit: (event: SubscriptionEvent<unknown>) => void, context: RuntimeContext, label?: string): Promise<() => void>;
4069
- /** Re-run a computed subscription's handler; emit a fresh snapshot iff
4070
- * the value changed. A computed value is an arbitrary payload (a scalar,
4071
- * an aggregate object, a non-id-keyed array) — it has no id-keyed row
4072
- * set to diff, so an update ships the full value as a `snapshot`, which
4073
- * the client materialises as a wholesale base replacement. Best-effort:
4074
- * a recompute throw is logged, not propagated, so one failing query
4075
- * can't wedge the change stream. */
4170
+ /** Serialize computed reads. A source change during a pending read asks for
4171
+ * one more read before delivery; an older result cannot overtake newer data.
4172
+ * Ordinary failures are visible in-band and retry independently of changes.
4173
+ * Access withdrawal stays terminal and never enters the retry lane. */
4076
4174
  private recomputeComputed;
4077
4175
  /** Live snapshot of all fingerprinted subscriptions — used by the
4078
4176
  * `/_voltro/inspect/subscriptions` endpoint and DevTools. */
@@ -4087,6 +4185,9 @@ export declare class Dispatcher {
4087
4185
  onSubscriptionsChange(listener: () => void): () => void;
4088
4186
  /** Tear down the change-event listener. Call on server shutdown. */
4089
4187
  close(): void;
4188
+ /** Close admission immediately, then join reads and deliveries before the
4189
+ * owner disposes the store. Do not await this from inside a query callback. */
4190
+ closeAndDrain(): Promise<void>;
4090
4191
  /**
4091
4192
  * Re-run EVERY live subscription, because this replica proved it missed
4092
4193
  * changes it can never recover.
@@ -4112,6 +4213,8 @@ export declare class Dispatcher {
4112
4213
  }
4113
4214
 
4114
4215
  export declare interface DispatcherDependencies {
4216
+ /** Active synchronous live-change work only; asynchronous reads are not timed. */
4217
+ readonly measureSync?: <A>(run: () => A) => A;
4115
4218
  readonly store: DataStore;
4116
4219
  /** CRDT columns per table (schemaRegistry.crdtColumns). Feeds the
4117
4220
  * downstream lane: crdt cells diff as incremental mergeCells ops.
@@ -4157,6 +4260,8 @@ export declare interface DispatcherDependencies {
4157
4260
  export declare const DORMANCY_WAKEUP_TENANT = "default";
4158
4261
 
4159
4262
  export declare interface DrainDeps<R = never> {
4263
+ /** Active synchronous handler entry only; never await a Promise inside this measurement. */
4264
+ readonly measureSync?: <A>(run: () => A) => A;
4160
4265
  readonly store: Pick<DataStore, 'query' | 'update' | 'updateMany' | 'insert' | 'delete'>;
4161
4266
  readonly handlers: ReadonlyMap<string, OutboxHandlerDefinition<R>>;
4162
4267
  /** Execute with the application's services. Required by drainOutbox when R
@@ -4235,7 +4340,7 @@ export declare interface DrainResult {
4235
4340
  readonly dead: number;
4236
4341
  readonly skipped: number;
4237
4342
  /**
4238
- * How many rows this pass had to look at. `0` means the queue is EMPTY, which
4343
+ * How many rows this pass had to look at. `0` means the eligible queue is EMPTY, which
4239
4344
  * a caller cannot otherwise tell from "everything delivered" — both leave
4240
4345
  * `delivered` at whatever it was, and only one of them means the poll has
4241
4346
  * nothing left to do.
@@ -4287,7 +4392,7 @@ export declare interface EffectInsertIgnoreOutcomeStore {
4287
4392
 
4288
4393
  /** The minimal Effect-store surface `insertManyRowsEffect` needs. */
4289
4394
  export declare interface EffectInsertManyStore {
4290
- readonly insertMany: (table: string, rows: ReadonlyArray<Row>) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
4395
+ readonly insertMany: (table: string, rows: ReadonlyArray<Row>, options?: InsertManyOptions) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
4291
4396
  }
4292
4397
 
4293
4398
  /** The minimal Effect-store surface `insertRowEffect` needs. */
@@ -4311,7 +4416,7 @@ export declare interface EffectStoreOps {
4311
4416
  * hand-built descriptor. */
4312
4417
  readonly query: <R = Row>(descriptor: QueryDescriptor<R>) => Effect.Effect<ReadonlyArray<R>, StoreError>;
4313
4418
  readonly insert: (table: string, row: Row) => Effect.Effect<Row, StoreError>;
4314
- readonly insertMany: (table: string, rows: ReadonlyArray<Row>) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
4419
+ readonly insertMany: (table: string, rows: ReadonlyArray<Row>, options?: InsertManyOptions) => Effect.Effect<ReadonlyArray<Row>, StoreError>;
4315
4420
  readonly patchJson: (table: string, primaryKey: string, path: string, value: unknown, additionalPatch?: Readonly<Record<string, unknown>>) => Effect.Effect<Row | null, StoreError>;
4316
4421
  readonly update: (table: string, primaryKey: string, patch: Readonly<Record<string, unknown>>) => Effect.Effect<Row | null, StoreError>;
4317
4422
  readonly updateMany: (table: string, patch: Readonly<Record<string, unknown>>, options: {
@@ -4398,6 +4503,10 @@ export declare const emptySchemaRegistry: SchemaRegistry;
4398
4503
  * should be observed are constructed — `observeStore` decides once, per store. */
4399
4504
  export declare const enableGraphObservation: () => void;
4400
4505
 
4506
+ /** Encode a snapshot for the cache. Throws on a value with no faithful form —
4507
+ * the caller does not store it then. */
4508
+ export declare const encodeSnapshotValue: (value: unknown) => unknown;
4509
+
4401
4510
  /**
4402
4511
  * Encrypt a value with the registered field cipher, in the SAME encoding an
4403
4512
  * `.encrypted()` column uses. Throws if no cipher is registered.
@@ -4429,15 +4538,22 @@ export declare const enforceApproval: (input: {
4429
4538
  readonly traceId?: string | undefined;
4430
4539
  }) => Promise<void>;
4431
4540
 
4432
- export declare interface EnqueueOptions {
4433
- /** Drop this enqueue if an undelivered row already carries the same key. */
4434
- readonly idempotencyKey?: string;
4435
- /** Override the handler's `maxAttempts` for this one effect. */
4436
- readonly maxAttempts?: number;
4437
- /** Delay the first attempt (ms from now). */
4438
- readonly delayMs?: number;
4541
+ /** One connected engine SDK, as it named itself in `x-voltro-sdk`. It proves nothing and grants nothing. */
4542
+ export declare interface EngineClient {
4543
+ readonly id: string;
4544
+ /** `csharp`, `unity`, `godot` or `unreal`. */
4545
+ readonly target: string;
4546
+ readonly version: string;
4547
+ /** SHA-256 of the API surface the SDK was generated from, or null when it did not say. */
4548
+ readonly surface: string | null;
4549
+ readonly connectedAt: number;
4439
4550
  }
4440
4551
 
4552
+ /** The engine SDKs connected to this process now, oldest first. */
4553
+ export declare const engineClientsSnapshot: () => ReadonlyArray<EngineClient>;
4554
+
4555
+ export { EnqueueOptions }
4556
+
4441
4557
  /**
4442
4558
  * Attribute the reads that FOLLOW, in this execution context, to `procedure`.
4443
4559
  *
@@ -5410,6 +5526,12 @@ export declare const externalizedTask: (name: string) => ExternalizedTask | unde
5410
5526
 
5411
5527
  export declare const externalizedTaskNames: () => ReadonlyArray<string>;
5412
5528
 
5529
+ export declare interface ExternalizedTaskRegistry {
5530
+ readonly register: (task: ExternalizedTask) => () => void;
5531
+ readonly get: (name: string) => ExternalizedTask | undefined;
5532
+ readonly names: () => ReadonlyArray<string>;
5533
+ }
5534
+
5413
5535
  /** Build an Effect `ExternalSpan` parent from a `traceparent` header so
5414
5536
  * inbound HTTP work continues the caller's trace. Returns undefined
5415
5537
  * when the header is missing/invalid (no parent → a fresh root span). */
@@ -5473,11 +5595,251 @@ declare type FailureTag<E> = 0 extends (1 & E) ? never : E extends {
5473
5595
  readonly _tag: infer T;
5474
5596
  } ? T extends 'UnknownError' ? never : T extends string ? T : never : never;
5475
5597
 
5598
+ export declare const FIELD_ENCRYPTION_ACTIVE_ENV = "VOLTRO_FIELD_ENCRYPTION_ACTIVE";
5599
+
5600
+ export declare const FIELD_ENCRYPTION_KEY_ENV = "VOLTRO_FIELD_ENCRYPTION_KEY";
5601
+
5602
+ export declare const FIELD_ENCRYPTION_KEYS_ENV = "VOLTRO_FIELD_ENCRYPTION_KEYS";
5603
+
5604
+ export declare const FIELD_ENCRYPTION_PREVIOUS_KEY_ENV = "VOLTRO_FIELD_ENCRYPTION_KEY_PREVIOUS";
5605
+
5606
+ export declare const FIELD_KEY_HEARTBEAT_MS = 10000;
5607
+
5608
+ /** The table of leases on field-encryption keys. */
5609
+ export declare const FIELD_KEY_HOLDERS_TABLE = "_voltro_field_key_holders";
5610
+
5611
+ export declare const FIELD_KEY_LEASE_MS = 30000;
5612
+
5613
+ /** The table of the last field-key count and re-key. */
5614
+ export declare const FIELD_KEY_REPORTS_TABLE = "_voltro_field_key_reports";
5615
+
5616
+ /** The environment names a keyring is read from, for a resolver that fetches them. */
5617
+ export declare const FIELD_KEYRING_ENV_NAMES: readonly ["VOLTRO_FIELD_ENCRYPTION_KEYS", "VOLTRO_FIELD_ENCRYPTION_ACTIVE", "VOLTRO_FIELD_ENCRYPTION_KEY", "VOLTRO_FIELD_ENCRYPTION_KEY_PREVIOUS"];
5618
+
5619
+ /** The table recording each field-encryption key id's state and canary. */
5620
+ export declare const FIELD_KEYS_TABLE = "_voltro_field_keys";
5621
+
5476
5622
  export declare interface FieldChange {
5477
5623
  readonly from: unknown;
5478
5624
  readonly to: unknown;
5479
5625
  }
5480
5626
 
5627
+ /** What this process opened since it started, per key and location — the Governance panel's view. */
5628
+ export declare const fieldDecryptSnapshot: () => ReadonlyArray<{
5629
+ readonly key: string;
5630
+ readonly location: string;
5631
+ readonly ok: number;
5632
+ readonly failed: number;
5633
+ }>;
5634
+
5635
+ /** The last `voltro secret status`: sealed values per key id, over all and per location. */
5636
+ export declare interface FieldKeyCountReport {
5637
+ readonly totals: Readonly<Record<string, number>>;
5638
+ readonly unnamed: number;
5639
+ readonly plaintext: number;
5640
+ readonly unreadable: number;
5641
+ readonly locations: ReadonlyArray<{
5642
+ readonly table: string;
5643
+ readonly column: string;
5644
+ readonly byKey: Readonly<Record<string, number>>;
5645
+ readonly unnamed: number;
5646
+ readonly plaintext: number;
5647
+ }>;
5648
+ }
5649
+
5650
+ /** One key of a keyring: its id and its secret (a passphrase, or 64 hex). */
5651
+ export declare interface FieldKeyEntry {
5652
+ readonly id: string;
5653
+ readonly secret: string;
5654
+ }
5655
+
5656
+ /** What one heartbeat found. `unheld`: the database's active key is one this
5657
+ * process does not hold — it missed its lease while the fleet moved on. */
5658
+ export declare interface FieldKeyHeartbeat {
5659
+ readonly active: string;
5660
+ readonly activated?: {
5661
+ readonly from: string | undefined;
5662
+ readonly to: string;
5663
+ };
5664
+ readonly waiting?: FieldKeyWaiting;
5665
+ readonly unheld: boolean;
5666
+ }
5667
+
5668
+ /** A process's lease. `now` is for tests; the lease is how long a process that
5669
+ * stopped heartbeating is still waited for. */
5670
+ export declare interface FieldKeyHolder {
5671
+ readonly holderId: string;
5672
+ readonly leaseMs?: number;
5673
+ readonly now?: () => number;
5674
+ }
5675
+
5676
+ export declare interface FieldKeyHolderHandle {
5677
+ /** Stop heartbeating, wait for a beat in flight, and give up the lease. */
5678
+ readonly stop: () => Promise<void>;
5679
+ }
5680
+
5681
+ /** A holder id for this process. */
5682
+ export declare const fieldKeyHolderId: () => string;
5683
+
5684
+ /** One process's lease, as recorded — `expiresAt` in the past means it no longer counts. */
5685
+ export declare interface FieldKeyHolderRecord {
5686
+ readonly holderId: string;
5687
+ readonly keyIds: ReadonlyArray<string>;
5688
+ readonly activeKeyId: string;
5689
+ readonly heartbeatAt: Date;
5690
+ readonly expiresAt: Date;
5691
+ }
5692
+
5693
+ export declare interface FieldKeyHolderRow {
5694
+ readonly holderId: string;
5695
+ readonly keyIds: ReadonlyArray<string>;
5696
+ readonly activeKeyId: string;
5697
+ readonly expiresAt: string;
5698
+ }
5699
+
5700
+ /**
5701
+ * The id a key gets when the operator does not name one: `k` + 10 hex
5702
+ * characters of an HMAC over the derived key. Stable for a given key, short
5703
+ * enough to ride in every envelope, and not the key — the fingerprint is keyed
5704
+ * by the key itself, so it says nothing about it to someone without it.
5705
+ */
5706
+ export declare const fieldKeyIdOf: (secret: string) => string;
5707
+
5708
+ /** The last `voltro secret rekey` (also run by `rotate`): what moved, what is left, and whether the active key alone opens everything. */
5709
+ export declare interface FieldKeyRekeyReport {
5710
+ readonly active: string;
5711
+ readonly rekeyed: number;
5712
+ readonly left: number;
5713
+ readonly verified: boolean;
5714
+ }
5715
+
5716
+ export declare interface FieldKeyReports {
5717
+ readonly status?: {
5718
+ readonly reportedAt: Date;
5719
+ readonly report: FieldKeyCountReport;
5720
+ };
5721
+ readonly rekey?: {
5722
+ readonly reportedAt: Date;
5723
+ readonly report: FieldKeyRekeyReport;
5724
+ };
5725
+ }
5726
+
5727
+ /** A field cipher over several keys, each with an id — what `makeFieldKeyring` returns. */
5728
+ export declare interface FieldKeyring extends FieldCipher {
5729
+ /** The key new values are sealed under — the configured active key until
5730
+ * {@link FieldKeyring.activate} names another one the keyring holds. */
5731
+ readonly activeKeyId: string;
5732
+ /** The active key the configuration names. The database may keep another
5733
+ * active until every live process holds this one (`verifyFieldKeyring`). */
5734
+ readonly requestedKeyId: string;
5735
+ /** Every id the keyring holds, the configured active key first. */
5736
+ readonly keyIds: ReadonlyArray<string>;
5737
+ /** Each held key's fingerprint ({@link fieldKeyIdOf} — an HMAC of the key, never
5738
+ * the key), by id: what the boot line and the Governance panel show. */
5739
+ readonly fingerprints: Readonly<Record<string, string>>;
5740
+ /** Seal under one named key, whichever is active (a key's canary). */
5741
+ readonly sealWith: (keyId: string, plaintext: string, binding?: FieldBinding) => string;
5742
+ /** Does the named key open this value? `false` for a key the keyring does not hold. */
5743
+ readonly opensWith: (keyId: string, ciphertext: string, binding?: FieldBinding) => boolean;
5744
+ /** Seal new values under another held key — the database, not the
5745
+ * environment, decides which key is active (`verifyFieldKeyring`). */
5746
+ readonly activate: (keyId: string) => void;
5747
+ }
5748
+
5749
+ /** The keys a process holds, and the one new values are sealed under. */
5750
+ export declare interface FieldKeyringConfig {
5751
+ readonly active: string;
5752
+ readonly keys: ReadonlyArray<FieldKeyEntry>;
5753
+ }
5754
+
5755
+ /** A keyring configuration that cannot be used — named, never containing a key. */
5756
+ export declare class FieldKeyringConfigError extends Error {
5757
+ readonly _tag = "FieldKeyringConfigError";
5758
+ constructor(message: string);
5759
+ }
5760
+
5761
+ /** The boot cannot use this keyring with this database — the message names
5762
+ * ids, columns and the way out, never a key. */
5763
+ export declare class FieldKeyringRefusal extends Error {
5764
+ readonly _tag = "FieldKeyringRefusal";
5765
+ constructor(message: string);
5766
+ }
5767
+
5768
+ /** What a boot's check found and recorded. */
5769
+ export declare interface FieldKeyringVerification {
5770
+ /** The key new values are sealed under, as the database records it. */
5771
+ readonly active: string;
5772
+ /** Ids this boot recorded for the first time. */
5773
+ readonly registered: ReadonlyArray<string>;
5774
+ /** Set when this boot made another key active. */
5775
+ readonly activated?: {
5776
+ readonly from: string | undefined;
5777
+ readonly to: string;
5778
+ };
5779
+ /** A requested key that is not active yet, and the live processes that lack it. */
5780
+ readonly waiting?: FieldKeyWaiting;
5781
+ /** Things worth a log line, never a refusal. */
5782
+ readonly notes: ReadonlyArray<string>;
5783
+ }
5784
+
5785
+ /** One recorded key id — its state and canary, never its key. */
5786
+ export declare interface FieldKeyRow {
5787
+ readonly keyId: string;
5788
+ readonly state: FieldKeyState;
5789
+ readonly canary: string;
5790
+ readonly registeredAt: Date | null;
5791
+ readonly activatedAt: Date | null;
5792
+ readonly replacedAt: Date | null;
5793
+ readonly retiredAt: Date | null;
5794
+ readonly requestedAt: Date | null;
5795
+ }
5796
+
5797
+ /** A key's state. `pending`: held, never active. `active`: new values are sealed
5798
+ * under it — exactly one. `decrypt-only`: was active, replaced; values may still
5799
+ * be sealed under it. `retired`: nothing is sealed under it any more. */
5800
+ export declare type FieldKeyState = 'pending' | 'active' | 'decrypt-only' | 'retired';
5801
+
5802
+ export declare interface FieldKeyStateRow {
5803
+ readonly keyId: string;
5804
+ readonly state: string;
5805
+ readonly activatedAt: string | null;
5806
+ readonly requestedAt: string | null;
5807
+ }
5808
+
5809
+ export declare interface FieldKeyStatus {
5810
+ /** The recorded keys and their states — empty before the first boot recorded any. */
5811
+ readonly keys: ReadonlyArray<FieldKeyStateRow>;
5812
+ /** Every process that holds a lease, live or not (`expiresAt` says which). */
5813
+ readonly holders: ReadonlyArray<FieldKeyHolderRow>;
5814
+ readonly locations: ReadonlyArray<SealedLocation>;
5815
+ /** Envelopes per key id, over every location. */
5816
+ readonly totals: Readonly<Record<string, number>>;
5817
+ readonly unnamed: number;
5818
+ readonly plaintext: number;
5819
+ /** Columns that could not be read — listed, never silently left out of the counts. */
5820
+ readonly unreadable: ReadonlyArray<UnreadableColumn>;
5821
+ }
5822
+
5823
+ /**
5824
+ * Count every sealed value in the database by the key it names. `declared` are
5825
+ * the app's tables: their `.encrypted()` columns are always reported (with
5826
+ * plaintext counted), the rest only where envelopes were found.
5827
+ */
5828
+ export declare const fieldKeyStatus: (dialect: DialectId, declared: Iterable<unknown>) => Effect.Effect<{
5829
+ keys: FieldKeyStateRow[];
5830
+ holders: FieldKeyHolderRow[];
5831
+ locations: SealedLocation[];
5832
+ totals: Record<string, number>;
5833
+ unreadable: UnreadableColumn[];
5834
+ unnamed: number;
5835
+ plaintext: number;
5836
+ }, SqlError, SqlClient.SqlClient>;
5837
+
5838
+ export declare interface FieldKeyWaiting {
5839
+ readonly keyId: string;
5840
+ readonly holders: ReadonlyArray<string>;
5841
+ }
5842
+
5481
5843
  /**
5482
5844
  * Canonical fingerprint over `(table, predicate, indexHint?)`. The
5483
5845
  * optional `indexHint` participates so two subscriptions with the same
@@ -5854,6 +6216,13 @@ export declare interface HealthConfigInput {
5854
6216
  readonly readiness?: () => boolean | Promise<boolean>;
5855
6217
  }
5856
6218
 
6219
+ /**
6220
+ * One heartbeat: renew this process's lease, complete a requested activation
6221
+ * once every live holder holds the key, and seal under the database's active
6222
+ * key from now on. Any holder can complete an activation another one requested.
6223
+ */
6224
+ export declare const heartbeatFieldKeys: (store: DataStore, keyring: FieldKeyring, holder: FieldKeyHolder) => Promise<FieldKeyHeartbeat>;
6225
+
5857
6226
  /** Define a histogram. `boundaries` default to the framework duration buckets. */
5858
6227
  export declare const histogramMetric: (name: string, boundaries?: ReadonlyArray<number>, description?: string) => Metric.Histogram<number>;
5859
6228
 
@@ -5995,9 +6364,10 @@ export declare class InMemoryDataStore implements DataStore {
5995
6364
  * to tell apart from "no such table".
5996
6365
  */
5997
6366
  storedTables(): ReadonlyArray<StoredTableShape>;
6367
+ integrityQuery(descriptor: QueryDescriptor): Promise<ReadonlyArray<Row>>;
5998
6368
  query(descriptor: QueryDescriptor): Promise<ReadonlyArray<Row>>;
5999
6369
  insert(table: string, row: Row): Promise<Row>;
6000
- insertMany(table: string, rows: ReadonlyArray<Row>): Promise<ReadonlyArray<Row>>;
6370
+ insertMany(table: string, rows: ReadonlyArray<Row>, options?: InsertManyOptions): Promise<ReadonlyArray<Row>>;
6001
6371
  patchJson(table: string, primaryKey: RowKey, path: string, value: unknown, additionalPatch?: Readonly<Record<string, unknown>>): Promise<Row | null>;
6002
6372
  update(table: string, primaryKey: RowKey, patch: Readonly<Record<string, unknown>>): Promise<Row | null>;
6003
6373
  delete(table: string, primaryKey: RowKey): Promise<boolean>;
@@ -6029,8 +6399,9 @@ export declare const insertIgnoreRowOutcomeEffect: <T extends AnyWritableTable>(
6029
6399
  readonly outcome: "inserted" | "ignored";
6030
6400
  }, StoreError>;
6031
6401
 
6032
- /** `insertRowEffect`'s batch — every element checked against `InferInsertRow<T>`. */
6033
- export declare const insertManyRowsEffect: <T extends AnyWritableTable>(store: EffectInsertManyStore, table: T, rows: ReadonlyArray<InferInsertRow<T>>) => Effect.Effect<ReadonlyArray<InferRow<T>>, StoreError>;
6402
+ /** `insertRowEffect`'s batch — every element checked against `InferInsertRow<T>`.
6403
+ * `{ returning: 'none' }` resolves to `[]` without reading the rows back. */
6404
+ export declare const insertManyRowsEffect: <T extends AnyWritableTable>(store: EffectInsertManyStore, table: T, rows: ReadonlyArray<InferInsertRow<T>>, options?: InsertManyOptions) => Effect.Effect<ReadonlyArray<InferRow<T>>, StoreError>;
6034
6405
 
6035
6406
  /**
6036
6407
  * Insert a row, typed against the table, on the Effect channel.
@@ -6135,6 +6506,10 @@ export { inspectWorkflow }
6135
6506
 
6136
6507
  export declare const installApprovalGate: (gate: ApprovalGateApi) => void;
6137
6508
 
6509
+ /** Turn on read capture for cached computes — called at boot when any query
6510
+ * declares `cache:`. Until then the request store is not wrapped for it. */
6511
+ export declare const installComputedQueryCacheCapture: () => void;
6512
+
6138
6513
  /**
6139
6514
  * Install the resolver that answers `guards: [{ action, resourceType }]`.
6140
6515
  *
@@ -6238,6 +6613,9 @@ export declare const isExpectationDefinition: (value: unknown) => value is Expec
6238
6613
 
6239
6614
  export declare const isExperimentDefinition: (value: unknown) => value is ExperimentDefinition;
6240
6615
 
6616
+ /** Is this cipher a keyring (ids, per-key seal and open), not a bare cipher? */
6617
+ export declare const isFieldKeyring: (cipher: FieldCipher | undefined) => cipher is FieldKeyring;
6618
+
6241
6619
  export { isForeignKeyViolation }
6242
6620
 
6243
6621
  /**
@@ -6464,7 +6842,7 @@ export declare interface KvFacade {
6464
6842
  readonly service: Effect.Success<typeof Kv>;
6465
6843
  /** The resolved backend kind — for boot logging. */
6466
6844
  readonly backend: 'database' | 'redis' | 'memory';
6467
- /** Tear down the managed runtime (closes a pooled redis connection). */
6845
+ /** Release this consumer runtime; an injected registry retains its pools. */
6468
6846
  readonly dispose: () => Promise<void>;
6469
6847
  }
6470
6848
 
@@ -6473,6 +6851,10 @@ export declare interface KvFacadeOptions {
6473
6851
  readonly store: DataStore;
6474
6852
  /** Defaults to `process.env`. */
6475
6853
  readonly env?: NodeJS.ProcessEnv;
6854
+ readonly backend?: 'database' | 'redis' | 'memory';
6855
+ readonly connectionName?: string;
6856
+ readonly keyPrefix?: string;
6857
+ readonly connections?: RespConnections;
6476
6858
  }
6477
6859
 
6478
6860
  /**
@@ -6594,6 +6976,27 @@ export declare interface LocalityAwareOptions {
6594
6976
  */
6595
6977
  export declare const localityAwareSelector: (options: LocalityAwareOptions) => ReplicaSelector;
6596
6978
 
6979
+ /** One location's outcome. */
6980
+ export declare interface LocationRekey {
6981
+ readonly table: string;
6982
+ readonly column: string;
6983
+ readonly cells: number;
6984
+ readonly rekeyed: number;
6985
+ readonly current: number;
6986
+ readonly unresolved: number;
6987
+ /** Cells the app changed between the read and the write — run again. */
6988
+ readonly changedMeanwhile: number;
6989
+ /** Values that need a re-key in a table with no single-column primary key to address the cell by. */
6990
+ readonly unaddressable: number;
6991
+ }
6992
+
6993
+ /** Read the current key row within its expected tenant under a write fence.
6994
+ * Supply an existing transaction after the application's organization/account
6995
+ * fences and keep it through the protected write. Null matches unassigned
6996
+ * keys only. The internal row uses the normal store codec; never return it in
6997
+ * a public response. This is not bearer verification or an authorization grant. */
6998
+ export declare const lockApiKeyById: (store: DataStore, id: string, tenantId: string | null) => Promise<ApiKeyRow | null>;
6999
+
6597
7000
  export declare interface LogTraceContext {
6598
7001
  readonly traceId: string;
6599
7002
  readonly spanId?: string;
@@ -6665,7 +7068,7 @@ log?: SchedulerLogger) => Coordinator;
6665
7068
  * tampered / wrong-key value AND on a bound value read at another address —
6666
7069
  * both surface as a read error, never silent corruption.
6667
7070
  */
6668
- export declare const makeAesCipher: (key: Buffer) => FieldCipher;
7071
+ export declare const makeAesCipher: (key: Buffer, keyId?: string) => FieldCipher;
6669
7072
 
6670
7073
  export declare const makeApiKeyService: (store: ApiKeyStore, opts?: {
6671
7074
  prefix?: string;
@@ -6693,6 +7096,61 @@ export declare const makeApiKeyUsageFlusher: (store: ApiKeyStore) => (id: string
6693
7096
  readonly lastUsedAt: number;
6694
7097
  }) => Promise<void>;
6695
7098
 
7099
+ /** In-memory, bounded finalized-bucket queue. Current instrumentation is partial;
7100
+ * this collector cannot certify complete workload coverage merely from uptime. */
7101
+ export declare const makeApiRoleBucketSampler: (input: {
7102
+ readonly replicaId: string;
7103
+ readonly startedAt: number;
7104
+ readonly role: string;
7105
+ readonly workloads: ReadonlyArray<ApiWorkload>;
7106
+ readonly epochNow: number;
7107
+ readonly monotonicNow: number;
7108
+ }) => {
7109
+ record(segment: {
7110
+ readonly workload: ApiWorkload;
7111
+ readonly from: number;
7112
+ readonly until: number;
7113
+ }): void;
7114
+ /** Heartbeat every30s. Delays >60s or clock skew >1s conservatively invalidate
7115
+ * affected intervals; never spread elapsed request time across buckets. */
7116
+ advance(monotonicNow: number, epochNow: number): void;
7117
+ pending(): ReadonlyArray<ApiRoleWorkloadBucket>;
7118
+ acknowledge(from: number): void;
7119
+ status: () => {
7120
+ pendingBuckets: number;
7121
+ droppedBuckets: number;
7122
+ rejectedSegments: number;
7123
+ };
7124
+ };
7125
+
7126
+ /** Measures only the synchronous execution of a callback, including throws.
7127
+ * Returning a Promise measures its construction, not its awaited lifetime.
7128
+ * Each resumed async callback must be instrumented separately. No wall-time
7129
+ * request duration may be fed into this counter as a substitute for loop time.
7130
+ * Nested calls on this recorder suspend their parent, so time is exclusive. */
7131
+ export declare const makeApiRoleWorkloadMetrics: (roles: ReadonlyArray<string>, options?: {
7132
+ readonly now?: () => number;
7133
+ readonly onSegment?: (segment: {
7134
+ readonly workload: ApiWorkload;
7135
+ readonly from: number;
7136
+ readonly until: number;
7137
+ }) => void;
7138
+ }) => {
7139
+ role: string;
7140
+ observationErrors: () => number;
7141
+ /** Effect4's tracer context surrounds each synchronous primitive, including
7142
+ * the first, resumed and inherited child work. Preserve the existing tracer;
7143
+ * Promise callbacks outside evaluation still use measureSync explicitly. */
7144
+ observeEffect<A, E, R>(effect: Effect.Effect<A, E, R>, workload: ApiWorkload): Effect.Effect<A, E, R>;
7145
+ measureSync<A>(workload: ApiWorkload, run: () => A): A;
7146
+ /** Local totals, not a 24-hour history or evidence of full instrumentation. */
7147
+ snapshot(): ReadonlyArray<{
7148
+ readonly role: string;
7149
+ readonly workload: ApiWorkload;
7150
+ readonly seconds: number;
7151
+ }>;
7152
+ };
7153
+
6696
7154
  /** Build the `ctx.access` slice for a subject. Reads the effective-scope seam
6697
7155
  * LIVE (via getters/closures) so a scope rbac resolves after context
6698
7156
  * construction is still reflected. Used by the shared AppContext builder AND
@@ -6716,7 +7174,7 @@ export declare interface MakeApprovalGateOptions {
6716
7174
 
6717
7175
  /** Build the `ctx.kv` facade. `KV_BACKEND` picks the backend; unknown values
6718
7176
  * fall back to `database`. */
6719
- export declare const makeAsyncKv: ({ store, env }: KvFacadeOptions) => Promise<KvFacade>;
7177
+ export declare const makeAsyncKv: ({ store, env, backend: configuredBackend, connectionName, keyPrefix, connections }: KvFacadeOptions) => Promise<KvFacade>;
6720
7178
 
6721
7179
  /**
6722
7180
  * The `AuthMiddleware` + `ConnectionInfoMiddleware` pair every rpc surface
@@ -6728,9 +7186,9 @@ export declare const makeAsyncKv: ({ store, env }: KvFacadeOptions) => Promise<K
6728
7186
  * (a no-op for a connection that never re-authenticated);
6729
7187
  * 2. run the FULL chain on the result — strategies, session revocation,
6730
7188
  * `resolveScopes`, the scope cache;
6731
- * 3. record what the strategy verified about the credential's lifetime, so
6732
- * `ConnectionInfo.credentialExpiresAt` reports the token's own `exp` rather
6733
- * than a cookie derivation that only ever saw one auth shape.
7189
+ * 3. pass the verified lifetime through call-local Effect context, so parallel
7190
+ * calls and explicitly unbounded credentials cannot inherit another call's
7191
+ * expiry. Compose the group's pair with `withRpcAuthMiddleware`.
6734
7192
  *
6735
7193
  * Step 1 is the only thing a re-authenticated connection gets. It changes WHICH
6736
7194
  * credential is presented and nothing about how it is judged.
@@ -6835,19 +7293,45 @@ export declare const makeEventPublisher: (ctx: EventPublishContext) => EventPubl
6835
7293
 
6836
7294
  export declare const makeEventsFacade: (options: EventsFacadeOptions) => EventsAppContext;
6837
7295
 
7296
+ /** Pass one instance to a host's scheduler factories and trigger route. */
7297
+ export declare const makeExternalizedTaskRegistry: () => ExternalizedTaskRegistry;
7298
+
6838
7299
  /**
6839
7300
  * Derive a key from a passphrase and build the cipher — with the keys a
6840
- * ROTATION retires, when there are any.
7301
+ * ROTATION retires, when there are any. Ids are derived from the keys
7302
+ * (`fieldKeyIdOf`); a previous key equal to the current one is skipped.
6841
7303
  *
6842
- * Writes use the current key; reads try the current one, then each previous
6843
- * one. GCM authenticates, so a wrong key fails its tag rather than producing
6844
- * garbage, and trying them in turn is safe. Without this, a key change made
6845
- * every value written before it unreadable — measured: every sleeping or
6846
- * suspended run of an `encrypted: true` workflow failed its replay with
6847
- * `MalformedMessage`, and every `.encrypted()` column read failed.
7304
+ * Writes use the current key; reads open a value by the key it names, or by
7305
+ * trying the current one, then each previous one. GCM authenticates, so a
7306
+ * wrong key fails its tag rather than producing garbage. Without this, a key
7307
+ * change made every value written before it unreadable — measured: every
7308
+ * sleeping or suspended run of an `encrypted: true` workflow failed its replay
7309
+ * with `MalformedMessage`, and every `.encrypted()` column read failed.
6848
7310
  */
6849
7311
  export declare const makeFieldCipher: (passphrase: string, previous?: ReadonlyArray<string>) => FieldCipher;
6850
7312
 
7313
+ /**
7314
+ * A cipher over a keyring: new values are sealed under the active key and name
7315
+ * it; a value is opened by the key it names (a lookup), and one written before
7316
+ * values named their key by trying each key, the active one first.
7317
+ *
7318
+ * A named key that is not in the keyring is a refusal that names it, so an
7319
+ * operator reads "sealed under k2026a, which this process does not hold"
7320
+ * instead of a GCM failure. A named key that does not open the value (an id
7321
+ * that was altered) falls back to trying the others — the id is a hint, GCM is
7322
+ * the authority.
7323
+ */
7324
+ export declare const makeFieldKeyring: (config: FieldKeyringConfig, options?: {
7325
+ /**
7326
+ * Refuse to seal until {@link FieldKeyring.activate} has run — the boot's
7327
+ * keyring sets this, so nothing is sealed under the configured key before
7328
+ * the database has said which key is active. A value sealed under a key the
7329
+ * fleet has not accepted is one a replica on the previous configuration
7330
+ * cannot read.
7331
+ */
7332
+ readonly sealOnlyOnceActivated?: boolean;
7333
+ }) => FieldKeyring;
7334
+
6851
7335
  /** Build the fluent `select` / `update` / `delete` entry functions over a
6852
7336
  * backend + scope. Wired into `wrapStoreWithMixinBehaviour` so they hang
6853
7337
  * off `ctx.store` alongside the keyed `query`/`insert`/`update`/`delete`. */
@@ -6870,12 +7354,18 @@ export declare const makeLazyWorkflowFacade: (resolve: () => WorkflowsAppContext
6870
7354
  export declare const makeListConnectionsExecutor: (deps: ConnectionBuiltinDeps) => (_input: Record<string, never>, ctx: ConnectionExecutorCtx) => Promise<ReadonlyArray<ConnectionState_2>>;
6871
7355
 
6872
7356
  /**
6873
- * Build the replay codec from a mutation's `descriptor.output` Schema (call it at
6874
- * the bind site). Both directions fall back to the raw value if the Schema can't
6875
- * round-trip it — a guard for exotic schemas; for a value the handler actually
6876
- * produced, `encodeUnknownSync` never throws. `undefined` schema → no codec.
7357
+ * Build one input/output contract from both declared schemas. Refuse incompatible
7358
+ * values with payload-free errors; never return or log an old raw response
7359
+ * when the current output contract cannot decode it. Input is captured from its schema before keyed acquisition.
6877
7360
  */
6878
- export declare const makeMutationOutputCodec: (outputSchema: Schema.Top | undefined) => MutationOutputCodec<unknown> | undefined;
7361
+ export declare const makeMutationCodec: (inputSchema: Schema.Top, outputSchema: Schema.Top, admit: MutationCodec<unknown>["admit"]) => MutationCodec<unknown>;
7362
+
7363
+ /** Current admission for a keyed unary call, including its cached result.
7364
+ * Pure refresher binding is separate from business interceptors/executors. */
7365
+ export declare const makeMutationReplayAdmission: (procedure: MutationLike, kind: "mutation" | "action", options?: {
7366
+ readonly defaultDeny?: boolean;
7367
+ readonly bindReplayAuthority?: RpcReplayAuthorityBinding | undefined;
7368
+ }) => ((input: unknown, request: ServeRequestContext) => Promise<void>);
6879
7369
 
6880
7370
  /**
6881
7371
  * Build the shared mutation runner. Used by BOTH the rpc WS handler and
@@ -6949,7 +7439,7 @@ export declare const makeOutboxFacade: (deps: OutboxFacadeDeps) => OutboxFacade;
6949
7439
  */
6950
7440
  export declare const makeProcessAdapter: (supervisor: AppSupervisor) => WakeAdapter;
6951
7441
 
6952
- export declare const makeQueryDescriptorProducer: <D>(deps: QueryProducerDeps<D>) => (query: MutationLike, input: unknown) => (requestContext: ServeRequestContext) => D | ComputedQuery | Effect.Effect<D | ComputedQuery, unknown, never>;
7442
+ export declare const makeQueryDescriptorProducer: <D>(deps: QueryProducerDeps<D>, workloadOverride?: "rpc" | "subscriptions") => (query: MutationLike, input: unknown) => (requestContext: ServeRequestContext) => ComputedQuery | D | Effect.Effect<ComputedQuery | D, unknown, never>;
6953
7443
 
6954
7444
  export declare const makeQueryFinalizer: (options: QueryFinalizeOptions) => ((descriptor: QueryDescriptor, subject: {
6955
7445
  readonly tenantId?: string | null;
@@ -6965,16 +7455,13 @@ export declare const makeQueryFinalizer: (options: QueryFinalizeOptions) => ((de
6965
7455
  * the socket keeps delivering rows the subject may no longer read until
6966
7456
  * the client happens to disconnect.
6967
7457
  *
6968
- * So every delivery re-runs the same `checkGuardsEffect` the subscribe-time
6969
- * gate ran — including the async resource-scope resolver, which is where a
6970
- * per-row/per-team revocation actually shows up. Returns `null` when the
6971
- * subject still passes, or the typed `ScopeError` that denied it.
6972
- *
6973
- * Returns a closure that always resolves `null` when the descriptor carries
6974
- * no guards AND default-deny is off, so the caller needs no branch and an
6975
- * unguarded query pays only a resolved promise. Under `defaultDeny` an
6976
- * UNDECIDED descriptor resolves the same typed refusal on every delivery —
6977
- * fail closed on the re-check too, not only at subscribe.
7458
+ * Each delivery refreshes the original authentication chain, subject guards,
7459
+ * dynamic role grants, and resource guards before emitting data. Configured
7460
+ * authentication/scope caches retain their documented invalidation windows.
7461
+ * A revoked credential or grant ends the subscription with a typed refusal.
7462
+ * The original principal and tenant remain fixed; changing either requires a
7463
+ * new subscription. Even unguarded descriptors refresh authentication, while
7464
+ * default-deny keeps rejecting descriptors without a declared access policy.
6978
7465
  */
6979
7466
  export declare const makeQueryReauthorizer: (query: MutationLike, input: unknown, defaultDeny?: boolean) => (subject: Subject) => () => Promise<unknown>;
6980
7467
 
@@ -7391,35 +7878,22 @@ export declare const MIN_LEVEL_RESYNC_MS = 30000;
7391
7878
  /** Mint a fresh service token. `voltro dev` and `voltro secret generate` call this. */
7392
7879
  export declare const mintServiceToken: () => string;
7393
7880
 
7394
- /**
7395
- * Ordering token for one mirrored write.
7396
- *
7397
- * **The sink MUST persist this and MUST NOT invent its own.** It is
7398
- * assigned by the framework at the moment the change leaves the store's
7399
- * change channel — i.e. in COMMIT order — so a write with a lower
7400
- * version is, by construction, an older image of that row. Stamping a
7401
- * version at sink-call time instead (a `Date.now()` inside `upsert`)
7402
- * makes a late-arriving STALE image outrank the fresh one and win
7403
- * permanently; that is the bug this type exists to make unrepresentable.
7404
- *
7405
- * How the number is derived depends on the store's `changeScope`:
7406
- *
7407
- * - `'local'` (one process observes each change): a hybrid clock —
7408
- * wall-clock microseconds forced strictly upward, so it orders within
7409
- * a millisecond and keeps increasing across a restart.
7410
- * - `'fleet'` (every replica observes every change): derived from the
7411
- * CHANGE, not from the receiving process — the warehouse's own max
7412
- * version for the key (read once via {@link AnalyticsMirrorImpl.maxVersion})
7413
- * plus the change's per-key position in the totally-ordered fleet
7414
- * stream. N replicas mirroring the same change therefore stamp the
7415
- * SAME number, and the sink's version guard dedupes the N duplicate
7416
- * writes for free — no leader, no clock, no skew hazard.
7417
- */
7418
- export declare type MirrorVersion = number;
7881
+ export { MirrorVersion }
7419
7882
 
7420
7883
  /** The error `.one()` throws: the factory's, or the framework's `NoRowFound`. */
7421
7884
  export declare const missingRowError: (info: NoRowFoundInfo, onMissing: OnMissingRow | undefined) => unknown;
7422
7885
 
7886
+ /**
7887
+ * Store encoded wire output and decode it against the current output contract.
7888
+ * A failed codec never falls back to an unvalidated raw response.
7889
+ */
7890
+ export declare interface MutationCodec<Output> {
7891
+ readonly input: Schema.Top;
7892
+ readonly admit: (input: unknown, context: RuntimeContext) => Promise<void>;
7893
+ readonly encode: (output: Output) => unknown;
7894
+ readonly decode: (stored: unknown) => Output;
7895
+ }
7896
+
7423
7897
  export declare interface MutationLifecycle {
7424
7898
  readonly afterCommit: (work: () => Promise<unknown>) => void;
7425
7899
  /** Already selected physical, namespace-bound nontransactional store.
@@ -7431,8 +7905,16 @@ export declare interface MutationLifecycle {
7431
7905
  export declare interface MutationLike {
7432
7906
  readonly descriptor: {
7433
7907
  readonly name: string;
7908
+ readonly undo?: {
7909
+ readonly capture: false;
7910
+ readonly reason: string;
7911
+ } | undefined;
7434
7912
  readonly source?: string | ReadonlyArray<string> | undefined;
7435
7913
  readonly guards?: ReadonlyArray<AnyCheckSpec> | undefined;
7914
+ /** Query only — read by the computed-query cache (`computedQueryCache.ts`). */
7915
+ readonly cache?: QueryCacheLike | undefined;
7916
+ readonly input?: Schema.Top | undefined;
7917
+ readonly output?: Schema.Top | undefined;
7436
7918
  /** The second-human control (mutation/action only). Enforced by
7437
7919
  * `enforceApprovalGate`, immediately after `enforceGuards`. */
7438
7920
  readonly requiresApproval?: AnyApprovalPolicy | undefined;
@@ -7447,21 +7929,20 @@ export declare interface MutationLike {
7447
7929
  executor(input: unknown, ctx: unknown): unknown;
7448
7930
  }
7449
7931
 
7450
- /**
7451
- * Encode/decode a mutation's output for idempotent replay. On a FRESH call the
7452
- * WIRE form (`encode`) is stored, so a later replay `decode`s it back to the exact
7453
- * Output the handler would have returned and the rpc layer re-encodes it
7454
- * identically. Storing the DECODED Output directly would corrupt `Date`/etc.
7455
- * fields through the store's JSON round-trip (encode there expects a `Date`, not
7456
- * the ISO string a round-trip produced). Built from `descriptor.output` at the
7457
- * call site; both fns fall back to the raw value if the Schema can't round-trip.
7458
- */
7459
- export declare interface MutationOutputCodec<Output> {
7460
- readonly encode: (output: Output) => unknown;
7461
- readonly decode: (stored: unknown) => Output;
7462
- }
7463
-
7464
7932
  export declare interface MutationRunnerDeps {
7933
+ /** Measures only the synchronous executor entry, never an awaited result. */
7934
+ readonly measureSync?: <A>(run: () => A) => A;
7935
+ readonly outcomeOutbox?: (request: ServeRequestContext) => OutboxEnqueueFacade | undefined;
7936
+ /** A failure aborts the business transaction; transient contention replays
7937
+ * executor and hook together. Never perform external I/O here. */
7938
+ readonly beforeMutationCommit?: ServeMutationCommitHook | undefined;
7939
+ /**
7940
+ * Resolves once the cache invalidations this process started have reached
7941
+ * the cache. Awaited after commit, BEFORE the mutation answers — without it
7942
+ * the writer's next read raced its own invalidation and was served the
7943
+ * pre-write entry. Both boot paths pass `wireCacheInvalidation`'s `settled`.
7944
+ */
7945
+ readonly settleCacheInvalidations?: () => Promise<void>;
7465
7946
  readonly store: TransactionalStore;
7466
7947
  /** Select and provision the request's physical store before opening its
7467
7948
  * transaction. Resolved once, including across retries and post-commit folds. */
@@ -7484,6 +7965,7 @@ export declare interface MutationRunnerDeps {
7484
7965
  /** Build the per-call `AppContext` bound to the transactional `tx`. */
7485
7966
  readonly buildContext: (request: ServeRequestContext, tx: unknown, lifecycle?: MutationLifecycle) => {
7486
7967
  readonly store: unknown;
7968
+ readonly outbox?: OutboxEnqueueFacade;
7487
7969
  };
7488
7970
  /** Run an Effect-returning executor with the per-request store layer. */
7489
7971
  readonly runEffect: (effect: Effect.Effect<unknown, unknown, never>, store: unknown) => Promise<unknown>;
@@ -7525,6 +8007,19 @@ export declare interface MutationStore extends DataStore {
7525
8007
  hardDelete(table: string, primaryKey: RowKey): Promise<boolean>;
7526
8008
  }
7527
8009
 
8010
+ /**
8011
+ * The encoding a body of `size` bytes would be compressed with — `undefined`
8012
+ * unless (enabled ∧ type compressible ∧ size ≥ threshold ∧ the client accepts
8013
+ * an encoding). Lets a caller that has not read the body yet (a static file
8014
+ * known only by `stat`) take the same decision `maybeCompress` takes.
8015
+ */
8016
+ export declare const negotiatedCompression: (input: {
8017
+ readonly size: number;
8018
+ readonly contentType: string | undefined;
8019
+ readonly acceptEncoding: string | undefined;
8020
+ readonly options?: CompressionOptions | undefined;
8021
+ }) => NegotiatedEncoding | undefined;
8022
+
7528
8023
  export declare type NegotiatedEncoding = 'br' | 'gzip';
7529
8024
 
7530
8025
  /** Pick the encoding the client accepts — brotli preferred, gzip second,
@@ -7532,24 +8027,7 @@ export declare type NegotiatedEncoding = 'br' | 'gzip';
7532
8027
  * (a client sending both accepts both). */
7533
8028
  export declare const negotiateEncoding: (acceptEncoding: string | undefined) => NegotiatedEncoding | undefined;
7534
8029
 
7535
- /**
7536
- * A fresh trace id for work that has NO incoming span to continue — a webhook
7537
- * delivery, a schedule firing, a devtools invoke, a REST or gRPC entry point.
7538
- *
7539
- * 128 random bits as 32 lowercase hex, the shape `TRACEPARENT_RE` above accepts
7540
- * and the shape a collector, a log pipeline or `voltro traces` can join on.
7541
- *
7542
- * The reason this exists as ONE function: every entry point that minted its own
7543
- * had drifted somewhere different, and three of the shapes were not ids at all.
7544
- * `incoming:<webhookId>`, `reaction:<workflow>` and the literal
7545
- * `'webhooks:trigger'` are CONSTANTS — they were the caller's `source` label
7546
- * copied into the id field, so every delivery a process ever handled shared one
7547
- * trace and the waterfall merged unrelated work. `public-`/`grpc-`/`rest-` plus
7548
- * eight base36 characters carried ~41 bits, which collides long before a busy
7549
- * day is over. The entry-point kind is not lost by fixing this: it lives in the
7550
- * `source` field beside the id, which is where it was already being written.
7551
- */
7552
- export declare const newTraceId: () => string;
8030
+ export { newTraceId }
7553
8031
 
7554
8032
  /**
7555
8033
  * The backoff curve, extracted so it can be asserted directly — a schedule
@@ -7666,6 +8144,14 @@ export declare interface NoRowFoundInfo {
7666
8144
  readonly found: number;
7667
8145
  }
7668
8146
 
8147
+ /** Record a non-table input of the cached compute in flight, if any. Called by
8148
+ * the framework surfaces that reach outside the database. */
8149
+ export declare const noteCacheVolatile: (reason: string) => void;
8150
+
8151
+ /** Note that the query in flight depends on `table` without reading it
8152
+ * through `ctx.store`. */
8153
+ export declare const noteDependency: (table: string) => void;
8154
+
7669
8155
  /** Note one read against the in-flight procedure. No scope → nothing happens. */
7670
8156
  export declare const noteRead: (descriptor: QueryDescriptor) => void;
7671
8157
 
@@ -7695,6 +8181,45 @@ export declare interface Notification {
7695
8181
  readonly newMatched: boolean;
7696
8182
  }
7697
8183
 
8184
+ /** What a cross-environment restore did to the sealed values it cannot read. */
8185
+ export declare interface NullSealedReport {
8186
+ readonly nulled: ReadonlyArray<{
8187
+ readonly table: string;
8188
+ readonly column: string;
8189
+ readonly count: number;
8190
+ }>;
8191
+ readonly unreadable: ReadonlyArray<{
8192
+ readonly table: string;
8193
+ readonly column: string;
8194
+ readonly count: number;
8195
+ }>;
8196
+ /** Recorded key ids removed: they came with the restored data and this environment does not hold them. */
8197
+ readonly forgottenKeys: ReadonlyArray<string>;
8198
+ readonly unreadableColumns: ReadonlyArray<UnreadableColumn>;
8199
+ }
8200
+
8201
+ /**
8202
+ * After restoring another environment's database: write NULL for every whole
8203
+ * sealed value no configured key opens — the source ciphertext is useless here
8204
+ * and users re-enter it — count the sealed copies inside other values (they
8205
+ * cannot be nulled), and forget the restored key records and leases this
8206
+ * environment does not hold, so the next boot records its own keys.
8207
+ */
8208
+ export declare const nullUnreadableSealedValues: (dialect: DialectId, keyring: FieldKeyring | undefined, declared: Iterable<unknown>) => Effect.Effect<{
8209
+ nulled: {
8210
+ table: string;
8211
+ column: string;
8212
+ count: number;
8213
+ }[];
8214
+ unreadable: {
8215
+ table: string;
8216
+ column: string;
8217
+ count: number;
8218
+ }[];
8219
+ forgottenKeys: string[];
8220
+ unreadableColumns: UnreadableColumn[];
8221
+ }, SqlError, SqlClient.SqlClient>;
8222
+
7698
8223
  export declare interface OAuth2ConnectionDefinition extends ConnectionDefinitionCommon {
7699
8224
  readonly kind: 'oauth2';
7700
8225
  readonly authorizeUrl: string;
@@ -7735,6 +8260,17 @@ export declare type OAuthClientCredential = string | (() => string);
7735
8260
 
7736
8261
  export declare const oauthCredentialValue: (credential: OAuthClientCredential) => string;
7737
8262
 
8263
+ /** Preserve the caller's environment, Exit and cancellation. Observation is
8264
+ * installed before the body's first primitive; it creates no detached runtime. */
8265
+ export declare const observeApiRoleEffect: <A, E>(effect: Effect.Effect<A, E, never>, metrics: ReturnType<typeof makeApiRoleWorkloadMetrics>, workload: ApiWorkload) => Effect.Effect<A, E, never>;
8266
+
8267
+ /**
8268
+ * Test seam: a ConnectionInfo layer that hands every request's headers to
8269
+ * `observe` and reports only the client id. It never authenticates and is not a
8270
+ * boot path; it lives here so ConnectionInfo keeps one construction site.
8271
+ */
8272
+ export declare const observeConnectionHeaders: (observe: (headers: Readonly<Record<string, string | undefined>>, clientId: number) => void) => Layer.Layer<ConnectionInfoMiddleware>;
8273
+
7738
8274
  /** One recorded `(procedure → table, op)` edge. */
7739
8275
  export declare interface ObservedEdge {
7740
8276
  readonly tag: string;
@@ -7818,6 +8354,16 @@ export declare type OnMissingRow = (info: NoRowFoundInfo) => unknown;
7818
8354
  */
7819
8355
  export declare const onProcessShutdown: (hook: () => void | Promise<void>) => (() => void);
7820
8356
 
8357
+ /**
8358
+ * Open every envelope in one cell with `keyring` — each under the address it
8359
+ * was sealed under, found the same way a re-key finds it. A keyring holding the
8360
+ * active key alone answers "does anything still need another key?".
8361
+ */
8362
+ export declare const openCell: (text: string, keyring: FieldKeyring, context: CellContext) => {
8363
+ readonly opened: number;
8364
+ readonly unopened: number;
8365
+ };
8366
+
7821
8367
  /** Thrown by `.expectVersion(n).set(...)` when the optimistic-lock guard
7822
8368
  * matched no row (the row was concurrently updated or deleted). */
7823
8369
  export declare class OptimisticLockError extends OptimisticLockError_base {
@@ -8013,14 +8559,14 @@ export declare const outboxAttemptsTable: TableLike;
8013
8559
  * twice because of us or because of them" becomes unanswerable. */
8014
8560
  export declare type OutboxAttemptTrigger = 'automatic' | 'manual';
8015
8561
 
8016
- export declare interface OutboxFacade {
8017
- /**
8018
- * Persist the intent to run `effect` after this transaction commits.
8019
- *
8020
- * Returns the outbox row id, which doubles as the delivery id a client can
8021
- * watch to render external-side-effect progress ("saving… syncing… synced").
8022
- */
8023
- enqueue(effect: string, payload: Record<string, unknown>, options?: EnqueueOptions): Promise<string>;
8562
+ /** Declared-event publication for an outbox attempt, scoped to its queued tenant.
8563
+ * This service provides no request subject or store access. */
8564
+ export declare class OutboxEventPublisher extends OutboxEventPublisher_base {
8565
+ }
8566
+
8567
+ declare const OutboxEventPublisher_base: Context.ServiceClass<OutboxEventPublisher, "@voltro/OutboxEventPublisher", EventPublisher>;
8568
+
8569
+ export declare interface OutboxFacade extends OutboxEnqueueFacade {
8024
8570
  /**
8025
8571
  * Re-arm one entry for delivery NOW, on purpose, attributed to the caller.
8026
8572
  *
@@ -8065,25 +8611,9 @@ export declare interface OutboxFacadeDeps {
8065
8611
  readonly now?: () => Date;
8066
8612
  }
8067
8613
 
8068
- export declare interface OutboxHandlerContext {
8069
- /** Stable identity of this delivery intent, preserved across retries. */
8070
- readonly outboxId: string;
8071
- /** Caller-supplied enqueue key, or null. Unlike outboxId this can be reused
8072
- * for a distinct intent after an earlier intent has been delivered. */
8073
- readonly idempotencyKey: string | null;
8074
- readonly payload: Record<string, unknown>;
8075
- readonly attempt: number;
8076
- readonly subjectId: string | null;
8077
- readonly tenantId: string | null;
8078
- readonly traceId: string | null;
8079
- }
8614
+ export { OutboxHandlerContext }
8080
8615
 
8081
- export declare interface OutboxHandlerDefinition<R = never> {
8082
- readonly effect: string;
8083
- readonly handler: (ctx: OutboxHandlerContext) => Promise<unknown> | Effect.Effect<unknown, unknown, R>;
8084
- /** Give up after this many attempts, then dead-letter. Default 8. */
8085
- readonly maxAttempts?: number;
8086
- }
8616
+ export { OutboxHandlerDefinition }
8087
8617
 
8088
8618
  /** What the pump hands events to — the `emit` of a `Stream.asyncScoped`. */
8089
8619
  export declare interface OutboxSink<T> {
@@ -8129,6 +8659,9 @@ export declare interface PairInput {
8129
8659
  */
8130
8660
  export declare const parseApprovalInterval: (spec: string) => number | null;
8131
8661
 
8662
+ /** `unity/0.1.0; surface=<64 hex>` → its parts; anything else is not an engine SDK. */
8663
+ export declare const parseEngineSdkHeader: (value: string) => Omit<EngineClient, "id" | "connectedAt"> | null;
8664
+
8132
8665
  /** Parse a `traceparent` header. Returns null when malformed or when
8133
8666
  * the all-zero invalid ids are present (per the spec those are
8134
8667
  * treated as "no parent"). */
@@ -8333,8 +8866,7 @@ export declare type ProbeKind = 'liveness' | 'readiness' | 'startup';
8333
8866
  * columns, which have no wire representation at all. */
8334
8867
  export declare const projectConnectionState: (definition: ConnectionDefinition, row: AnyRow_2 | undefined) => ConnectionState_2;
8335
8868
 
8336
- /** Exact-match property filter. Values are AND'd. */
8337
- export declare type PropertyFilter = Readonly<Record<string, string | number | boolean | null>>;
8869
+ export { PropertyFilter }
8338
8870
 
8339
8871
  export declare interface ProvenanceActor {
8340
8872
  readonly id: string | null;
@@ -8488,8 +9020,25 @@ export declare interface PumpOptions {
8488
9020
  */
8489
9021
  export declare const pumpOutbox: <T>(outbox: SubscriptionOutbox<T>, sink: OutboxSink<T>, label: string, options?: PumpOptions) => Promise<void>;
8490
9022
 
9023
+ /** A query's declared `cache:` block, structurally — see `QueryCacheConfig`. */
9024
+ export declare interface QueryCacheLike {
9025
+ readonly ttl: number | string;
9026
+ readonly swr?: number | string | undefined;
9027
+ readonly scope: ComputedCacheScope;
9028
+ readonly volatile?: boolean | undefined;
9029
+ }
9030
+
9031
+ /** A query's declared `cache:`, parsed — `undefined` when the ttl does not
9032
+ * parse (the cache is then off for that query; `voltro doctor` says so). */
9033
+ export declare const queryCachePolicy: (cache: {
9034
+ readonly ttl: number | string;
9035
+ readonly swr?: number | string | undefined;
9036
+ readonly scope: ComputedCacheScope;
9037
+ readonly volatile?: boolean | undefined;
9038
+ }) => ComputedQueryCachePolicy | undefined;
9039
+
8491
9040
  /**
8492
- * The two scopes, composed once, for every path that finalises a descriptor.
9041
+ * The read scopes, composed once, for every path that finalises a descriptor.
8493
9042
  *
8494
9043
  * **The primitives above were extracted so there is "no second copy that could
8495
9044
  * drift" — and then the COMPOSITION became the second copy.** `voltro dev`
@@ -8515,6 +9064,8 @@ export declare const pumpOutbox: <T>(outbox: SubscriptionOutbox<T>, sink: Outbox
8515
9064
  export declare interface QueryFinalizeOptions {
8516
9065
  readonly tenantScopedTables: ReadonlySet<string>;
8517
9066
  readonly softDeleteScopedTables: ReadonlySet<string>;
9067
+ /** Tables carrying expires(); hosts derive this set from the schema registry. */
9068
+ readonly expiresScopedTables?: ReadonlySet<string>;
8518
9069
  readonly observe?: {
8519
9070
  /** Before scoping — sees what the handler asked for. */
8520
9071
  readonly beforeScope?: (descriptor: QueryDescriptor, subject: {
@@ -8532,6 +9083,9 @@ export declare type QueryLike<R = Row_7> = QueryDescriptor<R> | {
8532
9083
  };
8533
9084
 
8534
9085
  export declare interface QueryProducerDeps<D> {
9086
+ readonly workloadMetrics?: ReturnType<typeof makeApiRoleWorkloadMetrics>;
9087
+ /** See {@link ComputedQueryCacheDeps}. */
9088
+ readonly computedCache?: ComputedQueryCacheDeps;
8535
9089
  readonly buildContext: (request: ServeRequestContext) => {
8536
9090
  readonly store: unknown;
8537
9091
  };
@@ -8844,6 +9398,19 @@ export declare interface ReactiveSocketTunables {
8844
9398
  * (unit tests, a bare library use). */
8845
9399
  export declare const reactiveSocketTunables: () => ReactiveSocketTunables;
8846
9400
 
9401
+ /** Bounded exact-incarnation read. Corruption/read failure is raised, never
9402
+ * flattened to no observations. Membership expiry does not delete this history. */
9403
+ export declare const readApiRoleWorkloadWindow: (store: DataStore, input: {
9404
+ readonly now: number;
9405
+ readonly replicaId: string;
9406
+ readonly startedAt: number;
9407
+ readonly role: string;
9408
+ readonly requiredWorkloads: ReadonlyArray<ApiWorkload>;
9409
+ }) => Promise<{
9410
+ buckets: ApiRoleWorkloadBucket[];
9411
+ assessment: ApiRoleWindowAssessment;
9412
+ }>;
9413
+
8847
9414
  export declare interface ReadClassification {
8848
9415
  /** Tables whose ROWS can reach the caller: the queried table and its joins. */
8849
9416
  readonly composed: ReadonlySet<string>;
@@ -8851,6 +9418,14 @@ export declare interface ReadClassification {
8851
9418
  readonly restricting: ReadonlySet<string>;
8852
9419
  }
8853
9420
 
9421
+ /** Every recorded lease, live or not. */
9422
+ export declare const readFieldKeyHolders: (store: DataStore) => Promise<ReadonlyArray<FieldKeyHolderRecord>>;
9423
+
9424
+ export declare const readFieldKeyReports: (store: DataStore) => Promise<FieldKeyReports>;
9425
+
9426
+ /** The recorded keys, without decrypting anything. */
9427
+ export declare const readFieldKeys: (store: DataStore) => Promise<ReadonlyArray<FieldKeyRow>>;
9428
+
8854
9429
  /** First-or-null for a boot DataStore or a query-only tuple source. It invokes
8855
9430
  * the supplied query path, preserving that path's filters and codecs. A raw
8856
9431
  * driver remains raw; this helper does not add request scoping. */
@@ -8990,6 +9565,12 @@ export declare const recordExternalMissed: (name: string, count?: number) => voi
8990
9565
 
8991
9566
  export declare const recordExternalTrigger: (name: string, outcome: "accepted" | "duplicate" | "noOccurrence" | "ahead" | "notExternal" | "unknownSchedule") => void;
8992
9567
 
9568
+ /** One open of a sealed value. `key` opened it (`ok`) or was named by it (`failed`). */
9569
+ export declare const recordFieldDecrypt: (key: string, location: string, outcome: "ok" | "failed") => void;
9570
+
9571
+ /** Record the last count or re-key — one row per kind, replaced each time. */
9572
+ export declare const recordFieldKeyReport: <K extends keyof FieldKeyReports>(store: DataStore, kind: K, report: NonNullable<FieldKeyReports[K]>["report"], at?: Date) => Promise<void>;
9573
+
8993
9574
  /**
8994
9575
  * Record one emitted event into the identity's ring. Snapshots RESET the ring
8995
9576
  * (the snapshot's revision becomes the new replay base — a client holding an
@@ -9120,76 +9701,32 @@ export declare const redactColumns: <R extends Row>(rows: ReadonlyArray<R>, reda
9120
9701
  /** Blank sensitive-looking columns. Returns a new object; null passes through. */
9121
9702
  export declare const redactRow: (row: Row_2 | null | undefined) => Row_2 | null;
9122
9703
 
9123
- /**
9124
- * Options for `redisRywPositionStore`. The store needs TWO Redis
9125
- * connections because `SUBSCRIBE` puts a client in a mode where only
9126
- * (P)SUB / UNSUB / PING / QUIT are valid — sharing one client across
9127
- * writes and the subscribe loop would deadlock. Pass the same client
9128
- * for both unless you've separated them yourself.
9129
- */
9704
+ /** Registry-owned command facade and one borrowed Pub/Sub consumer. */
9130
9705
  export declare interface RedisRywOptions {
9131
- /**
9132
- * Connection used for SET / DEL / GET fallback writes. Stays in
9133
- * normal command mode.
9134
- */
9135
- readonly client: Redis;
9136
- /**
9137
- * Separate connection dedicated to the SUBSCRIBE loop. Pass a fresh
9138
- * `client.duplicate()` of the main connection; the store does NOT
9139
- * duplicate internally because callers may want to manage the
9140
- * subscription connection's lifecycle separately.
9141
- */
9142
- readonly subscriber: Redis;
9143
- /**
9144
- * Redis key prefix — every entry stores under `${keyPrefix}:<subjectKey>`.
9145
- * Defaults to `'voltro:ryw'`. Override to namespace per-app when
9146
- * multiple deployments share a Redis.
9147
- */
9148
- readonly keyPrefix?: string;
9149
- /**
9150
- * Pub/sub channel name. Defaults to `${keyPrefix}:bus`. All nodes
9151
- * sharing an RYW state MUST agree on this name.
9152
- */
9706
+ readonly client: RespClient;
9707
+ readonly pubsub: RedisPubSub;
9708
+ /** Application/environment namespace. Required; never shared implicitly. */
9709
+ readonly keyPrefix: string;
9710
+ /** Defaults to `${keyPrefix}:bus`; all participating processes must agree. */
9153
9711
  readonly channel?: string;
9154
- /** Clock injection for tests. Defaults to `Date.now`. */
9155
9712
  readonly now?: () => number;
9156
- /**
9157
- * Called when a Redis-side error occurs (publish/setex/subscribe
9158
- * failure). RYW degrades gracefully — local writes still succeed,
9159
- * other instances just won't see this node's writes until the next
9160
- * one. Hook for observability; default is a console.warn.
9161
- */
9713
+ /** Local writes survive remote failures. Failed mutations are never replayed. */
9162
9714
  readonly onError?: (error: unknown, op: 'set' | 'delete' | 'subscribe' | 'parse') => void;
9163
9715
  }
9164
9716
 
9717
+ export declare interface RedisRywPositionStore extends RywPositionStore {
9718
+ /** Drain accepted writes and release this consumer, leaving shared sockets open. */
9719
+ readonly close: () => Promise<void>;
9720
+ }
9721
+
9165
9722
  /**
9166
- * Build a Redis-backed RYW store. Cross-instance coherent within one
9167
- * round-trip; sync read path against a local mirror that the
9168
- * SUBSCRIBE loop keeps warm. Lifecycle:
9169
- *
9170
- * - on `set(key, entry)`:
9171
- * 1. write to local map (immediate, sync)
9172
- * 2. fire-and-forget SETEX in Redis with millisecond TTL
9173
- * 3. fire-and-forget PUBLISH on the channel — peers update
9174
- * their local mirror without round-tripping Redis again
9175
- * - on `delete(key)`:
9176
- * 1. remove from local map
9177
- * 2. fire-and-forget DEL + PUBLISH
9178
- * - on `get(key)`:
9179
- * 1. read from local map; lazy-evict if expired
9180
- *
9181
- * The SUBSCRIBE loop receives self-publishes (Redis sends them back
9182
- * to the sender). Each entry carries a `senderId`; the local node
9183
- * filters out its own broadcasts so we don't double-apply.
9184
- *
9185
- * On boot the local mirror is EMPTY. A read for a subject whose write
9186
- * happened on a peer node before this node started will miss the
9187
- * mirror — but `ReplicatedDataStore` falls back to primary on
9188
- * "no position", so the worst-case is "one extra primary read on the
9189
- * very first request that touches a peer-written subject". After that
9190
- * read, this node's own writes propagate normally.
9723
+ * Subscribe before returning. Reads consult only the process-local mirror.
9724
+ * Writes update it synchronously, then enqueue PSETEX/DEL followed by PUBLISH.
9725
+ * Pub/Sub is eventual and cannot replay lost messages or rebuild a new mirror.
9726
+ * A missing position still follows replica routing under fallback and wait;
9727
+ * neither policy establishes cross-process read-your-writes before delivery.
9191
9728
  */
9192
- export declare const redisRywPositionStore: (options: RedisRywOptions) => RywPositionStore;
9729
+ export declare const redisRywPositionStore: (options: RedisRywOptions) => Effect.Effect<RedisRywPositionStore, KvError>;
9193
9730
 
9194
9731
  /** `__voltro.undo.redo` — re-apply a previously-undone invocation's forward
9195
9732
  * changes. Idempotent if not currently undone. */
@@ -9243,7 +9780,15 @@ export declare const registerConnectionStream: (clientId: number, interrupt: ()
9243
9780
  */
9244
9781
  export declare const registerDefaultTupleSource: (source: TupleSource) => boolean;
9245
9782
 
9246
- export declare const registerExternalizedTask: (task: ExternalizedTask) => void;
9783
+ /** Process-level callers share the same map even across duplicated modules. */
9784
+ export declare const registerExternalizedTask: (task: ExternalizedTask) => (() => void);
9785
+
9786
+ /**
9787
+ * Record a key ahead of the deploy that brings it, as `pending`, with its
9788
+ * canary — so the first boot that holds it verifies its material, and the
9789
+ * configuration without it still boots (nothing is sealed under a pending key).
9790
+ */
9791
+ export declare const registerFieldKey: (store: DataStore, keyring: FieldKeyring, keyId: string) => Promise<void>;
9247
9792
 
9248
9793
  export { registerRetention }
9249
9794
 
@@ -9340,6 +9885,37 @@ export declare interface RegistryTableLike {
9340
9885
  * request was. */
9341
9886
  export declare const rehydrateGuards: (serialized: ReadonlyArray<SerializedGuard>) => ReadonlyArray<AnyGuardSpec>;
9342
9887
 
9888
+ /**
9889
+ * Re-seal every envelope in one cell that is not under the active key, or
9890
+ * names no key, under the active key and the address it was sealed under.
9891
+ */
9892
+ export declare const rekeyCell: (text: string, keyring: FieldKeyring, context: CellContext) => CellRekey;
9893
+
9894
+ export declare interface RekeyReport {
9895
+ readonly active: string;
9896
+ readonly locations: ReadonlyArray<LocationRekey>;
9897
+ readonly unreadable: ReadonlyArray<UnreadableColumn>;
9898
+ }
9899
+
9900
+ /**
9901
+ * Re-key every discovered location under the keyring's active key. With
9902
+ * `dryRun`, count what would change and write nothing.
9903
+ */
9904
+ export declare const rekeySealedValues: (dialect: DialectId, keyring: FieldKeyring, declared: Iterable<unknown>, options?: {
9905
+ readonly dryRun?: boolean;
9906
+ readonly onProgress?: (location: LocationRekey) => void;
9907
+ /** Runs between reading a cell and writing it back — where another writer may change it. */
9908
+ readonly beforeWrite?: (cell: {
9909
+ readonly table: string;
9910
+ readonly column: string;
9911
+ readonly rowId: unknown;
9912
+ }) => Effect.Effect<void, unknown, SqlClient.SqlClient>;
9913
+ }) => Effect.Effect<{
9914
+ active: string;
9915
+ locations: LocationRekey[];
9916
+ unreadable: UnreadableColumn[];
9917
+ }, SqlError, SqlClient.SqlClient>;
9918
+
9343
9919
  /** The store slice `applyDeclaredRelations` needs. `columns` is the junction's
9344
9920
  * DERIVED reference pair — the truth the descriptor's declaration is checked
9345
9921
  * against before anything is written. */
@@ -9362,6 +9938,9 @@ export declare interface RelationTuple {
9362
9938
  readonly resourceId: string;
9363
9939
  }
9364
9940
 
9941
+ /** Give up this process's lease — on shutdown, so nobody waits for it. */
9942
+ export declare const releaseFieldKeyHolder: (store: DataStore, holderId: string) => Promise<void>;
9943
+
9365
9944
  /**
9366
9945
  * Release a claim back to `pending` (CAS `fired → pending`) — used when
9367
9946
  * the wake failed, so the next poll retries it (at-least-once wake). The
@@ -9452,6 +10031,7 @@ export declare interface ReplicaSelector {
9452
10031
  }
9453
10032
 
9454
10033
  export declare class ReplicatedDataStore implements DataStore {
10034
+ readonly integrityQuery?: NonNullable<DataStore['integrityQuery']>;
9455
10035
  private readonly primary;
9456
10036
  private readonly replicas;
9457
10037
  private readonly adapter;
@@ -9463,12 +10043,13 @@ export declare class ReplicatedDataStore implements DataStore {
9463
10043
  private readonly health;
9464
10044
  private readonly recordRouting?;
9465
10045
  private readonly now;
10046
+ private closing;
9466
10047
  constructor(options: ReplicatedDataStoreOptions);
9467
10048
  query(descriptor: QueryDescriptor): Promise<ReadonlyArray<Row>>;
9468
10049
  private routeToReplica;
9469
10050
  private routeWaitMode;
9470
10051
  insert(table: string, row: Row): Promise<Row>;
9471
- insertMany(table: string, rows: ReadonlyArray<Row>): Promise<ReadonlyArray<Row>>;
10052
+ insertMany(table: string, rows: ReadonlyArray<Row>, options?: InsertManyOptions): Promise<ReadonlyArray<Row>>;
9472
10053
  patchJson(table: string, primaryKey: string, path: string, value: unknown, additionalPatch?: Readonly<Record<string, unknown>>): Promise<Row | null>;
9473
10054
  update(table: string, primaryKey: string, patch: Readonly<Record<string, unknown>>): Promise<Row | null>;
9474
10055
  delete(table: string, primaryKey: string): Promise<boolean>;
@@ -9493,6 +10074,8 @@ export declare class ReplicatedDataStore implements DataStore {
9493
10074
  injectExternalChange(event: ChangeEvent): void;
9494
10075
  /** Forwarded from the primary — see DataStore.changeScope. */
9495
10076
  get changeScope(): 'local' | 'fleet';
10077
+ /** Drain the RYW consumer before closing every SQL pool; repeated close is shared. */
10078
+ close(gracePeriodMs?: number): Promise<void>;
9496
10079
  private stampPostWrite;
9497
10080
  private emitRouting;
9498
10081
  }
@@ -9574,8 +10157,8 @@ export declare interface ResendOptions {
9574
10157
  readonly attempts?: number;
9575
10158
  }
9576
10159
 
9577
- /** Exported for tests — the warn-once set is process-global by design. */
9578
- export declare const resetComputedQueryCacheWarnings: () => void;
10160
+ /** Test seam: back to the boot default. */
10161
+ export declare const resetComputedQueryCacheCaptureForTests: () => void;
9579
10162
 
9580
10163
  /** Test/dev-only — clear ALL per-connection state. Don't call from app code. */
9581
10164
  export declare const _resetConnectionCredentialsForTest: () => void;
@@ -9586,6 +10169,9 @@ export declare const resetDetachedForTest: () => void;
9586
10169
  /** Test seams for the tag-cache guard — the cache is module-private otherwise. */
9587
10170
  export declare const resetEventMetricTagCacheForTests: () => void;
9588
10171
 
10172
+ /** Test seam. */
10173
+ export declare const resetFieldDecryptCountsForTests: () => void;
10174
+
9589
10175
  /** Drop everything recorded. For tests; not called by the runtime. */
9590
10176
  export declare const resetObservedGraph: () => void;
9591
10177
 
@@ -9720,7 +10306,9 @@ export declare interface ResolvedDevice {
9720
10306
  * Walk a query descriptor's eager-load tree and return the FULL set
9721
10307
  * of tables whose changes could affect the resolved snapshot.
9722
10308
  *
9723
- * - For a query without `eager`, returns just `{ descriptor.table }`.
10309
+ * - Includes explicitly declared invalidation sources (`dependentTables`),
10310
+ * independently of SQL predicates and projections.
10311
+ * - A plain query with no additional sources returns `{ descriptor.table }`.
9724
10312
  * - For each one()/many() relation, adds the target table.
9725
10313
  * - For each manyToMany() relation, adds the through-table AND the
9726
10314
  * target table (writes to either can shift the resolved set).
@@ -9787,6 +10375,15 @@ export declare interface ResolvedWorkflowCallerContext extends WorkflowCallerCon
9787
10375
  readonly rowFilter: RowFilterScope;
9788
10376
  }
9789
10377
 
10378
+ /**
10379
+ * The keyring an environment configures, or `undefined` when it configures no
10380
+ * key at all. Refuses (`FieldKeyringConfigError`, never containing key material)
10381
+ * an unknown or missing active id, a duplicate id, one key under two ids,
10382
+ * `KEY` equal to `_PREVIOUS`, and a `KEY`/`_PREVIOUS` set beside `KEYS` that
10383
+ * `KEYS` does not contain.
10384
+ */
10385
+ export declare const resolveFieldKeyring: (env: Readonly<Record<string, string | undefined>>) => FieldKeyringConfig | undefined;
10386
+
9790
10387
  /**
9791
10388
  * Resolve the app's health block against the boot path's own readiness flag.
9792
10389
  *
@@ -10057,6 +10654,15 @@ export { RetentionSpec }
10057
10654
 
10058
10655
  export { retentionTtlMsFromEnv }
10059
10656
 
10657
+ /**
10658
+ * Retire a key: nothing may be sealed under it again, and a configuration may
10659
+ * drop it — the boot no longer asks for it. Refused for the active key, a key
10660
+ * nobody recorded, and a key a live process still seals new values under (it
10661
+ * has not adopted the new key yet). Whether VALUES are still sealed under it is
10662
+ * the caller's question to answer first (`voltro secret retire` counts them).
10663
+ */
10664
+ export declare const retireFieldKey: (store: DataStore, keyId: string, holder?: Pick<FieldKeyHolder, "now">) => Promise<void>;
10665
+
10060
10666
  /**
10061
10667
  * Drop the ISR cache entries for a path on every `voltro start` replica.
10062
10668
  *
@@ -10364,6 +10970,8 @@ export declare interface RpcConnection {
10364
10970
 
10365
10971
  export declare interface RpcServerOptions<Rpcs extends Rpc.Any> {
10366
10972
  readonly group: RpcGroup.RpcGroup<Rpcs>;
10973
+ /** Executable RPC surfaces for this replica; omitted retains both transports. */
10974
+ readonly workloadAdmission?: RpcWorkloadAdmission;
10367
10975
  readonly handlersLayer: Layer.Layer<Rpc.ToHandler<Rpcs>>;
10368
10976
  /** Optional handlers layer dedicated to the one-shot HTTP rpc surface
10369
10977
  * (`POST /rpc`, used by SSR web-router loaders). The HTTP JSON protocol
@@ -10559,6 +11167,14 @@ export declare interface RpcServerOptions<Rpcs extends Rpc.Any> {
10559
11167
  readonly security?: TransportSecurityOptions;
10560
11168
  }
10561
11169
 
11170
+ export declare interface RpcWorkloadAdmission {
11171
+ readonly rpc: boolean;
11172
+ readonly subscriptions: boolean;
11173
+ /** Event streams are independent of live query subscriptions. */
11174
+ readonly events?: boolean;
11175
+ readonly routes?: ReadonlyArray<string>;
11176
+ }
11177
+
10562
11178
  /**
10563
11179
  * Rules that apply to one change, or an empty list.
10564
11180
  *
@@ -10643,6 +11259,10 @@ export declare const runSingleNodeOrchestrator: (opts: SingleNodeOrchestratorOpt
10643
11259
  export declare const RUNTIME_NAME: "framework-runtime";
10644
11260
 
10645
11261
  export declare interface RuntimeContext {
11262
+ /** Effective incoming Cookie header for server-side signature verification.
11263
+ * Unverified private input; never return, log or persist it. Optional for
11264
+ * internal callers and cookie-less requests. */
11265
+ readonly cookieHeader?: string;
10646
11266
  /** Subscription / call subject — user, API key, service account, or anonymous. */
10647
11267
  readonly subject: Subject;
10648
11268
  /** Trace identifier — the active span's W3C trace id (32 hex) when
@@ -10776,6 +11396,8 @@ export declare interface RywPositionStore {
10776
11396
  delete(subjectKey: string): void;
10777
11397
  /** Approximate size for observability + tests. */
10778
11398
  size(): number;
11399
+ /** Release consumer resources when this store owns any. */
11400
+ readonly close?: () => Promise<void>;
10779
11401
  }
10780
11402
 
10781
11403
  /**
@@ -10948,6 +11570,8 @@ export declare type ScheduleHandler = (ctx: ScheduleContext) => void | Promise<v
10948
11570
  export declare type ScheduleOverlapPolicy = 'skip' | 'queue' | 'parallel';
10949
11571
 
10950
11572
  export declare interface SchedulerDeps {
11573
+ /** Active synchronous handler entry only; never await a Promise inside this measurement. */
11574
+ readonly measureSync?: <A>(run: () => A) => A;
10951
11575
  /** App-owned service environment; the signal interrupts Effect work on timeout. */
10952
11576
  readonly runEffect?: (effect: Extract<ReturnType<ScheduleHandler>, Effect.Effect<unknown, unknown, unknown>>, signal: AbortSignal) => Promise<unknown>;
10953
11577
  readonly store: DataStore;
@@ -11059,6 +11683,8 @@ export declare interface SchedulerDeps {
11059
11683
  }
11060
11684
 
11061
11685
  export declare interface SchedulerHandle {
11686
+ /** Completed startup and shutdown has not begun; not a successful-job claim. */
11687
+ isRunning(): boolean;
11062
11688
  /** Fire a schedule immediately, bypassing the cron clock + the
11063
11689
  * coordinator. Waits for handler completion and returns the recorded run id. */
11064
11690
  fireNow(name: string, trigger: ScheduleTrigger | 'manual'): Promise<string | undefined>;
@@ -11364,6 +11990,22 @@ declare interface ScopeCtx {
11364
11990
  /** The scope strings a UI shows ("ask someone with …"). */
11365
11991
  export declare const scopeStringsOf: (serialized: ReadonlyArray<SerializedGuard>) => ReadonlyArray<string>;
11366
11992
 
11993
+ /** One column that holds envelopes, and what is under which key in it. */
11994
+ export declare interface SealedLocation {
11995
+ readonly table: string;
11996
+ readonly column: string;
11997
+ /** The app declares it `.encrypted()` (a whole cell is one value), rather than a place found holding envelopes. */
11998
+ readonly declared: boolean;
11999
+ /** Cells holding at least one envelope. */
12000
+ readonly cells: number;
12001
+ /** Envelopes, counted per key id. */
12002
+ readonly byKey: Readonly<Record<string, number>>;
12003
+ /** Envelopes written before envelopes named their key. */
12004
+ readonly unnamed: number;
12005
+ /** Declared `.encrypted()` only: non-null cells that are not an envelope. */
12006
+ readonly plaintext: number;
12007
+ }
12008
+
11367
12009
  export declare interface SecretsBackend {
11368
12010
  /** Resolve a secret by key. `undefined` when absent. */
11369
12011
  readonly get: (key: string) => Promise<string | undefined>;
@@ -11503,6 +12145,8 @@ export declare type SerializedGuard = {
11503
12145
  readonly resource: string | null;
11504
12146
  } | {
11505
12147
  readonly kind: 'authenticated';
12148
+ } | {
12149
+ readonly kind: 'upgraded';
11506
12150
  };
11507
12151
 
11508
12152
  /**
@@ -11511,7 +12155,25 @@ export declare type SerializedGuard = {
11511
12155
  */
11512
12156
  export declare const serializeGuards: (guards: ReadonlyArray<AnyGuardSpec>, input: unknown) => ReadonlyArray<SerializedGuard>;
11513
12157
 
12158
+ /** Required plugin work executed on the actual transaction connection. */
12159
+ export declare type ServeMutationCommitHook = (context: Parameters<ServeRpcInterceptor>[1] & {
12160
+ readonly kind: 'mutation';
12161
+ readonly store: DataStore;
12162
+ readonly output: unknown;
12163
+ readonly outbox?: OutboxEnqueueFacade;
12164
+ readonly startedAt?: number;
12165
+ readonly durationMs?: number;
12166
+ }) => Effect.Effect<void, unknown>;
12167
+
11514
12168
  export declare interface ServeRequestContext {
12169
+ /** Listener-owned identity; used only for measurement attribution here. */
12170
+ readonly connection?: {
12171
+ readonly transport: 'http' | 'websocket';
12172
+ };
12173
+ /** Effective incoming Cookie header for server-side signature verification.
12174
+ * Unverified private input; never return, log or persist it. Optional for
12175
+ * internal callers and cookie-less requests. */
12176
+ readonly cookieHeader?: string;
11515
12177
  readonly subject: unknown;
11516
12178
  readonly traceId: string;
11517
12179
  readonly spanId?: string;
@@ -11570,10 +12232,11 @@ export declare const serverOnlyLeaks: (query: AuditableQuery, serverOnlyByTable:
11570
12232
  /** A plugin interceptor — wraps the base run Effect (Effect-native chain). */
11571
12233
  export declare type ServeRpcInterceptor = (base: Effect.Effect<unknown, unknown, never>, meta: {
11572
12234
  readonly tag: string;
11573
- readonly kind: 'mutation' | 'action' | 'query' | 'workflow';
12235
+ readonly kind: 'mutation' | 'action' | 'query' | 'workflow' | 'stream';
11574
12236
  readonly input: unknown;
11575
12237
  readonly subject: unknown;
11576
12238
  readonly traceId: string;
12239
+ readonly enqueueOutcome?: OutboxEnqueueFacade['enqueue'];
11577
12240
  readonly spanId?: string;
11578
12241
  /**
11579
12242
  * The declared write-target TABLE names of this mutation/action, derived
@@ -11785,8 +12448,14 @@ export declare interface SingleNodeOrchestratorOptions {
11785
12448
  export declare interface SnapshotCache {
11786
12449
  readonly wrap: (binding: SnapshotCacheBinding, tags: ReadonlyArray<string>, compute: () => Promise<ReadonlyArray<Row>>) => Promise<ReadonlyArray<Row>>;
11787
12450
  /** Write-through from the live recompute, so the cache is never staler
11788
- * than the freshest live subscriber. Fire-and-forget. */
11789
- readonly put: (binding: SnapshotCacheBinding, tags: ReadonlyArray<string>, rows: ReadonlyArray<Row>) => void;
12451
+ * than the freshest live subscriber. Fire-and-forget. `fence` is the
12452
+ * cache's invalidation position observed BEFORE the rows were read: a
12453
+ * later invalidation of any tag voids the write, so an earlier, slower
12454
+ * read can never overwrite a later one. */
12455
+ readonly put: (binding: SnapshotCacheBinding, tags: ReadonlyArray<string>, rows: ReadonlyArray<Row>, fence: number) => void;
12456
+ /** The cache's invalidation position — observed before a read whose rows
12457
+ * will be written through. */
12458
+ readonly fence: () => Promise<number>;
11790
12459
  }
11791
12460
 
11792
12461
  /**
@@ -11798,6 +12467,8 @@ export declare interface SnapshotCacheBinding {
11798
12467
  readonly key: string;
11799
12468
  readonly ttlMs: number;
11800
12469
  readonly swrMs: number | undefined;
12470
+ /** The query name its counters are kept under (`queryStats`, metrics). */
12471
+ readonly label?: string | undefined;
11801
12472
  }
11802
12473
 
11803
12474
  /**
@@ -11809,6 +12480,20 @@ export declare const snapshotCrdt: (store: CrdtHistoryStore, cell: CrdtCellRef &
11809
12480
  readonly createdBy?: string;
11810
12481
  }) => Promise<CrdtVersion | undefined>;
11811
12482
 
12483
+ /**
12484
+ * The entry a READ belongs to: the rpc layer's scoped key plus the descriptor
12485
+ * actually read.
12486
+ *
12487
+ * The rpc key names the query, its input and the scope (subject / tenant /
12488
+ * global) — but not what the caller may SEE. A registered row filter makes two
12489
+ * colleagues of one tenant read different rows through the same `'tenant'` key,
12490
+ * and keying by the rpc key alone served the first colleague's filtered rows to
12491
+ * the next one. The read descriptor carries every predicate the caller's
12492
+ * visibility added, so two readers share an entry exactly when they read the
12493
+ * same thing.
12494
+ */
12495
+ export declare const snapshotEntryFor: (binding: SnapshotCacheBinding, read: QueryDescriptor) => SnapshotCacheBinding;
12496
+
11812
12497
  /** Snapshot the whole registry, normalized to `MetricSample[]` — plus the
11813
12498
  * socket-backpressure counters (`subscriptionSocketMetrics.ts`), appended
11814
12499
  * HERE so every reader (Prometheus exporter, inspect Metrics panel) sees
@@ -11846,32 +12531,23 @@ export declare class SsrfBlockedError extends Error {
11846
12531
  */
11847
12532
  export declare const ssrfGuardHttpClientLayer: (policy?: SsrfPolicy) => Layer.Layer<HttpClient.HttpClient, never, HttpClient.HttpClient>;
11848
12533
 
11849
- export declare interface SsrfPolicy {
11850
- /**
11851
- * Hosts that bypass the guard. An entry may be an exact hostname
11852
- * (`billing.internal`), a suffix wildcard (`*.svc.cluster.local`), or a
11853
- * host:port (`127.0.0.1:8787`) when only one port should be reachable.
11854
- *
11855
- * This is the one escape hatch, and it is deliberately per-HOST rather than a
11856
- * boolean: "we call one internal service" and "we do not check URLs" are very
11857
- * different postures, and a boolean cannot tell them apart six months later.
11858
- */
11859
- readonly allowHosts?: ReadonlyArray<string>;
11860
- /** Max redirect hops to follow. Each one is revalidated. Default 5. */
11861
- readonly maxRedirects?: number;
11862
- }
12534
+ export { SsrfPolicy }
12535
+
12536
+ export { ssrfReason }
11863
12537
 
11864
12538
  /**
11865
- * Decide whether a URL may be fetched. Returns `null` when allowed, else the
11866
- * reason. Fails CLOSED: a URL that will not parse is blocked.
11867
- *
11868
- * DNS is deliberately NOT resolved — this is a synchronous check on the literal
11869
- * target, so a hostname that RESOLVES to a private address (DNS rebinding) is not
11870
- * caught here. Blocking the direct-IP vector is the high-severity, cheap half;
11871
- * rebinding needs network-layer egress control and is called out in the docs
11872
- * rather than silently implied.
12539
+ * Heartbeat every {@link FIELD_KEY_HEARTBEAT_MS} for as long as the process
12540
+ * runs. Logs a transition once — a key that became active, a key still waiting
12541
+ * and for whom, an active key this process does not hold — never every beat.
11873
12542
  */
11874
- export declare const ssrfReason: (rawUrl: string, policy?: SsrfPolicy) => string | null;
12543
+ export declare const startFieldKeyHolder: (store: DataStore, keyring: FieldKeyring, holder: FieldKeyHolder & {
12544
+ readonly intervalMs?: number;
12545
+ readonly log: {
12546
+ readonly info: (message: string) => void;
12547
+ readonly warn: (message: string) => void;
12548
+ readonly error: (message: string) => void;
12549
+ };
12550
+ }) => FieldKeyHolderHandle;
11875
12551
 
11876
12552
  /**
11877
12553
  * Start the rpc-based runtime server on Node. Composes:
@@ -12101,6 +12777,12 @@ export declare interface SubscriberDefinition {
12101
12777
  readonly table: string;
12102
12778
  /** Default `'any'`. */
12103
12779
  readonly on?: SubscribeOp | ReadonlyArray<Exclude<SubscribeOp, 'any'>>;
12780
+ /** Bind this invocation's event publisher to the trusted committed row's
12781
+ * tenant. No client input is available here. Omitted keeps system/global
12782
+ * publication. This does not change ctx.store's system identity or turn a
12783
+ * best-effort subscriber into durable delivery. Invalid results refuse the
12784
+ * handler rather than publishing into the global partition. */
12785
+ readonly eventTenant?: (event: SubscribeEvent) => string | null;
12104
12786
  /**
12105
12787
  * Run the handler ONCE PER CHANGE across the whole fleet, instead of once on
12106
12788
  * every replica that sees it.
@@ -12450,7 +13132,7 @@ export declare const tenantSelectionStore: (getStore: () => DataStore | undefine
12450
13132
  * a page. */
12451
13133
  export declare const TERMINAL_RUN_STATUSES: ReadonlySet<string>;
12452
13134
 
12453
- export declare type TimeBucket = 'minute' | 'hour' | 'day' | 'week' | 'month';
13135
+ export { TimeBucket }
12454
13136
 
12455
13137
  export declare interface TimelineEvent {
12456
13138
  /** Preserves the store's warning that images are not original commit images. */
@@ -12516,29 +13198,11 @@ export declare class TimelineRecorder {
12516
13198
  replay(table: string, asOfSeq: number, currentRows: ReadonlyArray<Row_2>): ReadonlyArray<Row_2>;
12517
13199
  }
12518
13200
 
12519
- /** Time window. `to` defaults to now. */
12520
- export declare interface TimeRange {
12521
- readonly from: Date;
12522
- readonly to?: Date;
12523
- }
13201
+ export { TimeRange }
12524
13202
 
12525
- export declare interface TimeseriesQuery extends AggregateQuery {
12526
- readonly bucket: TimeBucket;
12527
- }
13203
+ export { TimeseriesQuery }
12528
13204
 
12529
- export declare interface TopNQuery {
12530
- readonly event: string;
12531
- /** Property to group by (must be a string-valued property). */
12532
- readonly groupBy: string;
12533
- readonly metric: 'count' | {
12534
- readonly sum: string;
12535
- };
12536
- readonly n: number;
12537
- readonly range: TimeRange;
12538
- readonly filter?: PropertyFilter;
12539
- /** Tenant scope — injected by `useAnalytics()`; see {@link AggregateQuery.tenantId}. */
12540
- readonly tenantId?: string | null;
12541
- }
13205
+ export { TopNQuery }
12542
13206
 
12543
13207
  /** A row a mutation wrote, carried to rule evaluation. `row` is the POST-WRITE
12544
13208
  * state (insert result / update result). */
@@ -12990,7 +13654,11 @@ export declare class UndoStack<E> {
12990
13654
  */
12991
13655
  export declare const undoSurfaceEnabled: (env?: Record<string, string | undefined>) => boolean;
12992
13656
 
12993
- export declare const unregisterExternalizedTask: (name: string) => void;
13657
+ export declare interface UnreadableColumn {
13658
+ readonly table: string;
13659
+ readonly column: string;
13660
+ readonly reason: string;
13661
+ }
12994
13662
 
12995
13663
  /** One `source:` entry that resolves to no declared table. */
12996
13664
  export declare interface UnresolvedSource {
@@ -13003,6 +13671,8 @@ export declare interface UnresolvedSource {
13003
13671
  /** True when the name is in the `channel:` namespace: it named a reactivity
13004
13672
  * channel nobody declared, which is a different repair from a stale table. */
13005
13673
  readonly channel: boolean;
13674
+ /** Intentionally optional integration observation, retained in source. */
13675
+ readonly optional?: true;
13006
13676
  }
13007
13677
 
13008
13678
  /**
@@ -13014,6 +13684,7 @@ export declare interface UnresolvedSource {
13014
13684
  export declare const unresolvedSources: (procedures: ReadonlyArray<{
13015
13685
  readonly name: string;
13016
13686
  readonly source: string | ReadonlyArray<string> | undefined;
13687
+ readonly optionalSource?: ReadonlyArray<string>;
13017
13688
  }>, declared: ReadonlySet<string>) => ReadonlyArray<UnresolvedSource>;
13018
13689
 
13019
13690
  /** Thrown at boot; the message is the whole point, so it names the path and the
@@ -13095,6 +13766,27 @@ export declare type VerificationDeclared<T> = T & {
13095
13766
  readonly [WEBHOOK_VERIFICATION_PROPERTY]: WebhookVerification;
13096
13767
  };
13097
13768
 
13769
+ /**
13770
+ * Check the keyring against the database and record what is new; make the
13771
+ * database's active key the keyring's. Throws {@link FieldKeyringRefusal} when
13772
+ * the keyring cannot read this database's data.
13773
+ *
13774
+ * `tables` are the app's declared tables: a few sealed values per
13775
+ * `.encrypted()` column are opened as a sample, and nothing else is read.
13776
+ */
13777
+ export declare const verifyFieldKeyring: (store: DataStore, keyring: FieldKeyring, tables: Iterable<unknown>, holder?: FieldKeyHolder) => Promise<FieldKeyringVerification>;
13778
+
13779
+ /** Every location's envelopes, opened with `keyring` — after a re-key, a keyring with the active key alone. */
13780
+ export declare const verifySealedValues: (dialect: DialectId, keyring: FieldKeyring, declared: Iterable<unknown>) => Effect.Effect<{
13781
+ opened: number;
13782
+ unopened: {
13783
+ readonly table: string;
13784
+ readonly column: string;
13785
+ readonly count: number;
13786
+ }[];
13787
+ unreadable: UnreadableColumn[];
13788
+ }, SqlError, SqlClient.SqlClient>;
13789
+
13098
13790
  /** The pure core of live revocation: given a subject + action + a row-set,
13099
13791
  * return ONLY the rows the subject may still see. The reactive matcher calls
13100
13792
  * this on a permission-changing write and diffs against the prior visible set;
@@ -13172,6 +13864,19 @@ export declare const _voltroConnectionsTable: TableLike;
13172
13864
 
13173
13865
  export declare const _voltroCrdtVersionsTable: TableLike;
13174
13866
 
13867
+ /** The leases: which process holds which keys, and until when it counts —
13868
+ * rewritten by every heartbeat, so not reactive. */
13869
+ export declare const _voltroFieldKeyHoldersTable: TableLike;
13870
+
13871
+ /** The last count and the last re-key `voltro secret status` / `rekey` / `rotate`
13872
+ * ran — what the Governance panel shows as a rotation's progress, since the
13873
+ * app itself never scans every sealed value. Counts and locations, never a value. */
13874
+ export declare const _voltroFieldKeyReportsTable: TableLike;
13875
+
13876
+ /** Each field-encryption key id's state and canary — a framework table, created for every app.
13877
+ * Declared by its literal name: the data-transfer classification guard reads declarations. */
13878
+ export declare const _voltroFieldKeysTable: TableLike;
13879
+
13175
13880
  /** `_voltro_rebac_tuples` — the relationship tuples `can()` reads. One row =
13176
13881
  * "`subjectId` has `relation` on `<resourceType>:<resourceId>`". Grant by
13177
13882
  * inserting; revoke by deleting (a delete is the live-revocation trigger). */
@@ -13341,6 +14046,14 @@ export declare type WhereOp = '=' | '!=' | '<>' | '>' | '>=' | '<' | '<=' | 'in'
13341
14046
 
13342
14047
  export declare const withRowFilter: <R extends ServeRequestContext>(request: R) => Promise<R>;
13343
14048
 
14049
+ /**
14050
+ * Add the shared RPC auth pair once to an undecorated group. Authentication
14051
+ * runs before ConnectionInfo captures this call's verified credential lifetime.
14052
+ * Groups already carrying either middleware are refused: Effect preserves Set
14053
+ * insertion order, so appending a duplicate cannot repair an existing order.
14054
+ */
14055
+ export declare const withRpcAuthMiddleware: <R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>) => RpcGroup.RpcGroup<Rpc.AddMiddleware<Rpc.AddMiddleware<R, typeof ConnectionInfoMiddleware>, typeof AuthMiddleware>>;
14056
+
13344
14057
  /**
13345
14058
  * Run `body` against a request that carries a resolved row-filter scope.
13346
14059
  *
@@ -13511,6 +14224,15 @@ export declare interface WorkflowEventTriggerResult {
13511
14224
  readonly reason?: string;
13512
14225
  }
13513
14226
 
14227
+ export declare interface WorkflowExecutionRefusal {
14228
+ readonly workflowName: string;
14229
+ readonly executionId: string;
14230
+ readonly payload: unknown;
14231
+ readonly cause: Cause.Cause<unknown>;
14232
+ /** Restored identity and host-owned placement; no resolved permissions. */
14233
+ readonly callerContext: WorkflowCallerContext;
14234
+ }
14235
+
13514
14236
  export declare interface WorkflowFacadeOptions {
13515
14237
  readonly cancelQueued?: (input: WorkflowQueuedControlTarget & {
13516
14238
  readonly callerContext: WorkflowCallerContext | undefined;
@@ -13652,13 +14374,18 @@ export declare interface WorkflowLayerOptions<Context> {
13652
14374
  * whose business logic said no.
13653
14375
  */
13654
14376
  readonly resolveAuthority?: (identity: unknown) => Promise<unknown>;
14377
+ /** Record a known caller's refusal through the host's ordinary resident run
14378
+ * recorder. Called before application context/body construction. The failed
14379
+ * attempt stays failed, even if this hook completes successfully. Missing
14380
+ * caller identity cannot fabricate a tenant or a first-run record. */
14381
+ readonly onExecutionRefusal?: (refusal: WorkflowExecutionRefusal) => Effect.Effect<unknown, unknown, unknown>;
13655
14382
  /**
13656
14383
  * Told when an execution is refused BEFORE its body — the start context
13657
14384
  * could not be resolved, the identity was missing, the authority or row
13658
14385
  * filter resolver rejected. The engine already fails the attempt; what a
13659
- * discarded start does NOT do is tell anyone, and a run refused here has no
13660
- * row yet, so nothing else can. Measured: an acknowledged start whose
13661
- * resident context was filed under another id died with a debug-level
14386
+ * discarded start does NOT do is tell anyone. A first start may have no
14387
+ * row yet; a resumed run may still have a running row. Measured: an
14388
+ * acknowledged start whose resident context was filed under another id died with a debug-level
13662
14389
  * "Fiber terminated" and nothing else. Hosts wire this to an error log.
13663
14390
  */
13664
14391
  readonly reportExecutionRefusal?: (refusal: {
@@ -13899,7 +14626,7 @@ export declare interface WorkflowsAppContext {
13899
14626
  * execution, or never to run — read once, without waiting. A queued handle
13900
14627
  * is resolved through its durable receipt, so the answer survives the
13901
14628
  * process that recorded the handle. */
13902
- readStart(handle: WorkflowRunHandle, options?: Pick<WorkflowWaitOptions, 'callerContext'>): Promise<WorkflowStartObservation>;
14629
+ readStart(handle: WorkflowRunHandle, options?: WorkflowRunOptions): Promise<WorkflowStartObservation>;
13903
14630
  /**
13904
14631
  * Set on the facade a mutation TRANSACTION hands out: every start it records
13905
14632
  * is provisional until the transaction commits, so nothing about a start can
@@ -14037,6 +14764,7 @@ export declare interface WorkflowStartOptions {
14037
14764
  }
14038
14765
 
14039
14766
  export declare interface WorkflowStartRunnerDeps {
14767
+ readonly outcomeOutbox?: MutationRunnerDeps['outcomeOutbox'];
14040
14768
  /** Composed plugin workflow-interceptor (`interceptWorkflow`). */
14041
14769
  readonly interceptor?: ServeRpcInterceptor;
14042
14770
  readonly recordMetric?: MutationRunnerDeps['recordMetric'];
@@ -14081,6 +14809,10 @@ export declare const wrapStoreWithBootCodec: (underlying: DataStore, dialectId:
14081
14809
 
14082
14810
  export declare const wrapStoreWithMixinBehaviour: (rawUnderlying: DataStore, ctx: StoreMiddlewareContext) => FluentStore;
14083
14811
 
14812
+ /** Writer errors propagate to the publisher, which owns retry/logging. A failed
14813
+ * history write must not be mistaken for a successfully recorded zero bucket. */
14814
+ export declare const writeApiRoleWorkloadBucket: (store: DataStore, bucket: ApiRoleWorkloadBucket) => Promise<void>;
14815
+
14084
14816
  export declare const writeReplicaObservation: (store: DataStore, kind: ReplicaObservationKind, payload: unknown) => Promise<void>;
14085
14817
 
14086
14818
  export { }