@voltro/runtime 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -957,7 +957,7 @@ export declare const applyInverses: (store: UndoApplyStore, ops: ReadonlyArray<I
957
957
  * finds nothing — an orphan rule firing on a row nobody references is the
958
958
  * normal case, not an error.
959
959
  */
960
- export declare const applyPluginRefRules: (store: PluginRefStore, rules: ReadonlyArray<PluginRefRule>, change: PluginRefChange) => Promise<ReadonlyArray<{
960
+ export declare const applyPluginRefRules: (store: PluginRefStore, rules: ReadonlyArray<PluginRefRule>, change: ChangeEvent) => Promise<ReadonlyArray<{
961
961
  readonly rule: PluginRefRule;
962
962
  readonly affected: number;
963
963
  }>>;
@@ -1151,15 +1151,6 @@ export declare interface BeginOAuthResult {
1151
1151
  readonly state: string;
1152
1152
  }
1153
1153
 
1154
- /**
1155
- * Override the subject for an active connection. Called from the
1156
- * `auth.signin` (or any "I just authenticated this caller") handler
1157
- * after the credential check passes. Future calls on the same
1158
- * connection see the new subject via the AuthMiddleware fast-path.
1159
- *
1160
- * Emits to all `onBind` listeners synchronously so subscription
1161
- * registries can re-scope active subscriptions.
1162
- */
1163
1154
  export declare const bindConnectionSubject: (clientId: number, subject: Subject) => void;
1164
1155
 
1165
1156
  /**
@@ -1532,12 +1523,18 @@ export declare const clearSystemStoreHandle: () => void;
1532
1523
  */
1533
1524
  export declare const collectPluginRefRules: (tables: ReadonlyArray<{
1534
1525
  readonly name: string;
1535
- readonly columns: Record<string, unknown>;
1536
- }>, specOf: (column: unknown) => {
1537
- target: () => unknown;
1538
- orphanPolicy: PluginRefOrphanPolicy;
1539
- onSoftDelete: boolean;
1540
- } | undefined, registered: ReadonlySet<string>) => ReadonlyArray<PluginRefRule>;
1526
+ /** The DECLARED references, carried on the built table. Reading the column
1527
+ * bag instead does not work: `table()` materialises builders into plain
1528
+ * field descriptors, so the spec is gone by the time anyone can ask. That
1529
+ * is how this collector silently produced ZERO rules while its own wiring
1530
+ * test — which only checked that it was CALLED — stayed green. */
1531
+ readonly appliedPluginRefs?: ReadonlyArray<{
1532
+ readonly column: string;
1533
+ readonly target: () => unknown;
1534
+ readonly orphanPolicy: PluginRefOrphanPolicy;
1535
+ readonly onSoftDelete: boolean;
1536
+ }>;
1537
+ }>, registered: ReadonlySet<string>) => ReadonlyArray<PluginRefRule>;
1541
1538
 
1542
1539
  /** Parse + return the compiled `Cron` for a definition. Throws the
1543
1540
  * same way `defineSchedule` validated — callers that already hold a
@@ -2943,6 +2940,8 @@ export declare const getConnectionResolver: () => ConnectionResolver | undefined
2943
2940
  /** Look up the override for a connection. Returns `undefined` if no override is set. */
2944
2941
  export declare const getConnectionSubject: (clientId: number) => Subject | undefined;
2945
2942
 
2943
+ export declare const getCredentialExpiry: (clientId: number) => number | undefined;
2944
+
2946
2945
  /** The registered field cipher, if any. The store middleware reads this. */
2947
2946
  export declare const getFieldCipher: () => FieldCipher | undefined;
2948
2947
 
@@ -3348,7 +3347,7 @@ export declare const isScheduleDefinition: (v: unknown) => v is BrandedScheduleD
3348
3347
  * The transition matters, not the value: a row that was already deleted and is
3349
3348
  * updated again must not re-fire the rule.
3350
3349
  */
3351
- export declare const isSoftDelete: (change: PluginRefChange) => boolean;
3350
+ export declare const isSoftDelete: (change: ChangeEvent) => boolean;
3352
3351
 
3353
3352
  /** A freshly issued key — `token` is shown ONCE and never stored in clear. */
3354
3353
  export declare interface IssuedApiKey {
@@ -3783,6 +3782,10 @@ export declare const makeProcessAdapter: (supervisor: AppSupervisor) => WakeAdap
3783
3782
  */
3784
3783
  export declare const makeQueryDescriptorProducer: <D>(deps: QueryProducerDeps<D>) => (query: MutationLike, input: unknown) => (requestContext: ServeRequestContext) => D | ComputedQuery | Effect.Effect<D | ComputedQuery, unknown, never>;
3785
3784
 
3785
+ export declare const makeQueryFinalizer: (options: QueryFinalizeOptions) => ((descriptor: QueryDescriptor, subject: {
3786
+ readonly tenantId?: string | null;
3787
+ }) => QueryDescriptor);
3788
+
3786
3789
  /**
3787
3790
  * Build the per-subscription authorization re-check.
3788
3791
  *
@@ -4557,18 +4560,6 @@ export declare const payloadPropertyNames: (schema: Schema.Schema.Any) => {
4557
4560
  readonly optional: ReadonlyArray<string>;
4558
4561
  };
4559
4562
 
4560
- /** A change as the post-commit channel reports it. */
4561
- export declare interface PluginRefChange {
4562
- readonly table: string;
4563
- readonly op: 'insert' | 'update' | 'delete';
4564
- readonly rowId: string;
4565
- readonly tenantId?: string | null;
4566
- /** The row before, when there was one — used to spot a soft delete. */
4567
- readonly old?: Record<string, unknown> | null;
4568
- /** The row after, when there is one. */
4569
- readonly new?: Record<string, unknown> | null;
4570
- }
4571
-
4572
4563
  /** One resolved rule: "when <targetTable> loses a row, do <policy> to <table.column>". */
4573
4564
  export declare interface PluginRefRule {
4574
4565
  readonly table: string;
@@ -4716,6 +4707,43 @@ export declare const publishEvent: <Name extends string, Key extends Schema.Sche
4716
4707
  readonly deferred: boolean;
4717
4708
  }, EventPublishError>;
4718
4709
 
4710
+ /**
4711
+ * The two scopes, composed once, for every path that finalises a descriptor.
4712
+ *
4713
+ * **The primitives above were extracted so there is "no second copy that could
4714
+ * drift" — and then the COMPOSITION became the second copy.** `voltro dev`
4715
+ * wrapped them in a local helper; `serveApi` inlined the same pair in the other
4716
+ * spelling. They agreed, which is the dangerous state: nothing kept them
4717
+ * agreeing, and adding a third scoping concern would have landed in whichever
4718
+ * file the author had open.
4719
+ *
4720
+ * That is the shape this repo has shipped seven times and the one a
4721
+ * source-reading parity guard cannot see — both paths supply something, both
4722
+ * look right at their own call site, and they disagree about content. The fix is
4723
+ * not detection. It is having one function, so the disagreement has nowhere to
4724
+ * live.
4725
+ *
4726
+ * `observe` is where the paths are ALLOWED to differ: `voltro dev` warns about
4727
+ * an org-less subject, an empty tenant scope and a non-indexed predicate, and
4728
+ * production does not want any of that on the hot path. A hook that cannot
4729
+ * change the descriptor keeps the difference to the part that is genuinely
4730
+ * dev-only. It receives a COPY of the descriptor: a hook that could rewrite the
4731
+ * query would let the two paths disagree again through the one seam built to
4732
+ * stop them.
4733
+ */
4734
+ export declare interface QueryFinalizeOptions {
4735
+ readonly tenantScopedTables: ReadonlySet<string>;
4736
+ readonly softDeleteScopedTables: ReadonlySet<string>;
4737
+ readonly observe?: {
4738
+ /** Before scoping — sees what the handler asked for. */
4739
+ readonly beforeScope?: (descriptor: QueryDescriptor, subject: {
4740
+ readonly tenantId?: string | null;
4741
+ }) => void;
4742
+ /** After scoping — sees what will actually run. */
4743
+ readonly afterScope?: (descriptor: QueryDescriptor) => void;
4744
+ };
4745
+ }
4746
+
4719
4747
  /** A typed builder or its descriptor — the single-row terminals accept either,
4720
4748
  * so a call site never has to reach for `.descriptor` just to use them. */
4721
4749
  export declare type QueryLike<R = Row_5> = QueryDescriptor<R> | {
@@ -4873,6 +4901,8 @@ export declare interface RebacSubject {
4873
4901
  readonly scopes?: ReadonlyArray<string>;
4874
4902
  }
4875
4903
 
4904
+ export declare const recordCredentialExpiry: (clientId: number, exp: number | undefined) => void;
4905
+
4876
4906
  /** What the framework emit-seams (servePipeline / rpcServer / plugin wrappers)
4877
4907
  * hand to the registry. A flat, transport-agnostic sample shape the
4878
4908
  * recording callbacks can build without touching Effect. */
@@ -5770,7 +5800,7 @@ export declare interface RpcServerOptions<Rpcs extends Rpc.Any> {
5770
5800
  * Exported separately from the execution so the matching is testable without a
5771
5801
  * store: which rules fire is the part with the edge cases.
5772
5802
  */
5773
- export declare const rulesFor: (rules: ReadonlyArray<PluginRefRule>, change: PluginRefChange) => ReadonlyArray<PluginRefRule>;
5803
+ export declare const rulesFor: (rules: ReadonlyArray<PluginRefRule>, change: ChangeEvent) => ReadonlyArray<PluginRefRule>;
5774
5804
 
5775
5805
  /**
5776
5806
  * Run `fn` with `SubjectService` bound to a `system` subject and a