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
@@ -1,23 +1,78 @@
1
1
  import { getLogger } from "@/common/log";
2
2
  import type {
3
3
  DatabaseProvider,
4
+ NativeDatabaseProvider,
4
5
  RawAccess,
5
6
  SqliteDatabase,
7
+ SqliteProfilingOptions,
6
8
  SqliteTransactionDatabase,
9
+ SqliteTransactionOptions,
7
10
  } from "./config";
8
11
  import {
9
12
  isManualTransactionControl,
10
13
  isSqliteBindingObject,
11
14
  MIGRATION_TRANSACTION_TIMEOUT_MS,
12
15
  toSqliteBindings,
16
+ validateTransactionName,
13
17
  validateTransactionTimeout,
14
18
  } from "./shared";
15
19
 
16
20
  export type { RawAccess } from "./config";
17
21
 
18
- interface DatabaseFactoryConfig {
22
+ export interface DatabaseFactoryConfig {
19
23
  onMigrate?: (db: RawAccess) => Promise<void> | void;
20
24
  warnOnManualTransactions?: boolean;
25
+ /**
26
+ * SQLite profiling configuration.
27
+ *
28
+ * @experimental This entire configuration surface is experimental and
29
+ * subject to change without notice.
30
+ */
31
+ profiling?: SqliteProfilingOptions;
32
+ }
33
+ const nativeStateTransactionOpeners = new WeakMap<
34
+ NativeDatabaseProvider,
35
+ (
36
+ timeoutMs?: number,
37
+ context?: unknown,
38
+ ) => Promise<SqliteTransactionDatabase>
39
+ >();
40
+ type NativeStateTransactionContext = {
41
+ enter(): Promise<unknown>;
42
+ exit(scope: unknown): void;
43
+ };
44
+ const nativeStateTransactionClientBinders = new WeakMap<
45
+ object,
46
+ (context: NativeStateTransactionContext) => object
47
+ >();
48
+
49
+ /** @internal */
50
+ export function registerNativeStateTransactionOpener<
51
+ T extends NativeDatabaseProvider,
52
+ >(
53
+ provider: T,
54
+ opener: (
55
+ timeoutMs?: number,
56
+ context?: unknown,
57
+ ) => Promise<SqliteTransactionDatabase>,
58
+ ): T {
59
+ nativeStateTransactionOpeners.set(provider, opener);
60
+ return provider;
61
+ }
62
+
63
+ /** @internal */
64
+ export function bindNativeStateTransactionContext<T>(
65
+ client: T,
66
+ context: NativeStateTransactionContext,
67
+ ): T {
68
+ if (
69
+ (typeof client !== "object" || client === null) &&
70
+ typeof client !== "function"
71
+ ) {
72
+ return client;
73
+ }
74
+ const bind = nativeStateTransactionClientBinders.get(client as object);
75
+ return (bind?.(context) ?? client) as T;
21
76
  }
22
77
 
23
78
  function hasMultipleStatements(query: string): boolean {
@@ -28,8 +83,10 @@ function hasMultipleStatements(query: string): boolean {
28
83
  export function db({
29
84
  onMigrate,
30
85
  warnOnManualTransactions = true,
86
+ profiling,
31
87
  }: DatabaseFactoryConfig = {}): DatabaseProvider<RawAccess> {
32
- return {
88
+ const provider: DatabaseProvider<RawAccess> = {
89
+ sqliteProfiling: profiling,
33
90
  createClient: async (ctx) => {
34
91
  const nativeDatabaseProvider = ctx.nativeDatabaseProvider;
35
92
  if (!nativeDatabaseProvider) {
@@ -52,110 +109,161 @@ export function db({
52
109
  const createClient = (
53
110
  target: SqliteDatabase | SqliteTransactionDatabase,
54
111
  transactionScoped = false,
55
- ): RawAccess => ({
56
- execute: async <
57
- TRow extends Record<string, unknown> = Record<
58
- string,
59
- unknown
60
- >,
61
- >(
62
- query: string,
63
- ...args: unknown[]
64
- ): Promise<TRow[]> => {
65
- ensureOpen();
66
- if (
67
- !transactionScoped &&
68
- warnOnManualTransactions &&
69
- !manualTransactionWarned &&
70
- !hasMultipleStatements(query) &&
71
- isManualTransactionControl(query)
72
- ) {
73
- manualTransactionWarned = true;
74
- getLogger("database").warn(
75
- { actorId: ctx.actorId },
76
- "Manual cross-call SQLite transactions can interleave with other actor work. Use db.transaction() for coordinated transactions. Set warnOnManualTransactions: false in your db(...) configuration to disable this warning.",
77
- );
78
- }
79
-
80
- const kvReadsBefore = ctx.metrics?.totalKvReads ?? 0;
81
- const kvWritesBefore = ctx.metrics?.totalKvWrites ?? 0;
82
- const start = performance.now();
83
-
84
- try {
85
- if (args.length > 0) {
86
- const bindings =
87
- args.length === 1 &&
88
- isSqliteBindingObject(args[0])
89
- ? toSqliteBindings(args[0])
90
- : toSqliteBindings(args);
91
- const { rows, columns } = await target.execute(
92
- query,
93
- bindings,
94
- );
95
- return rows.map((row) =>
96
- rowToObject<TRow>(row, columns),
112
+ stateTransactionContext?: NativeStateTransactionContext,
113
+ ): RawAccess => {
114
+ const client: RawAccess = {
115
+ execute: async <
116
+ TRow extends Record<string, unknown> = Record<
117
+ string,
118
+ unknown
119
+ >,
120
+ >(
121
+ query: string,
122
+ ...args: unknown[]
123
+ ): Promise<TRow[]> => {
124
+ ensureOpen();
125
+ if (
126
+ !transactionScoped &&
127
+ warnOnManualTransactions &&
128
+ !manualTransactionWarned &&
129
+ !hasMultipleStatements(query) &&
130
+ isManualTransactionControl(query)
131
+ ) {
132
+ manualTransactionWarned = true;
133
+ getLogger("database").warn(
134
+ { actorId: ctx.actorId },
135
+ "Manual cross-call SQLite transactions can interleave with other actor work. Use db.transaction() for coordinated transactions. Set warnOnManualTransactions: false in your db(...) configuration to disable this warning.",
97
136
  );
98
137
  }
99
138
 
100
- if (!hasMultipleStatements(query)) {
101
- const { rows, columns } = await target.execute(
139
+ const kvReadsBefore = ctx.metrics?.totalKvReads ?? 0;
140
+ const kvWritesBefore = ctx.metrics?.totalKvWrites ?? 0;
141
+ const start = performance.now();
142
+
143
+ try {
144
+ if (args.length > 0) {
145
+ const bindings =
146
+ args.length === 1 &&
147
+ isSqliteBindingObject(args[0])
148
+ ? toSqliteBindings(args[0])
149
+ : toSqliteBindings(args);
150
+ const { rows, columns } = await target.execute(
151
+ query,
152
+ bindings,
153
+ );
154
+ return rows.map((row) =>
155
+ rowToObject<TRow>(row, columns),
156
+ );
157
+ }
158
+
159
+ if (!hasMultipleStatements(query)) {
160
+ const { rows, columns } = await target.execute(
161
+ query,
162
+ undefined,
163
+ );
164
+ return rows.map((row) =>
165
+ rowToObject<TRow>(row, columns),
166
+ );
167
+ }
168
+
169
+ return await execMultiStatement<TRow>(
170
+ target,
102
171
  query,
103
- undefined,
104
- );
105
- return rows.map((row) =>
106
- rowToObject<TRow>(row, columns),
107
172
  );
173
+ } finally {
174
+ const durationMs = performance.now() - start;
175
+ ctx.metrics?.trackSql(query, durationMs);
176
+ if (ctx.metrics) {
177
+ const kvReads =
178
+ ctx.metrics.totalKvReads - kvReadsBefore;
179
+ const kvWrites =
180
+ ctx.metrics.totalKvWrites - kvWritesBefore;
181
+ ctx.log?.debug({
182
+ msg: "sql query",
183
+ query: query.slice(0, 120),
184
+ durationMs,
185
+ kvReads,
186
+ kvWrites,
187
+ });
188
+ }
108
189
  }
109
-
110
- return await execMultiStatement<TRow>(target, query);
111
- } finally {
112
- const durationMs = performance.now() - start;
113
- ctx.metrics?.trackSql(query, durationMs);
114
- if (ctx.metrics) {
115
- const kvReads =
116
- ctx.metrics.totalKvReads - kvReadsBefore;
117
- const kvWrites =
118
- ctx.metrics.totalKvWrites - kvWritesBefore;
119
- ctx.log?.debug({
120
- msg: "sql query",
121
- query: query.slice(0, 120),
122
- durationMs,
123
- kvReads,
124
- kvWrites,
125
- });
190
+ },
191
+ transaction: async <T>(
192
+ callback: (tx: RawAccess) => Promise<T> | T,
193
+ options?: SqliteTransactionOptions,
194
+ ): Promise<T> => {
195
+ validateTransactionTimeout(options?.timeout);
196
+ validateTransactionName(options?.name);
197
+ if (
198
+ transactionScoped &&
199
+ options?.experimental?.includeState
200
+ ) {
201
+ throw new Error(
202
+ "experimental.includeState is not supported for nested transactions",
203
+ );
126
204
  }
127
- }
128
- },
129
- transaction: async <T>(
130
- callback: (tx: RawAccess) => Promise<T> | T,
131
- options?: { timeout?: number },
132
- ): Promise<T> => {
133
- validateTransactionTimeout(options?.timeout);
134
- const transaction = await db.beginTransaction(
135
- options?.timeout,
136
- );
137
- const tx = createClient(transaction, true);
138
- try {
139
- const result = await callback(tx);
140
- await transaction.commit();
141
- return result;
142
- } catch (error) {
205
+ const includeState =
206
+ options?.experimental?.includeState === true;
207
+ const stateScope =
208
+ includeState && stateTransactionContext
209
+ ? await stateTransactionContext.enter()
210
+ : undefined;
143
211
  try {
144
- await transaction.rollback();
145
- } catch {
146
- // Preserve the callback or commit error after expiry cleanup.
212
+ const transaction = includeState
213
+ ? await (() => {
214
+ const beginStateTransaction =
215
+ ctx.nativeDatabaseProvider &&
216
+ nativeStateTransactionOpeners.get(
217
+ ctx.nativeDatabaseProvider,
218
+ );
219
+ if (!beginStateTransaction) {
220
+ throw new Error(
221
+ "experimental.includeState is only supported by RivetKit's embedded database provider",
222
+ );
223
+ }
224
+ return beginStateTransaction(
225
+ options?.timeout,
226
+ stateScope,
227
+ );
228
+ })()
229
+ : await db.beginTransaction(
230
+ options?.timeout,
231
+ options?.name,
232
+ );
233
+ const tx = createClient(transaction, true);
234
+ try {
235
+ const result = await callback(tx);
236
+ await transaction.commit();
237
+ return result;
238
+ } catch (error) {
239
+ try {
240
+ await transaction.rollback();
241
+ } catch {
242
+ // Preserve the callback or commit error after expiry cleanup.
243
+ }
244
+ throw error;
245
+ }
246
+ } finally {
247
+ if (stateScope !== undefined) {
248
+ stateTransactionContext?.exit(stateScope);
249
+ }
147
250
  }
148
- throw error;
149
- }
150
- },
151
- close: async () => {
152
- if (!closed) {
153
- closed = true;
154
- await db.close();
155
- }
156
- },
157
- nativeMetrics: () => db.nativeMetrics?.() ?? null,
158
- });
251
+ },
252
+ close: async () => {
253
+ if (!closed) {
254
+ closed = true;
255
+ await db.close();
256
+ }
257
+ },
258
+ nativeMetrics: () => db.nativeMetrics?.() ?? null,
259
+ };
260
+ if (!transactionScoped) {
261
+ nativeStateTransactionClientBinders.set(client, (context) =>
262
+ createClient(target, false, context),
263
+ );
264
+ }
265
+ return client;
266
+ };
159
267
  const client = createClient(db);
160
268
  return client;
161
269
  },
@@ -167,6 +275,7 @@ export function db({
167
275
  }
168
276
  },
169
277
  };
278
+ return provider;
170
279
  }
171
280
 
172
281
  function rowToObject<TRow extends Record<string, unknown>>(
@@ -221,6 +330,9 @@ async function withMigrationSavepoint<T>(
221
330
  throw error;
222
331
  }
223
332
  },
224
- { timeout: MIGRATION_TRANSACTION_TIMEOUT_MS },
333
+ {
334
+ name: "rivetkit-migration",
335
+ timeout: MIGRATION_TRANSACTION_TIMEOUT_MS,
336
+ },
225
337
  );
226
338
  }
@@ -81,7 +81,14 @@ export interface JsNativeDatabaseLike {
81
81
  executeBatch?(
82
82
  statements: NativeBatchStatement[],
83
83
  ): Promise<NativeExecuteResult[]>;
84
- beginTransaction(timeoutMs?: number): Promise<JsNativeTransactionLike>;
84
+ beginStateTransaction?(
85
+ timeoutMs?: number,
86
+ context?: unknown,
87
+ ): Promise<JsNativeTransactionLike>;
88
+ beginTransaction(
89
+ timeoutMs?: number,
90
+ name?: string,
91
+ ): Promise<JsNativeTransactionLike>;
85
92
  query(
86
93
  sql: string,
87
94
  params?: NativeBindParam[] | null,
@@ -94,6 +101,12 @@ export interface JsNativeDatabaseLike {
94
101
  takeLastKvError?(): string | null;
95
102
  close(): Promise<void>;
96
103
  }
104
+ export type StateAwareSqliteDatabase = SqliteDatabase & {
105
+ beginStateTransaction(
106
+ timeoutMs?: number,
107
+ context?: unknown,
108
+ ): Promise<SqliteTransactionDatabase>;
109
+ };
97
110
 
98
111
  export interface JsNativeTransactionLike {
99
112
  exec(sql: string): Promise<NativeExecResult>;
@@ -312,7 +325,7 @@ class NativeCloseGate {
312
325
 
313
326
  export function wrapJsNativeDatabase(
314
327
  database: JsNativeDatabaseLike,
315
- ): SqliteDatabase {
328
+ ): StateAwareSqliteDatabase {
316
329
  const gate = new NativeCloseGate();
317
330
  let closePromise: Promise<void> | undefined;
318
331
  let lastInsertRowId: number | null = null;
@@ -419,11 +432,37 @@ export function wrapJsNativeDatabase(
419
432
  },
420
433
  async beginTransaction(
421
434
  timeoutMs?: number,
435
+ name?: string,
422
436
  ): Promise<SqliteTransactionDatabase> {
423
437
  const release = gate.enter();
424
438
  let transaction: JsNativeTransactionLike;
425
439
  try {
426
- transaction = await database.beginTransaction(timeoutMs);
440
+ transaction = await database.beginTransaction(timeoutMs, name);
441
+ } catch (error) {
442
+ enrichNativeDatabaseError(database, error);
443
+ } finally {
444
+ release();
445
+ }
446
+ return wrapTransaction(database, transaction, gate, (result) => {
447
+ if (result.lastInsertRowId !== undefined) {
448
+ lastInsertRowId = result.lastInsertRowId;
449
+ }
450
+ });
451
+ },
452
+ async beginStateTransaction(
453
+ timeoutMs?: number,
454
+ context?: unknown,
455
+ ): Promise<SqliteTransactionDatabase> {
456
+ if (!database.beginStateTransaction) {
457
+ throw new Error("actor state transactions are not configured");
458
+ }
459
+ const release = gate.enter();
460
+ let transaction: JsNativeTransactionLike;
461
+ try {
462
+ transaction = await database.beginStateTransaction(
463
+ timeoutMs,
464
+ context,
465
+ );
427
466
  } catch (error) {
428
467
  enrichNativeDatabaseError(database, error);
429
468
  } finally {
@@ -15,6 +15,15 @@ export function validateTransactionTimeout(timeout: number | undefined): void {
15
15
  }
16
16
  }
17
17
 
18
+ export function validateTransactionName(name: string | undefined): void {
19
+ if (name === undefined) {
20
+ return;
21
+ }
22
+ if (name.length === 0) {
23
+ throw new Error("db.transaction() name must not be empty");
24
+ }
25
+ }
26
+
18
27
  type SqliteBindingObject = Record<string, unknown>;
19
28
 
20
29
  function isSqliteBindingValue(value: unknown): boolean {
@@ -12,6 +12,7 @@ import { db } from "./drizzle";
12
12
  class FakeSqliteDatabase implements SqliteDatabase {
13
13
  executeCalls: Array<{ sql: string; params?: SqliteBindings }> = [];
14
14
  transactionTimeouts: Array<number | undefined> = [];
15
+ transactionNames: Array<string | undefined> = [];
15
16
 
16
17
  async exec(): Promise<void> {}
17
18
 
@@ -44,8 +45,10 @@ class FakeSqliteDatabase implements SqliteDatabase {
44
45
 
45
46
  async beginTransaction(
46
47
  timeoutMs?: number,
48
+ name?: string,
47
49
  ): Promise<SqliteTransactionDatabase> {
48
50
  this.transactionTimeouts.push(timeoutMs);
51
+ this.transactionNames.push(name);
49
52
  this.executeCalls.push({ sql: "BEGIN" });
50
53
  return {
51
54
  exec: async () => {},
@@ -114,6 +117,9 @@ describe("Drizzle database transactions", () => {
114
117
  await provider.onMigrate(client);
115
118
 
116
119
  expect(nativeDb.transactionTimeouts).toEqual([300_000]);
120
+ expect(nativeDb.transactionNames).toEqual([
121
+ "rivetkit-drizzle-migration",
122
+ ]);
117
123
  expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
118
124
  "BEGIN",
119
125
  "SAVEPOINT __rivet_on_migrate",
@@ -133,10 +139,11 @@ describe("Drizzle database transactions", () => {
133
139
  "inside",
134
140
  );
135
141
  },
136
- { timeout: 120_000 },
142
+ { name: "drizzle-insert", timeout: 120_000 },
137
143
  );
138
144
 
139
145
  expect(nativeDb.transactionTimeouts).toEqual([120_000]);
146
+ expect(nativeDb.transactionNames).toEqual(["drizzle-insert"]);
140
147
  expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
141
148
  "BEGIN",
142
149
  "INSERT INTO items(value) VALUES (?)",
package/src/db/drizzle.ts CHANGED
@@ -7,6 +7,8 @@ import type {
7
7
  DatabaseProvider,
8
8
  DatabaseProviderContext,
9
9
  RawAccess,
10
+ SqliteProfilingOptions,
11
+ SqliteTransactionOptions,
10
12
  SqliteDatabase,
11
13
  SqliteTransactionDatabase,
12
14
  } from "@/common/database/config";
@@ -15,6 +17,7 @@ import {
15
17
  isManualTransactionControl,
16
18
  MIGRATION_TRANSACTION_TIMEOUT_MS,
17
19
  toSqliteBindings,
20
+ validateTransactionName,
18
21
  validateTransactionTimeout,
19
22
  } from "@/common/database/shared";
20
23
  import { sha256Hex } from "@/utils/crypto";
@@ -42,7 +45,7 @@ type DrizzleDatabase<TSchema extends DrizzleSchema> = Omit<
42
45
  Omit<RawAccess, "transaction"> & {
43
46
  transaction: <T>(
44
47
  callback: (tx: DrizzleDatabase<TSchema>) => Promise<T> | T,
45
- options?: { timeout?: number },
48
+ options?: SqliteTransactionOptions,
46
49
  ) => Promise<T>;
47
50
  };
48
51
 
@@ -58,11 +61,12 @@ interface DrizzleMigrations {
58
61
  migrations: Record<string, string>;
59
62
  }
60
63
 
61
- interface DrizzleDatabaseFactoryConfig<TSchema extends DrizzleSchema> {
64
+ export interface DrizzleDatabaseFactoryConfig<TSchema extends DrizzleSchema> {
62
65
  schema?: TSchema;
63
66
  migrations?: DrizzleMigrations;
64
67
  onMigrate?: (db: DrizzleDatabase<TSchema>) => Promise<void> | void;
65
68
  warnOnManualTransactions?: boolean;
69
+ profiling?: SqliteProfilingOptions;
66
70
  }
67
71
 
68
72
  interface DrizzleKitConfig {
@@ -86,10 +90,12 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
86
90
  migrations,
87
91
  onMigrate,
88
92
  warnOnManualTransactions = true,
93
+ profiling,
89
94
  }: DrizzleDatabaseFactoryConfig<TSchema> = {}): DatabaseProvider<
90
95
  DrizzleDatabase<TSchema>
91
96
  > {
92
97
  return {
98
+ sqliteProfiling: profiling,
93
99
  createClient: async (ctx) => {
94
100
  const override = ctx.overrideDrizzleDatabaseClient
95
101
  ? await ctx.overrideDrizzleDatabaseClient()
@@ -194,11 +200,13 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
194
200
  transactionCallback: (
195
201
  tx: DrizzleDatabase<TSchema>,
196
202
  ) => Promise<T> | T,
197
- options?: { timeout?: number },
203
+ options?: SqliteTransactionOptions,
198
204
  ): Promise<T> => {
199
205
  validateTransactionTimeout(options?.timeout);
206
+ validateTransactionName(options?.name);
200
207
  const transaction = await nativeDb.beginTransaction(
201
208
  options?.timeout,
209
+ options?.name,
202
210
  );
203
211
  const tx = createDrizzleClient(transaction, true);
204
212
  try {
@@ -286,7 +294,10 @@ async function withMigrationSavepoint<TSchema extends DrizzleSchema, T>(
286
294
  throw error;
287
295
  }
288
296
  },
289
- { timeout: MIGRATION_TRANSACTION_TIMEOUT_MS },
297
+ {
298
+ name: "rivetkit-drizzle-migration",
299
+ timeout: MIGRATION_TRANSACTION_TIMEOUT_MS,
300
+ },
290
301
  );
291
302
  }
292
303
 
package/src/db/mod.ts CHANGED
@@ -2,12 +2,15 @@ export type {
2
2
  AnyDatabaseProvider,
3
3
  DatabaseProvider,
4
4
  DatabaseProviderContext,
5
+ InferDatabaseClient,
5
6
  NativeDatabaseProvider,
6
7
  RawAccess,
7
8
  RawDatabaseClient,
8
9
  SqliteBindings,
9
10
  SqliteDatabase,
10
11
  SqliteNativeMetrics,
12
+ SqliteProfilingOptions,
11
13
  SqliteQueryResult,
14
+ SqliteTransactionOptions,
12
15
  } from "@/common/database/config";
13
16
  export { db } from "@/common/database/mod";
@@ -0,0 +1,61 @@
1
+ import type { JsonCompatValue } from "@/common/encoding";
2
+ import type { WorkflowHistoryBytes } from "@/common/inspector-transport";
3
+ import { encodeCborCompat } from "@/serde";
4
+ import { bufferToArrayBuffer } from "@/utils";
5
+
6
+ export type {
7
+ WorkflowBranchStatus,
8
+ WorkflowCbor,
9
+ WorkflowEntry,
10
+ WorkflowEntryKind,
11
+ WorkflowEntryMetadata,
12
+ WorkflowHistory,
13
+ WorkflowJoinEntry,
14
+ WorkflowLocation,
15
+ WorkflowLoopEntry,
16
+ WorkflowLoopIterationMarker,
17
+ WorkflowMessageEntry,
18
+ WorkflowNameIndex,
19
+ WorkflowPathSegment,
20
+ WorkflowRaceEntry,
21
+ WorkflowRemovedEntry,
22
+ WorkflowRollbackCheckpointEntry,
23
+ WorkflowSleepEntry,
24
+ WorkflowStepEntry,
25
+ WorkflowVersionCheckEntry,
26
+ } from "@/common/bare/transport/v1";
27
+ export {
28
+ WorkflowBranchStatusType,
29
+ WorkflowEntryStatus,
30
+ WorkflowSleepState,
31
+ } from "@/common/bare/transport/v1";
32
+ export type { WorkflowHistoryBytes } from "@/common/inspector-transport";
33
+ export {
34
+ decodeWorkflowHistoryTransport,
35
+ encodeWorkflowHistoryTransport,
36
+ } from "@/common/inspector-transport";
37
+
38
+ /** @experimental State exposed by a durable workflow run handler to the Inspector. */
39
+ export type WorkflowState =
40
+ | "pending"
41
+ | "running"
42
+ | "sleeping"
43
+ | "failed"
44
+ | "completed"
45
+ | "cancelled"
46
+ | "rolling_back";
47
+
48
+ /** @experimental The raw workflow Inspector adapter consumed by RivetKit's transport. */
49
+ export interface WorkflowInspectorAdapter {
50
+ getHistory: () => WorkflowHistoryBytes | null;
51
+ getState: () => Promise<WorkflowState | null>;
52
+ onHistoryUpdated: (
53
+ listener: (history: WorkflowHistoryBytes) => void,
54
+ ) => () => void;
55
+ replayFromStep: (entryId?: string) => Promise<WorkflowHistoryBytes | null>;
56
+ }
57
+
58
+ /** @experimental Encodes a workflow Inspector value with RivetKit's CBOR-compatible codec. */
59
+ export function encodeWorkflowInspectorValue(value: unknown): ArrayBuffer {
60
+ return bufferToArrayBuffer(encodeCborCompat(value as JsonCompatValue));
61
+ }