rivetkit 2.3.11-rc.8 → 2.3.11

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 (153) hide show
  1. package/dist/browser/client.d.ts +96 -14
  2. package/dist/browser/client.js +12 -2
  3. package/dist/browser/client.js.map +1 -1
  4. package/dist/browser/inspector/client.d.ts +139 -139
  5. package/dist/browser/inspector/client.js +12 -2
  6. package/dist/browser/inspector/client.js.map +1 -1
  7. package/dist/tsup/agent-os/index.cjs +146 -76
  8. package/dist/tsup/agent-os/index.cjs.map +1 -1
  9. package/dist/tsup/agent-os/index.d.cts +83 -9
  10. package/dist/tsup/agent-os/index.d.ts +83 -9
  11. package/dist/tsup/agent-os/index.js +146 -76
  12. package/dist/tsup/agent-os/index.js.map +1 -1
  13. package/dist/tsup/{chunk-JBQ63WSM.js → chunk-3ZR542SK.js} +4 -4
  14. package/dist/tsup/chunk-3ZR542SK.js.map +1 -0
  15. package/dist/tsup/{chunk-HNHLBM3Y.cjs → chunk-4KGXFC6M.cjs} +42 -5
  16. package/dist/tsup/chunk-4KGXFC6M.cjs.map +1 -0
  17. package/dist/tsup/chunk-5UYWLCRO.js +14 -0
  18. package/dist/tsup/chunk-5UYWLCRO.js.map +1 -0
  19. package/dist/tsup/{chunk-QWLJCP3X.js → chunk-6W5VGLFT.js} +42 -5
  20. package/dist/tsup/chunk-6W5VGLFT.js.map +1 -0
  21. package/dist/tsup/chunk-6WYATRS4.js +243 -0
  22. package/dist/tsup/chunk-6WYATRS4.js.map +1 -0
  23. package/dist/tsup/chunk-B3W74FBB.cjs +14 -0
  24. package/dist/tsup/chunk-B3W74FBB.cjs.map +1 -0
  25. package/dist/tsup/{chunk-V6ANE6JM.js → chunk-FWROC5LA.js} +2 -2
  26. package/dist/tsup/{chunk-ZVM35ICH.cjs → chunk-GLIPKKEC.cjs} +7 -7
  27. package/dist/tsup/{chunk-ZVM35ICH.cjs.map → chunk-GLIPKKEC.cjs.map} +1 -1
  28. package/dist/tsup/{chunk-CCUO5OKD.cjs → chunk-GN2EUMEW.cjs} +3 -3
  29. package/dist/tsup/{chunk-CCUO5OKD.cjs.map → chunk-GN2EUMEW.cjs.map} +1 -1
  30. package/dist/tsup/{chunk-2ROUKH7W.cjs → chunk-GU7ML3KE.cjs} +13 -3
  31. package/dist/tsup/chunk-GU7ML3KE.cjs.map +1 -0
  32. package/dist/tsup/{chunk-WRRB24UY.js → chunk-JQ2AZ5FN.js} +3 -3
  33. package/dist/tsup/{chunk-7AFZMFPQ.js → chunk-JTHHCZCZ.js} +10 -1
  34. package/dist/tsup/chunk-JTHHCZCZ.js.map +1 -0
  35. package/dist/tsup/{chunk-UEULFXUI.cjs → chunk-KVFIONKQ.cjs} +11 -2
  36. package/dist/tsup/chunk-KVFIONKQ.cjs.map +1 -0
  37. package/dist/tsup/chunk-LWQFXGKS.cjs +243 -0
  38. package/dist/tsup/chunk-LWQFXGKS.cjs.map +1 -0
  39. package/dist/tsup/{chunk-KVD6ZWNM.js → chunk-MO2SSUOR.js} +8 -7
  40. package/dist/tsup/chunk-MO2SSUOR.js.map +1 -0
  41. package/dist/tsup/{chunk-AGNBLCNJ.js → chunk-OUENKQHB.js} +13 -3
  42. package/dist/tsup/chunk-OUENKQHB.js.map +1 -0
  43. package/dist/tsup/{chunk-E6WB2BLO.cjs → chunk-PUZY2XCD.cjs} +10 -9
  44. package/dist/tsup/chunk-PUZY2XCD.cjs.map +1 -0
  45. package/dist/tsup/{chunk-4EDGOGCB.js → chunk-QFJ24MBU.js} +27 -2
  46. package/dist/tsup/{chunk-4EDGOGCB.js.map → chunk-QFJ24MBU.js.map} +1 -1
  47. package/dist/tsup/{chunk-A55CGZIV.cjs → chunk-RXXDNJXB.cjs} +140 -140
  48. package/dist/tsup/{chunk-A55CGZIV.cjs.map → chunk-RXXDNJXB.cjs.map} +1 -1
  49. package/dist/tsup/{chunk-N6MBTYGX.cjs → chunk-VBJQIBXI.cjs} +30 -5
  50. package/dist/tsup/chunk-VBJQIBXI.cjs.map +1 -0
  51. package/dist/tsup/client/mod.cjs +6 -6
  52. package/dist/tsup/client/mod.d.cts +4 -3
  53. package/dist/tsup/client/mod.d.ts +4 -3
  54. package/dist/tsup/client/mod.js +5 -5
  55. package/dist/tsup/common/log.cjs +2 -2
  56. package/dist/tsup/common/log.js +1 -1
  57. package/dist/tsup/common/websocket.cjs +3 -3
  58. package/dist/tsup/common/websocket.js +2 -2
  59. package/dist/tsup/{config-CZcjyT5B.d.ts → config-C4OSv0QP.d.ts} +92 -7
  60. package/dist/tsup/{config-rGWrumlO.d.cts → config-DTGoWdkG.d.cts} +92 -7
  61. package/dist/tsup/{config-BxOimoGX.d.cts → config-ey2I2zz5.d.cts} +46 -6
  62. package/dist/tsup/{config-BxOimoGX.d.ts → config-ey2I2zz5.d.ts} +46 -6
  63. package/dist/tsup/{context-B8W8E8nW.d.cts → context-C6cvDNyk.d.cts} +2 -2
  64. package/dist/tsup/{context-_UrDZhEh.d.ts → context-CMygeBxS.d.ts} +2 -2
  65. package/dist/tsup/db/drizzle.cjs +18 -10
  66. package/dist/tsup/db/drizzle.cjs.map +1 -1
  67. package/dist/tsup/db/drizzle.d.cts +5 -6
  68. package/dist/tsup/db/drizzle.d.ts +5 -6
  69. package/dist/tsup/db/drizzle.js +13 -5
  70. package/dist/tsup/db/drizzle.js.map +1 -1
  71. package/dist/tsup/db/mod.cjs +5 -175
  72. package/dist/tsup/db/mod.cjs.map +1 -1
  73. package/dist/tsup/db/mod.d.cts +11 -4
  74. package/dist/tsup/db/mod.d.ts +11 -4
  75. package/dist/tsup/db/mod.js +4 -174
  76. package/dist/tsup/db/mod.js.map +1 -1
  77. package/dist/tsup/dynamic/mod.cjs +2 -2
  78. package/dist/tsup/dynamic/mod.d.cts +3 -2
  79. package/dist/tsup/dynamic/mod.d.ts +3 -2
  80. package/dist/tsup/dynamic/mod.js +1 -1
  81. package/dist/tsup/inspector/mod.cjs +5 -4
  82. package/dist/tsup/inspector/mod.cjs.map +1 -1
  83. package/dist/tsup/inspector/mod.d.cts +12 -146
  84. package/dist/tsup/inspector/mod.d.ts +12 -146
  85. package/dist/tsup/inspector/mod.js +4 -3
  86. package/dist/tsup/inspector/mod.js.map +1 -1
  87. package/dist/tsup/inspector/workflow.cjs +21 -0
  88. package/dist/tsup/inspector/workflow.cjs.map +1 -0
  89. package/dist/tsup/inspector/workflow.d.cts +144 -0
  90. package/dist/tsup/inspector/workflow.d.ts +144 -0
  91. package/dist/tsup/inspector/workflow.js +21 -0
  92. package/dist/tsup/inspector/workflow.js.map +1 -0
  93. package/dist/tsup/inspector-tab/mod.cjs +2 -2
  94. package/dist/tsup/inspector-tab/mod.d.cts +4 -3
  95. package/dist/tsup/inspector-tab/mod.d.ts +4 -3
  96. package/dist/tsup/inspector-tab/mod.js +1 -1
  97. package/dist/tsup/mod.cjs +837 -243
  98. package/dist/tsup/mod.cjs.map +1 -1
  99. package/dist/tsup/mod.d.cts +6 -5
  100. package/dist/tsup/mod.d.ts +6 -5
  101. package/dist/tsup/mod.js +766 -172
  102. package/dist/tsup/mod.js.map +1 -1
  103. package/dist/tsup/test/mod.cjs +7 -7
  104. package/dist/tsup/test/mod.d.cts +3 -2
  105. package/dist/tsup/test/mod.d.ts +3 -2
  106. package/dist/tsup/test/mod.js +5 -5
  107. package/dist/tsup/unstable/migrations.d.cts +1 -1
  108. package/dist/tsup/unstable/migrations.d.ts +1 -1
  109. package/dist/tsup/utils.cjs +2 -2
  110. package/dist/tsup/utils.js +1 -1
  111. package/dist/tsup/workflow/mod.cjs +89 -95
  112. package/dist/tsup/workflow/mod.cjs.map +1 -1
  113. package/dist/tsup/workflow/mod.d.cts +5 -4
  114. package/dist/tsup/workflow/mod.d.ts +5 -4
  115. package/dist/tsup/workflow/mod.js +86 -92
  116. package/dist/tsup/workflow/mod.js.map +1 -1
  117. package/package.json +19 -9
  118. package/src/actor/config.test.ts +65 -1
  119. package/src/actor/config.ts +169 -5
  120. package/src/actor/mod.ts +10 -1
  121. package/src/client/actor-common.ts +5 -14
  122. package/src/common/database/config.ts +50 -3
  123. package/src/common/database/mod.test.ts +142 -4
  124. package/src/common/database/mod.ts +210 -98
  125. package/src/common/database/native-database.ts +42 -3
  126. package/src/common/database/shared.ts +9 -0
  127. package/src/db/drizzle.test.ts +8 -1
  128. package/src/db/drizzle.ts +15 -4
  129. package/src/db/mod.ts +3 -0
  130. package/src/inspector/workflow.ts +61 -0
  131. package/src/registry/napi-runtime.ts +69 -1
  132. package/src/registry/native.ts +505 -155
  133. package/src/registry/run-handler-coordinator.test.ts +252 -0
  134. package/src/registry/run-handler-coordinator.ts +219 -0
  135. package/src/registry/runtime.ts +34 -1
  136. package/src/registry/wasm-runtime.ts +122 -17
  137. package/src/registry/write-through-proxy.ts +101 -0
  138. package/src/utils/node.ts +44 -28
  139. package/src/workflow/driver.ts +56 -58
  140. package/src/workflow/inspector.ts +10 -15
  141. package/src/workflow/mod.ts +48 -70
  142. package/dist/tsup/chunk-2ROUKH7W.cjs.map +0 -1
  143. package/dist/tsup/chunk-7AFZMFPQ.js.map +0 -1
  144. package/dist/tsup/chunk-AGNBLCNJ.js.map +0 -1
  145. package/dist/tsup/chunk-E6WB2BLO.cjs.map +0 -1
  146. package/dist/tsup/chunk-HNHLBM3Y.cjs.map +0 -1
  147. package/dist/tsup/chunk-JBQ63WSM.js.map +0 -1
  148. package/dist/tsup/chunk-KVD6ZWNM.js.map +0 -1
  149. package/dist/tsup/chunk-N6MBTYGX.cjs.map +0 -1
  150. package/dist/tsup/chunk-QWLJCP3X.js.map +0 -1
  151. package/dist/tsup/chunk-UEULFXUI.cjs.map +0 -1
  152. /package/dist/tsup/{chunk-V6ANE6JM.js.map → chunk-FWROC5LA.js.map} +0 -0
  153. /package/dist/tsup/{chunk-WRRB24UY.js.map → chunk-JQ2AZ5FN.js.map} +0 -0
@@ -5,6 +5,7 @@ import type {
5
5
  InferDatabaseClient,
6
6
  } from "@/common/database/config";
7
7
  import type { UniversalWebSocket } from "@/common/websocket-interface";
8
+ import type { WorkflowState } from "@/inspector/workflow";
8
9
  import type { Registry } from "@/registry";
9
10
  import { flattenActionHandlers } from "./actions";
10
11
  import type { BaseActorDefinition } from "./definition";
@@ -64,7 +65,7 @@ type ActorKvListOptions<
64
65
  type ActorClientFor<T> = T extends Registry<any> ? Client<T> : T;
65
66
 
66
67
  /**
67
- * @deprecated Actor KV is deprecated. Use embedded SQLite (`c.db` / `c.sql`)
68
+ * @deprecated Actor KV is deprecated. Use embedded SQLite (`c.db`)
68
69
  * or actor state instead.
69
70
  */
70
71
  export interface ActorKv {
@@ -332,6 +333,16 @@ export interface ActorQueue<
332
333
  names: readonly TName[],
333
334
  opts?: QueueWaitOptions<TCompletable>,
334
335
  ): Promise<any>;
336
+ /** @experimental */
337
+ waitForAvailable<const TName extends QueueFilterName<TQueues>>(
338
+ names?: readonly TName[],
339
+ opts?: Omit<QueueWaitOptions<false>, "completable">,
340
+ ): Promise<void>;
341
+ /** @experimental */
342
+ complete<const TName extends QueueFilterName<TQueues>>(
343
+ message: { id: number | bigint; name: TName },
344
+ ...args: QueueCompleteArgsForName<TQueues, TName>
345
+ ): Promise<void>;
335
346
  enqueueAndWait<const TName extends QueueFilterName<TQueues>>(
336
347
  name: TName,
337
348
  body: QueueMessageForName<TQueues, TName>["body"],
@@ -389,7 +400,7 @@ export interface ActorContext<
389
400
  state: TState;
390
401
  vars: TVars;
391
402
  /**
392
- * @deprecated Actor KV is deprecated. Use embedded SQLite (`db` / `sql`)
403
+ * @deprecated Actor KV is deprecated. Use embedded SQLite (`c.db`)
393
404
  * or actor state instead.
394
405
  */
395
406
  readonly kv: ActorKv;
@@ -397,6 +408,8 @@ export interface ActorContext<
397
408
  readonly schedule: ActorSchedule;
398
409
  readonly cron: ActorCron;
399
410
  readonly queue: ActorQueue<TQueues>;
411
+ /** @experimental */
412
+ readonly run: ActorRun;
400
413
  readonly actorId: string;
401
414
  readonly name: string;
402
415
  readonly key: string[];
@@ -434,6 +447,15 @@ export interface ActorContext<
434
447
  [key: string]: any;
435
448
  }
436
449
 
450
+ /** @experimental */
451
+ export interface ActorRun {
452
+ /**
453
+ * @experimental Sets or clears the durable Unix-millisecond deadline that
454
+ * ensures this actor's run handler is active, starting it if inactive.
455
+ */
456
+ setWakeAt(timestamp: number | null): Promise<void>;
457
+ }
458
+
437
459
  export type ActionContext<
438
460
  TState,
439
461
  TConnParams,
@@ -821,20 +843,27 @@ const zActionTree = z
821
843
 
822
844
  export type InspectorUnsubscribe = () => void;
823
845
 
846
+ /** @experimental */
824
847
  export interface WorkflowInspectorConfig<THistory = unknown> {
825
848
  getHistory: () => THistory | null;
849
+ getState?: () => Promise<WorkflowState | null>;
826
850
  onHistoryUpdated?: (
827
851
  listener: (history: THistory) => void,
828
852
  ) => InspectorUnsubscribe;
829
853
  replayFromStep?: (entryId?: string) => Promise<THistory | null>;
830
854
  }
831
855
 
856
+ /** @experimental */
832
857
  export interface RunInspectorConfig<THistory = unknown> {
833
858
  workflow?: WorkflowInspectorConfig<THistory>;
834
859
  }
835
860
 
836
861
  const WorkflowInspectorConfigSchema = z.object({
837
862
  getHistory: zFunction<WorkflowInspectorConfig<unknown>["getHistory"]>(),
863
+ getState:
864
+ zFunction<
865
+ NonNullable<WorkflowInspectorConfig<unknown>["getState"]>
866
+ >().optional(),
838
867
  onHistoryUpdated:
839
868
  zFunction<
840
869
  NonNullable<WorkflowInspectorConfig<unknown>["onHistoryUpdated"]>
@@ -981,9 +1010,72 @@ type AnyRunConfig = RunConfig<
981
1010
  any
982
1011
  >;
983
1012
 
984
- export const RUN_FUNCTION_CONFIG_SYMBOL = Symbol.for(
985
- "rivetkit.run_function_config",
986
- );
1013
+ const RUN_FUNCTION_CONFIG_SYMBOL = Symbol.for("rivetkit.run_function_config");
1014
+
1015
+ /** @experimental */
1016
+ export type RunInspectorKind = "workflow";
1017
+
1018
+ /** @experimental */
1019
+ export interface RunWithInactiveOptions {
1020
+ /** Restart the run handler before releasing the exclusive gate on success. */
1021
+ restartOnSuccess?: boolean;
1022
+ }
1023
+
1024
+ /** @experimental */
1025
+ export interface RunControl {
1026
+ run: {
1027
+ /**
1028
+ * Executes only while no run handler is active or waiting to start.
1029
+ *
1030
+ * This is a non-blocking acquisition: concurrent replay/control requests
1031
+ * fail instead of waiting behind an active run.
1032
+ */
1033
+ withInactive<T>(
1034
+ options: RunWithInactiveOptions,
1035
+ callback: () => T | Promise<T>,
1036
+ ): Promise<T>;
1037
+ };
1038
+ }
1039
+
1040
+ /** @experimental */
1041
+ export interface RunInspectorFactoryContext {
1042
+ actorId: string;
1043
+ control: RunControl;
1044
+ }
1045
+
1046
+ /** @experimental */
1047
+ export interface RunInspectorFactoryResult<THistory = unknown> {
1048
+ inspector: {
1049
+ workflow: Required<WorkflowInspectorConfig<THistory>> & {
1050
+ getState: () => Promise<WorkflowState | null>;
1051
+ };
1052
+ };
1053
+ /** Releases actor-specific listeners and encoded history. */
1054
+ dispose?: () => void;
1055
+ }
1056
+
1057
+ interface RunHandlerDisplayOptions {
1058
+ name?: string;
1059
+ icon?: string;
1060
+ }
1061
+
1062
+ /** @experimental */
1063
+ export type DefineRunHandlerOptions<THistory = unknown> =
1064
+ RunHandlerDisplayOptions &
1065
+ (
1066
+ | {
1067
+ inspectorKind?: never;
1068
+ createInspector?: never;
1069
+ }
1070
+ | {
1071
+ /** Static metadata used to install Inspector callbacks at registry build time. */
1072
+ inspectorKind: RunInspectorKind;
1073
+ /** Creates one Inspector adapter for each live actor. */
1074
+ createInspector: (
1075
+ context: RunInspectorFactoryContext,
1076
+ ) => RunInspectorFactoryResult<THistory>;
1077
+ }
1078
+ );
987
1079
 
988
1080
  interface RunFunctionConfig {
989
1081
  name?: string;
@@ -992,12 +1084,69 @@ interface RunFunctionConfig {
992
1084
  inspectorFactory?: (actor: unknown) => RunInspectorConfig | undefined;
993
1085
  /** Release any per-actor inspector state held for this actor id. */
994
1086
  disposeInspector?: (actorId: string) => void;
1087
+ inspectorKind?: RunInspectorKind;
1088
+ createInspector?: (
1089
+ context: RunInspectorFactoryContext,
1090
+ ) => RunInspectorFactoryResult;
995
1091
  }
996
1092
 
997
1093
  type RunFunctionWithConfig = ((...args: any[]) => any) & {
998
1094
  [RUN_FUNCTION_CONFIG_SYMBOL]?: RunFunctionConfig;
999
1095
  };
1000
1096
 
1097
+ /**
1098
+ * @experimental Adds supported RivetKit run metadata while preserving the function's exact
1099
+ * callable type.
1100
+ */
1101
+ export function defineRunHandler<
1102
+ TRun extends (...args: any[]) => any,
1103
+ THistory = unknown,
1104
+ >(run: TRun, options: DefineRunHandlerOptions<THistory>): TRun {
1105
+ if (
1106
+ (options.inspectorKind === undefined) !==
1107
+ (options.createInspector === undefined)
1108
+ ) {
1109
+ throw new TypeError(
1110
+ "defineRunHandler requires inspectorKind and createInspector together",
1111
+ );
1112
+ }
1113
+
1114
+ Object.defineProperty(run, RUN_FUNCTION_CONFIG_SYMBOL, {
1115
+ configurable: false,
1116
+ enumerable: false,
1117
+ writable: false,
1118
+ value: {
1119
+ name: options.name,
1120
+ icon: options.icon,
1121
+ inspectorKind: options.inspectorKind,
1122
+ createInspector:
1123
+ options.createInspector as RunFunctionConfig["createInspector"],
1124
+ } satisfies RunFunctionConfig,
1125
+ });
1126
+
1127
+ return run;
1128
+ }
1129
+
1130
+ /** @internal */
1131
+ export function getRunInspectorKind(
1132
+ run: ((...args: any[]) => any) | AnyRunConfig | undefined,
1133
+ ): RunInspectorKind | undefined {
1134
+ if (!run || typeof run !== "function") return undefined;
1135
+ return (run as RunFunctionWithConfig)[RUN_FUNCTION_CONFIG_SYMBOL]
1136
+ ?.inspectorKind;
1137
+ }
1138
+
1139
+ /** @internal */
1140
+ export function createRunInspector(
1141
+ run: ((...args: any[]) => any) | AnyRunConfig | undefined,
1142
+ context: RunInspectorFactoryContext,
1143
+ ): RunInspectorFactoryResult | undefined {
1144
+ if (!run || typeof run !== "function") return undefined;
1145
+ return (run as RunFunctionWithConfig)[
1146
+ RUN_FUNCTION_CONFIG_SYMBOL
1147
+ ]?.createInspector?.(context);
1148
+ }
1149
+
1001
1150
  // Run can be either a function or an object with name/icon/run
1002
1151
  const zRunHandler = z.union([zFunction(), RunConfigSchema]).optional();
1003
1152
 
@@ -1042,6 +1191,21 @@ export function getRunInspectorConfig(
1042
1191
  return run.inspector;
1043
1192
  }
1044
1193
 
1194
+ /** @internal */
1195
+ export function hasRunInspectorConfig(
1196
+ run: ((...args: any[]) => any) | AnyRunConfig | undefined,
1197
+ ): boolean {
1198
+ if (!run) return false;
1199
+ if (typeof run !== "function") return run.inspector !== undefined;
1200
+ const config = (run as RunFunctionWithConfig)[RUN_FUNCTION_CONFIG_SYMBOL];
1201
+ return (
1202
+ config?.inspectorKind !== undefined ||
1203
+ config?.createInspector !== undefined ||
1204
+ config?.inspector !== undefined ||
1205
+ config?.inspectorFactory !== undefined
1206
+ );
1207
+ }
1208
+
1045
1209
  /** Release per-actor inspector state for a destroyed actor, if the run handler registered a disposer. */
1046
1210
  export function disposeRunInspector(
1047
1211
  run: ((...args: any[]) => any) | AnyRunConfig | undefined,
package/src/actor/mod.ts CHANGED
@@ -14,6 +14,7 @@ export type {
14
14
  UniversalWebSocket,
15
15
  } from "@/common/websocket-interface";
16
16
  export type * from "./config";
17
+ export { defineRunHandler } from "./config";
17
18
  export type {
18
19
  ActionContextOf,
19
20
  BeforeActionResponseContextOf,
@@ -57,4 +58,12 @@ export {
57
58
  UserError,
58
59
  type UserErrorOptions,
59
60
  } from "./errors";
60
- export { event, queue, type Type } from "./schema";
61
+ export {
62
+ type EventSchemaConfig,
63
+ event,
64
+ type InferEventArgs,
65
+ type InferSchemaMap,
66
+ type QueueSchemaConfig,
67
+ queue,
68
+ type Type,
69
+ } from "./schema";
@@ -48,20 +48,11 @@ type ActorActionMap<R> = {
48
48
  : never;
49
49
  };
50
50
 
51
- type ActionsOf<AD extends AnyActorDefinition> =
52
- AD extends BaseActorDefinition<
53
- any,
54
- any,
55
- any,
56
- any,
57
- any,
58
- any,
59
- any,
60
- any,
61
- infer R
62
- >
63
- ? R
64
- : never;
51
+ type ActionsOf<AD extends AnyActorDefinition> = AD["config"] extends {
52
+ actions?: infer R;
53
+ }
54
+ ? R
55
+ : never;
65
56
 
66
57
  export interface ActorGatewayOptions {
67
58
  skipReadyWait?: boolean;
@@ -9,7 +9,7 @@ export interface ActorMetricsLike {
9
9
  export type InferDatabaseClient<DBProvider extends AnyDatabaseProvider> =
10
10
  DBProvider extends DatabaseProvider<any>
11
11
  ? Awaited<ReturnType<DBProvider["createClient"]>>
12
- : never;
12
+ : RawAccess;
13
13
 
14
14
  export type SqliteBindings = unknown[] | Record<string, unknown>;
15
15
 
@@ -28,6 +28,43 @@ export interface SqliteBatchStatement {
28
28
  params?: SqliteBindings;
29
29
  }
30
30
 
31
+ export interface SqliteTransactionOptions {
32
+ /** Static operation name used to aggregate transaction performance. */
33
+ name?: string;
34
+ /** Deadlock-safety timeout in milliseconds. */
35
+ timeout?: number;
36
+ /** @experimental */
37
+ experimental?: {
38
+ /**
39
+ * Atomically includes actor and hibernatable connection state.
40
+ * Only single-statement `execute` calls are supported in the transaction.
41
+ * Concurrent actions that try to mutate state while the transaction is
42
+ * active fail with `actor.state_transaction_conflict`.
43
+ */
44
+ includeState?: boolean;
45
+ };
46
+ }
47
+
48
+ /**
49
+ * SQLite profiling configuration.
50
+ *
51
+ * @experimental This entire configuration surface is experimental and subject
52
+ * to change without notice.
53
+ */
54
+ export interface SqliteProfilingOptions {
55
+ enabled?: boolean;
56
+ maxTrackedStatementFingerprints?: number;
57
+ maxTrackedTransactionFingerprints?: number;
58
+ maxPrometheusSeries?: number;
59
+ maxStatementsPerTransactionTrace?: number;
60
+ maxGetPagesRequestsPerTrace?: number;
61
+ maxTransactionNameBytes?: number;
62
+ slowOperationThresholdMs?: number;
63
+ baselineSampleRate?: number;
64
+ maxDiagnosticEventsPerMinute?: number;
65
+ diagnosticEventQueueCapacity?: number;
66
+ }
67
+
31
68
  export interface SqliteNativeMetrics {
32
69
  requestBuildNs: number;
33
70
  serializeNs: number;
@@ -51,7 +88,10 @@ export interface SqliteDatabase {
51
88
  executeBatch(
52
89
  statements: SqliteBatchStatement[],
53
90
  ): Promise<SqliteExecuteResult[]>;
54
- beginTransaction(timeoutMs?: number): Promise<SqliteTransactionDatabase>;
91
+ beginTransaction(
92
+ timeoutMs?: number,
93
+ name?: string,
94
+ ): Promise<SqliteTransactionDatabase>;
55
95
  run(sql: string, params?: SqliteBindings): Promise<void>;
56
96
  query(sql: string, params?: SqliteBindings): Promise<SqliteQueryResult>;
57
97
  nativeMetrics?():
@@ -121,6 +161,13 @@ export interface DatabaseProviderContext {
121
161
  }
122
162
 
123
163
  export type DatabaseProvider<DB extends RawAccess> = {
164
+ /**
165
+ * Local SQLite profiling controls consumed by the actor runtime.
166
+ *
167
+ * @experimental This entire configuration surface is experimental and
168
+ * subject to change without notice.
169
+ */
170
+ sqliteProfiling?: SqliteProfilingOptions;
124
171
  /**
125
172
  * Creates a new database client for the actor.
126
173
  * The result is passed to the actor context as `c.db`.
@@ -165,7 +212,7 @@ export type RawAccess = {
165
212
  /** Runs a callback in an isolated SQLite transaction. */
166
213
  transaction: <T>(
167
214
  callback: (tx: RawAccess) => Promise<T> | T,
168
- options?: { timeout?: number },
215
+ options?: SqliteTransactionOptions,
169
216
  ) => Promise<T>;
170
217
  /**
171
218
  * Returns native SQLite metrics when the active runtime supports them.
@@ -8,14 +8,16 @@ import type {
8
8
  SqliteExecuteResult,
9
9
  SqliteTransactionDatabase,
10
10
  } from "./config";
11
- import { db } from "./mod";
11
+ import { db, registerNativeStateTransactionOpener } from "./mod";
12
12
 
13
13
  let logLines: string[];
14
14
 
15
15
  class FakeSqliteDatabase implements SqliteDatabase {
16
16
  failSql = new Map<string, Error>();
17
17
  executeCalls: { sql: string; params?: SqliteBindings }[] = [];
18
+ stateTransactionTimeouts: Array<number | undefined> = [];
18
19
  transactionTimeouts: Array<number | undefined> = [];
20
+ transactionNames: Array<string | undefined> = [];
19
21
 
20
22
  async exec(): Promise<void> {}
21
23
 
@@ -29,8 +31,10 @@ class FakeSqliteDatabase implements SqliteDatabase {
29
31
 
30
32
  async beginTransaction(
31
33
  timeoutMs?: number,
34
+ name?: string,
32
35
  ): Promise<SqliteTransactionDatabase> {
33
36
  this.transactionTimeouts.push(timeoutMs);
37
+ this.transactionNames.push(name);
34
38
  this.record("BEGIN");
35
39
  return {
36
40
  exec: async () => {},
@@ -42,6 +46,21 @@ class FakeSqliteDatabase implements SqliteDatabase {
42
46
  rollback: async () => this.record("ROLLBACK"),
43
47
  };
44
48
  }
49
+ async beginStateTransaction(
50
+ timeoutMs?: number,
51
+ ): Promise<SqliteTransactionDatabase> {
52
+ this.stateTransactionTimeouts.push(timeoutMs);
53
+ this.record("BEGIN_STATE");
54
+ return {
55
+ exec: async () => {},
56
+ execute: async (sql, params) => {
57
+ this.record(sql, params);
58
+ return emptyResult();
59
+ },
60
+ commit: async () => this.record("COMMIT"),
61
+ rollback: async () => this.record("ROLLBACK"),
62
+ };
63
+ }
45
64
 
46
65
  async executeBatch(
47
66
  statements: Array<{ sql: string; params?: SqliteBindings }>,
@@ -81,7 +100,8 @@ function emptyResult(): SqliteExecuteResult {
81
100
  }
82
101
 
83
102
  function testProviderContext(
84
- database: SqliteDatabase,
103
+ database: FakeSqliteDatabase,
104
+ includeStateTransactions = false,
85
105
  ): DatabaseProviderContext {
86
106
  return {
87
107
  actorId: "actor-a",
@@ -91,7 +111,13 @@ function testProviderContext(
91
111
  batchDelete: async () => {},
92
112
  deleteRange: async () => {},
93
113
  },
94
- nativeDatabaseProvider: { open: async () => database },
114
+ nativeDatabaseProvider: includeStateTransactions
115
+ ? registerNativeStateTransactionOpener(
116
+ { open: async () => database },
117
+ async (timeoutMs?: number) =>
118
+ await database.beginStateTransaction(timeoutMs),
119
+ )
120
+ : { open: async () => database },
95
121
  };
96
122
  }
97
123
 
@@ -128,6 +154,23 @@ describe("db", () => {
128
154
  "COMMIT",
129
155
  ]);
130
156
  expect(nativeDb.transactionTimeouts).toEqual([300_000]);
157
+ expect(nativeDb.transactionNames).toEqual(["rivetkit-migration"]);
158
+ });
159
+
160
+ test("exposes profiling controls to the actor runtime", () => {
161
+ const provider = db({
162
+ profiling: {
163
+ enabled: false,
164
+ maxTrackedStatementFingerprints: 12,
165
+ baselineSampleRate: 0.25,
166
+ },
167
+ });
168
+
169
+ expect(provider.sqliteProfiling).toEqual({
170
+ enabled: false,
171
+ maxTrackedStatementFingerprints: 12,
172
+ baselineSampleRate: 0.25,
173
+ });
131
174
  });
132
175
 
133
176
  test("rolls back migrations when onMigrate fails", async () => {
@@ -163,10 +206,11 @@ describe("db", () => {
163
206
  );
164
207
  return 42;
165
208
  },
166
- { timeout: 120_000 },
209
+ { name: "insert-item", timeout: 120_000 },
167
210
  );
168
211
  expect(value).toBe(42);
169
212
  expect(nativeDb.transactionTimeouts).toEqual([120_000]);
213
+ expect(nativeDb.transactionNames).toEqual(["insert-item"]);
170
214
  expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
171
215
  "BEGIN",
172
216
  "INSERT INTO items(value) VALUES (?)",
@@ -174,6 +218,25 @@ describe("db", () => {
174
218
  ]);
175
219
  });
176
220
 
221
+ test("validates transaction names", async () => {
222
+ const client = await db().createClient(
223
+ testProviderContext(new FakeSqliteDatabase()),
224
+ );
225
+ await expect(
226
+ client.transaction(async () => {}, { name: "" }),
227
+ ).rejects.toThrow("must not be empty");
228
+ });
229
+
230
+ test("defers the configured transaction name byte limit to the runtime", async () => {
231
+ const nativeDb = new FakeSqliteDatabase();
232
+ const client = await db().createClient(testProviderContext(nativeDb));
233
+ const name = "x".repeat(129);
234
+
235
+ await client.transaction(async () => {}, { name });
236
+
237
+ expect(nativeDb.transactionNames).toEqual([name]);
238
+ });
239
+
177
240
  test("rolls back a transaction when the callback throws", async () => {
178
241
  const nativeDb = new FakeSqliteDatabase();
179
242
  const client = await db().createClient(testProviderContext(nativeDb));
@@ -193,6 +256,81 @@ describe("db", () => {
193
256
  ]);
194
257
  });
195
258
 
259
+ test("uses the state-aware transaction bridge when explicitly requested", async () => {
260
+ const nativeDb = new FakeSqliteDatabase();
261
+ const client = await db().createClient(
262
+ testProviderContext(nativeDb, true),
263
+ );
264
+
265
+ await client.transaction(
266
+ async (tx) => {
267
+ await tx.execute(
268
+ "INSERT INTO items(value) VALUES (?)",
269
+ "inside",
270
+ );
271
+ },
272
+ {
273
+ timeout: 120_000,
274
+ experimental: { includeState: true },
275
+ },
276
+ );
277
+
278
+ expect(nativeDb.transactionTimeouts).toEqual([]);
279
+ expect(nativeDb.stateTransactionTimeouts).toEqual([120_000]);
280
+ expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
281
+ "BEGIN_STATE",
282
+ "INSERT INTO items(value) VALUES (?)",
283
+ "COMMIT",
284
+ ]);
285
+ });
286
+
287
+ test("rolls back state-aware transactions when the callback throws", async () => {
288
+ const nativeDb = new FakeSqliteDatabase();
289
+ const client = await db().createClient(
290
+ testProviderContext(nativeDb, true),
291
+ );
292
+
293
+ await expect(
294
+ client.transaction(
295
+ async (tx) => {
296
+ await tx.execute(
297
+ "INSERT INTO items(value) VALUES (?)",
298
+ "inside",
299
+ );
300
+ throw new Error("callback failed");
301
+ },
302
+ { experimental: { includeState: true } },
303
+ ),
304
+ ).rejects.toThrow("callback failed");
305
+ expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
306
+ "BEGIN_STATE",
307
+ "INSERT INTO items(value) VALUES (?)",
308
+ "ROLLBACK",
309
+ ]);
310
+ });
311
+
312
+ test("rejects nested state-aware transactions", async () => {
313
+ const nativeDb = new FakeSqliteDatabase();
314
+ const client = await db().createClient(
315
+ testProviderContext(nativeDb, true),
316
+ );
317
+
318
+ await expect(
319
+ client.transaction(
320
+ async (tx) => {
321
+ await tx.transaction(async () => {}, {
322
+ experimental: { includeState: true },
323
+ });
324
+ },
325
+ { experimental: { includeState: true } },
326
+ ),
327
+ ).rejects.toThrow("not supported for nested transactions");
328
+ expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
329
+ "BEGIN_STATE",
330
+ "ROLLBACK",
331
+ ]);
332
+ });
333
+
196
334
  test("validates transaction timeouts", async () => {
197
335
  const client = await db().createClient(
198
336
  testProviderContext(new FakeSqliteDatabase()),