rivetkit 2.3.4 → 2.3.5
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/browser/client.d.ts +157 -9
- package/dist/browser/client.js +518 -542
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.d.ts +101 -2
- package/dist/browser/inspector/client.js +1245 -227
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/agent-os/index.cjs +103 -36
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +159 -11
- package/dist/tsup/agent-os/index.d.ts +159 -11
- package/dist/tsup/agent-os/index.js +103 -36
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-7X4M7ZRA.cjs → chunk-2GZPBFZV.cjs} +146 -177
- package/dist/tsup/chunk-2GZPBFZV.cjs.map +1 -0
- package/dist/tsup/{chunk-JZ7TWV65.js → chunk-7AFZMFPQ.js} +15 -1
- package/dist/tsup/chunk-7AFZMFPQ.js.map +1 -0
- package/dist/tsup/{chunk-UPOCJPEQ.cjs → chunk-7HDG7FY3.cjs} +4 -4
- package/dist/tsup/{chunk-UPOCJPEQ.cjs.map → chunk-7HDG7FY3.cjs.map} +1 -1
- package/dist/tsup/{chunk-T4MURX4P.cjs → chunk-7IIAJQTF.cjs} +7 -7
- package/dist/tsup/{chunk-T4MURX4P.cjs.map → chunk-7IIAJQTF.cjs.map} +1 -1
- package/dist/tsup/{chunk-EOSGY3DC.js → chunk-ENPXVDGZ.js} +2 -2
- package/dist/tsup/{chunk-GXW3VFJQ.js → chunk-FJQ36P7Q.js} +2 -2
- package/dist/tsup/{chunk-3MHDOUD7.cjs → chunk-G3CCRCTK.cjs} +14 -9
- package/dist/tsup/chunk-G3CCRCTK.cjs.map +1 -0
- package/dist/tsup/{chunk-Q7NBMTF3.cjs → chunk-ID7DMKXR.cjs} +384 -4
- package/dist/tsup/chunk-ID7DMKXR.cjs.map +1 -0
- package/dist/tsup/{chunk-HXUEHHJF.js → chunk-JI6GZ2C2.js} +2 -11
- package/dist/tsup/{chunk-HXUEHHJF.js.map → chunk-JI6GZ2C2.js.map} +1 -1
- package/dist/tsup/{chunk-VE2X4KMG.cjs → chunk-MYWZCDML.cjs} +2 -11
- package/dist/tsup/chunk-MYWZCDML.cjs.map +1 -0
- package/dist/tsup/{chunk-M5TAM4JV.js → chunk-NYEGEML6.js} +3 -3
- package/dist/tsup/{chunk-SRT2DPN3.cjs → chunk-PG5P2IDC.cjs} +9 -11
- package/dist/tsup/chunk-PG5P2IDC.cjs.map +1 -0
- package/dist/tsup/{chunk-CMPFZ724.js → chunk-PMIEL4PM.js} +16 -47
- package/dist/tsup/{chunk-CMPFZ724.js.map → chunk-PMIEL4PM.js.map} +1 -1
- package/dist/tsup/{chunk-XIX5DOZN.js → chunk-SHBE77IT.js} +14 -9
- package/dist/tsup/chunk-SHBE77IT.js.map +1 -0
- package/dist/tsup/{chunk-3SNFA373.cjs → chunk-TKPQNJQ2.cjs} +3 -3
- package/dist/tsup/{chunk-3SNFA373.cjs.map → chunk-TKPQNJQ2.cjs.map} +1 -1
- package/dist/tsup/{chunk-ZA7FLHKH.cjs → chunk-UEULFXUI.cjs} +16 -2
- package/dist/tsup/chunk-UEULFXUI.cjs.map +1 -0
- package/dist/tsup/{chunk-H4XOUVGP.js → chunk-WGRSAJSX.js} +5 -7
- package/dist/tsup/{chunk-H4XOUVGP.js.map → chunk-WGRSAJSX.js.map} +1 -1
- package/dist/tsup/{chunk-M7DCRMOZ.js → chunk-YOP6FRYG.js} +382 -2
- package/dist/tsup/chunk-YOP6FRYG.js.map +1 -0
- package/dist/tsup/client/mod.cjs +7 -8
- package/dist/tsup/client/mod.cjs.map +1 -1
- package/dist/tsup/client/mod.d.cts +5 -4
- package/dist/tsup/client/mod.d.ts +5 -4
- package/dist/tsup/client/mod.js +6 -7
- package/dist/tsup/common/log.cjs +2 -2
- package/dist/tsup/common/log.js +1 -1
- package/dist/tsup/common/websocket.cjs +3 -3
- package/dist/tsup/common/websocket.js +2 -2
- package/dist/tsup/{config-D49x8NpL.d.cts → config-BxOimoGX.d.cts} +16 -0
- package/dist/tsup/{config-D49x8NpL.d.ts → config-BxOimoGX.d.ts} +16 -0
- package/dist/tsup/{config-ZkIsRFsN.d.ts → config-BzdqbLAP.d.ts} +164 -27
- package/dist/tsup/{config-BfBhjEbk.d.cts → config-CPPEwn_e.d.cts} +164 -27
- package/dist/tsup/{context-sZ9GlaBK.d.cts → context-DSA9gFXB.d.cts} +2 -2
- package/dist/tsup/{context-B7-84u9K.d.ts → context-wWv-K2K_.d.ts} +2 -2
- package/dist/tsup/db/drizzle.cjs +120 -68
- package/dist/tsup/db/drizzle.cjs.map +1 -1
- package/dist/tsup/db/drizzle.d.cts +8 -3
- package/dist/tsup/db/drizzle.d.ts +8 -3
- package/dist/tsup/db/drizzle.js +120 -68
- package/dist/tsup/db/drizzle.js.map +1 -1
- package/dist/tsup/db/mod.cjs +74 -22
- package/dist/tsup/db/mod.cjs.map +1 -1
- package/dist/tsup/db/mod.d.cts +4 -3
- package/dist/tsup/db/mod.d.ts +4 -3
- package/dist/tsup/db/mod.js +74 -22
- package/dist/tsup/db/mod.js.map +1 -1
- package/dist/tsup/dynamic/mod.cjs +2 -2
- package/dist/tsup/dynamic/mod.d.cts +3 -3
- package/dist/tsup/dynamic/mod.d.ts +3 -3
- package/dist/tsup/dynamic/mod.js +1 -1
- package/dist/tsup/inspector/mod.cjs +4 -5
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.js +3 -4
- package/dist/tsup/inspector/mod.js.map +1 -1
- package/dist/tsup/inspector-tab/mod.cjs +2 -2
- package/dist/tsup/inspector-tab/mod.cjs.map +1 -1
- package/dist/tsup/inspector-tab/mod.d.cts +5 -5
- package/dist/tsup/inspector-tab/mod.d.ts +5 -5
- package/dist/tsup/inspector-tab/mod.js +1 -1
- package/dist/tsup/inspector-tab/mod.js.map +1 -1
- package/dist/tsup/mod.cjs +605 -158
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +5 -5
- package/dist/tsup/mod.d.ts +5 -5
- package/dist/tsup/mod.js +528 -81
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +10 -11
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +3 -3
- package/dist/tsup/test/mod.d.ts +3 -3
- package/dist/tsup/test/mod.js +6 -7
- package/dist/tsup/test/mod.js.map +1 -1
- package/dist/tsup/utils-CV0akuDD.d.ts +162 -0
- package/dist/tsup/utils-DQDCphrl.d.cts +162 -0
- package/dist/tsup/utils.cjs +6 -2
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +3 -146
- package/dist/tsup/utils.d.ts +3 -146
- package/dist/tsup/utils.js +5 -1
- package/dist/tsup/workflow/mod.cjs +198 -151
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +5 -5
- package/dist/tsup/workflow/mod.d.ts +5 -5
- package/dist/tsup/workflow/mod.js +187 -140
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +8 -8
- package/src/actor/config.test.ts +14 -0
- package/src/actor/config.ts +104 -16
- package/src/actor/definition.ts +18 -7
- package/src/agent-os/actor/index.ts +2 -2
- package/src/common/bare/generated/actor-runtime-socket-protocol/v1.ts +848 -0
- package/src/common/bare/generated/inspector/v6.ts +1367 -0
- package/src/common/database/config.ts +24 -0
- package/src/common/database/mod.test.ts +148 -59
- package/src/common/database/mod.ts +93 -23
- package/src/common/database/native-database.test.ts +9 -0
- package/src/common/database/native-database.ts +151 -0
- package/src/common/database/shared.ts +15 -0
- package/src/common/encoding.ts +28 -21
- package/src/db/drizzle.test.ts +157 -0
- package/src/db/drizzle.ts +170 -79
- package/src/dynamic/isolate-runtime.ts +0 -2
- package/src/engine-client/driver.ts +0 -15
- package/src/engine-client/mod.ts +0 -41
- package/src/inspector/client.browser.ts +69 -8
- package/src/inspector-tab/mod.ts +1 -0
- package/src/registry/config/index.ts +1 -35
- package/src/registry/napi-runtime.ts +204 -16
- package/src/registry/native.ts +200 -30
- package/src/registry/runtime.ts +146 -3
- package/src/registry/wasm-runtime.ts +217 -6
- package/src/utils.ts +3 -0
- package/src/workflow/context.ts +5 -27
- package/src/workflow/driver.test.ts +62 -0
- package/src/workflow/driver.ts +231 -113
- package/src/workflow/mod.ts +3 -3
- package/dist/tsup/chunk-3MHDOUD7.cjs.map +0 -1
- package/dist/tsup/chunk-7X4M7ZRA.cjs.map +0 -1
- package/dist/tsup/chunk-JZ7TWV65.js.map +0 -1
- package/dist/tsup/chunk-M7DCRMOZ.js.map +0 -1
- package/dist/tsup/chunk-Q7NBMTF3.cjs.map +0 -1
- package/dist/tsup/chunk-SRT2DPN3.cjs.map +0 -1
- package/dist/tsup/chunk-VE2X4KMG.cjs.map +0 -1
- package/dist/tsup/chunk-W6WPKZ6I.js +0 -382
- package/dist/tsup/chunk-W6WPKZ6I.js.map +0 -1
- package/dist/tsup/chunk-XIX5DOZN.js.map +0 -1
- package/dist/tsup/chunk-Z7PSQWMC.cjs +0 -382
- package/dist/tsup/chunk-Z7PSQWMC.cjs.map +0 -1
- package/dist/tsup/chunk-ZA7FLHKH.cjs.map +0 -1
- package/src/actor/driver.ts +0 -141
- package/src/actor/instance/mod.ts +0 -2484
- package/src/drivers/engine/actor-driver.ts +0 -2473
- /package/dist/tsup/{chunk-EOSGY3DC.js.map → chunk-ENPXVDGZ.js.map} +0 -0
- /package/dist/tsup/{chunk-GXW3VFJQ.js.map → chunk-FJQ36P7Q.js.map} +0 -0
- /package/dist/tsup/{chunk-M5TAM4JV.js.map → chunk-NYEGEML6.js.map} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { decodeBridgeRivetError } from "@/actor/errors";
|
|
2
2
|
import type {
|
|
3
|
+
SqliteBatchStatement,
|
|
3
4
|
SqliteBindings,
|
|
4
5
|
SqliteDatabase,
|
|
5
6
|
SqliteExecuteResult,
|
|
6
7
|
SqliteNativeMetrics,
|
|
8
|
+
SqliteTransactionDatabase,
|
|
7
9
|
} from "./config";
|
|
8
10
|
|
|
9
11
|
type NativeBindNoValues = {
|
|
@@ -65,12 +67,21 @@ interface NativeExecuteResult {
|
|
|
65
67
|
lastInsertRowId?: number | null;
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
interface NativeBatchStatement {
|
|
71
|
+
sql: string;
|
|
72
|
+
params?: NativeBindParam[] | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
export interface JsNativeDatabaseLike {
|
|
69
76
|
exec(sql: string): Promise<NativeExecResult>;
|
|
70
77
|
execute(
|
|
71
78
|
sql: string,
|
|
72
79
|
params?: NativeBindParam[] | null,
|
|
73
80
|
): Promise<NativeExecuteResult>;
|
|
81
|
+
executeBatch?(
|
|
82
|
+
statements: NativeBatchStatement[],
|
|
83
|
+
): Promise<NativeExecuteResult[]>;
|
|
84
|
+
beginTransaction(timeoutMs?: number): Promise<JsNativeTransactionLike>;
|
|
74
85
|
query(
|
|
75
86
|
sql: string,
|
|
76
87
|
params?: NativeBindParam[] | null,
|
|
@@ -84,6 +95,16 @@ export interface JsNativeDatabaseLike {
|
|
|
84
95
|
close(): Promise<void>;
|
|
85
96
|
}
|
|
86
97
|
|
|
98
|
+
export interface JsNativeTransactionLike {
|
|
99
|
+
exec(sql: string): Promise<NativeExecResult>;
|
|
100
|
+
execute(
|
|
101
|
+
sql: string,
|
|
102
|
+
params?: NativeBindParam[] | null,
|
|
103
|
+
): Promise<NativeExecuteResult>;
|
|
104
|
+
commit(): Promise<void>;
|
|
105
|
+
rollback(): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
|
|
87
108
|
function shouldAttachNativeKvError(message: string): boolean {
|
|
88
109
|
return /i\/o error|unable to open database file/i.test(message);
|
|
89
110
|
}
|
|
@@ -207,6 +228,15 @@ function toNativeBindings(
|
|
|
207
228
|
});
|
|
208
229
|
}
|
|
209
230
|
|
|
231
|
+
function toNativeBatchStatement(
|
|
232
|
+
statement: SqliteBatchStatement,
|
|
233
|
+
): NativeBatchStatement {
|
|
234
|
+
return {
|
|
235
|
+
sql: statement.sql,
|
|
236
|
+
params: toNativeBindings(statement.sql, statement.params),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
210
240
|
function normalizeNativeMetrics(
|
|
211
241
|
metrics: SqliteNativeMetrics | null | undefined,
|
|
212
242
|
): SqliteNativeMetrics | null {
|
|
@@ -343,6 +373,68 @@ export function wrapJsNativeDatabase(
|
|
|
343
373
|
): Promise<SqliteExecuteResult> {
|
|
344
374
|
return await executeNative(sql, params);
|
|
345
375
|
},
|
|
376
|
+
async executeBatch(
|
|
377
|
+
statements: SqliteBatchStatement[],
|
|
378
|
+
): Promise<SqliteExecuteResult[]> {
|
|
379
|
+
const nativeStatements = statements.map(toNativeBatchStatement);
|
|
380
|
+
const release = gate.enter();
|
|
381
|
+
let transaction: JsNativeTransactionLike | undefined;
|
|
382
|
+
try {
|
|
383
|
+
const results = database.executeBatch
|
|
384
|
+
? await database.executeBatch(nativeStatements)
|
|
385
|
+
: await (async () => {
|
|
386
|
+
transaction = await database.beginTransaction();
|
|
387
|
+
const transactionResults: NativeExecuteResult[] =
|
|
388
|
+
[];
|
|
389
|
+
for (const statement of nativeStatements) {
|
|
390
|
+
transactionResults.push(
|
|
391
|
+
await transaction.execute(
|
|
392
|
+
statement.sql,
|
|
393
|
+
statement.params,
|
|
394
|
+
),
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
await transaction.commit();
|
|
398
|
+
transaction = undefined;
|
|
399
|
+
return transactionResults;
|
|
400
|
+
})();
|
|
401
|
+
for (const result of results) {
|
|
402
|
+
if (result.lastInsertRowId !== undefined) {
|
|
403
|
+
lastInsertRowId = result.lastInsertRowId;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return results;
|
|
407
|
+
} catch (error) {
|
|
408
|
+
if (transaction) {
|
|
409
|
+
try {
|
|
410
|
+
await transaction.rollback();
|
|
411
|
+
} catch {
|
|
412
|
+
// The original batch error is more actionable than cleanup failure.
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
enrichNativeDatabaseError(database, error);
|
|
416
|
+
} finally {
|
|
417
|
+
release();
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
async beginTransaction(
|
|
421
|
+
timeoutMs?: number,
|
|
422
|
+
): Promise<SqliteTransactionDatabase> {
|
|
423
|
+
const release = gate.enter();
|
|
424
|
+
let transaction: JsNativeTransactionLike;
|
|
425
|
+
try {
|
|
426
|
+
transaction = await database.beginTransaction(timeoutMs);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
enrichNativeDatabaseError(database, error);
|
|
429
|
+
} finally {
|
|
430
|
+
release();
|
|
431
|
+
}
|
|
432
|
+
return wrapTransaction(database, transaction, gate, (result) => {
|
|
433
|
+
if (result.lastInsertRowId !== undefined) {
|
|
434
|
+
lastInsertRowId = result.lastInsertRowId;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
},
|
|
346
438
|
async run(sql: string, params?: SqliteBindings): Promise<void> {
|
|
347
439
|
await executeNative(sql, params);
|
|
348
440
|
},
|
|
@@ -360,6 +452,65 @@ export function wrapJsNativeDatabase(
|
|
|
360
452
|
};
|
|
361
453
|
}
|
|
362
454
|
|
|
455
|
+
function wrapTransaction(
|
|
456
|
+
database: JsNativeDatabaseLike,
|
|
457
|
+
transaction: JsNativeTransactionLike,
|
|
458
|
+
gate: NativeCloseGate,
|
|
459
|
+
onExecute: (result: NativeExecuteResult) => void,
|
|
460
|
+
): SqliteTransactionDatabase {
|
|
461
|
+
return {
|
|
462
|
+
async exec(sql, callback) {
|
|
463
|
+
const release = gate.enter();
|
|
464
|
+
let result: NativeExecResult;
|
|
465
|
+
try {
|
|
466
|
+
result = await transaction.exec(sql);
|
|
467
|
+
} catch (error) {
|
|
468
|
+
enrichNativeDatabaseError(database, error);
|
|
469
|
+
} finally {
|
|
470
|
+
release();
|
|
471
|
+
}
|
|
472
|
+
if (callback) {
|
|
473
|
+
for (const row of result.rows) callback(row, result.columns);
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
async execute(sql, params) {
|
|
477
|
+
const release = gate.enter();
|
|
478
|
+
try {
|
|
479
|
+
const result = await transaction.execute(
|
|
480
|
+
sql,
|
|
481
|
+
toNativeBindings(sql, params),
|
|
482
|
+
);
|
|
483
|
+
onExecute(result);
|
|
484
|
+
return result;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
enrichNativeDatabaseError(database, error);
|
|
487
|
+
} finally {
|
|
488
|
+
release();
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
async commit() {
|
|
492
|
+
const release = gate.enter();
|
|
493
|
+
try {
|
|
494
|
+
await transaction.commit();
|
|
495
|
+
} catch (error) {
|
|
496
|
+
enrichNativeDatabaseError(database, error);
|
|
497
|
+
} finally {
|
|
498
|
+
release();
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
async rollback() {
|
|
502
|
+
const release = gate.enter();
|
|
503
|
+
try {
|
|
504
|
+
await transaction.rollback();
|
|
505
|
+
} catch (error) {
|
|
506
|
+
enrichNativeDatabaseError(database, error);
|
|
507
|
+
} finally {
|
|
508
|
+
release();
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
363
514
|
function lastInsertRowIdColumnName(sql: string): string | undefined {
|
|
364
515
|
const match = sql.match(
|
|
365
516
|
/^\s*SELECT\s+last_insert_rowid\s*\(\s*\)\s*(?:AS\s+("[^"]+"|`[^`]+`|\[[^\]]+\]|\w+))?\s*;?\s*$/i,
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import type { SqliteBindings } from "./config";
|
|
2
2
|
|
|
3
|
+
/** Migrations may legitimately do substantially more work than request transactions. */
|
|
4
|
+
export const MIGRATION_TRANSACTION_TIMEOUT_MS = 5 * 60_000;
|
|
5
|
+
|
|
6
|
+
export function isManualTransactionControl(query: string): boolean {
|
|
7
|
+
return /^\s*(?:BEGIN|SAVEPOINT|COMMIT|END|ROLLBACK)\b/i.test(query);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function validateTransactionTimeout(timeout: number | undefined): void {
|
|
11
|
+
if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"db.transaction() timeout must be a positive finite number of milliseconds",
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
type SqliteBindingObject = Record<string, unknown>;
|
|
4
19
|
|
|
5
20
|
function isSqliteBindingValue(value: unknown): boolean {
|
package/src/common/encoding.ts
CHANGED
|
@@ -473,27 +473,34 @@ function base64DecodeToArrayBuffer(base64: string): ArrayBuffer {
|
|
|
473
473
|
}
|
|
474
474
|
|
|
475
475
|
/** Stringifies with compat for values that BARE & CBOR supports. */
|
|
476
|
-
export function jsonStringifyCompat(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
value
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
476
|
+
export function jsonStringifyCompat(
|
|
477
|
+
input: any,
|
|
478
|
+
space?: string | number,
|
|
479
|
+
): string {
|
|
480
|
+
return JSON.stringify(
|
|
481
|
+
input,
|
|
482
|
+
(_key, value) => {
|
|
483
|
+
if (typeof value === "bigint") {
|
|
484
|
+
return [JSON_COMPAT_BIGINT, value.toString()];
|
|
485
|
+
}
|
|
486
|
+
if (value instanceof ArrayBuffer) {
|
|
487
|
+
return [JSON_COMPAT_ARRAY_BUFFER, base64EncodeArrayBuffer(value)];
|
|
488
|
+
}
|
|
489
|
+
if (value instanceof Uint8Array) {
|
|
490
|
+
return [JSON_COMPAT_UINT8_ARRAY, base64EncodeUint8Array(value)];
|
|
491
|
+
}
|
|
492
|
+
if (
|
|
493
|
+
Array.isArray(value) &&
|
|
494
|
+
value.length === 2 &&
|
|
495
|
+
typeof value[0] === "string" &&
|
|
496
|
+
value[0].startsWith("$")
|
|
497
|
+
) {
|
|
498
|
+
return [`$${value[0]}`, value[1]];
|
|
499
|
+
}
|
|
500
|
+
return value;
|
|
501
|
+
},
|
|
502
|
+
space,
|
|
503
|
+
);
|
|
497
504
|
}
|
|
498
505
|
|
|
499
506
|
/** Parses JSON with compat for values that BARE & CBOR supports. */
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type {
|
|
3
|
+
DatabaseProviderContext,
|
|
4
|
+
SqliteBatchStatement,
|
|
5
|
+
SqliteBindings,
|
|
6
|
+
SqliteDatabase,
|
|
7
|
+
SqliteExecuteResult,
|
|
8
|
+
SqliteTransactionDatabase,
|
|
9
|
+
} from "@/common/database/config";
|
|
10
|
+
import { db } from "./drizzle";
|
|
11
|
+
|
|
12
|
+
class FakeSqliteDatabase implements SqliteDatabase {
|
|
13
|
+
executeCalls: Array<{ sql: string; params?: SqliteBindings }> = [];
|
|
14
|
+
transactionTimeouts: Array<number | undefined> = [];
|
|
15
|
+
|
|
16
|
+
async exec(): Promise<void> {}
|
|
17
|
+
|
|
18
|
+
async execute(
|
|
19
|
+
sql: string,
|
|
20
|
+
params?: SqliteBindings,
|
|
21
|
+
): Promise<SqliteExecuteResult> {
|
|
22
|
+
this.executeCalls.push({ sql, params });
|
|
23
|
+
return emptyResult();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async executeBatch(
|
|
27
|
+
statements: SqliteBatchStatement[],
|
|
28
|
+
): Promise<SqliteExecuteResult[]> {
|
|
29
|
+
const transaction = await this.beginTransaction();
|
|
30
|
+
try {
|
|
31
|
+
const results: SqliteExecuteResult[] = [];
|
|
32
|
+
for (const statement of statements) {
|
|
33
|
+
results.push(
|
|
34
|
+
await transaction.execute(statement.sql, statement.params),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
await transaction.commit();
|
|
38
|
+
return results;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
await transaction.rollback();
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async beginTransaction(
|
|
46
|
+
timeoutMs?: number,
|
|
47
|
+
): Promise<SqliteTransactionDatabase> {
|
|
48
|
+
this.transactionTimeouts.push(timeoutMs);
|
|
49
|
+
this.executeCalls.push({ sql: "BEGIN" });
|
|
50
|
+
return {
|
|
51
|
+
exec: async () => {},
|
|
52
|
+
execute: async (sql, params) => {
|
|
53
|
+
this.executeCalls.push({ sql, params });
|
|
54
|
+
return emptyResult();
|
|
55
|
+
},
|
|
56
|
+
commit: async () => {
|
|
57
|
+
this.executeCalls.push({ sql: "COMMIT" });
|
|
58
|
+
},
|
|
59
|
+
rollback: async () => {
|
|
60
|
+
this.executeCalls.push({ sql: "ROLLBACK" });
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async run(sql: string, params?: SqliteBindings): Promise<void> {
|
|
66
|
+
await this.execute(sql, params);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async query(sql: string, params?: SqliteBindings) {
|
|
70
|
+
const { columns, rows } = await this.execute(sql, params);
|
|
71
|
+
return { columns, rows };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async close(): Promise<void> {}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function emptyResult(): SqliteExecuteResult {
|
|
78
|
+
return {
|
|
79
|
+
columns: [],
|
|
80
|
+
rows: [],
|
|
81
|
+
changes: 0,
|
|
82
|
+
lastInsertRowId: null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function testProviderContext(
|
|
87
|
+
database: SqliteDatabase,
|
|
88
|
+
): DatabaseProviderContext {
|
|
89
|
+
return {
|
|
90
|
+
actorId: "actor-a",
|
|
91
|
+
kv: {
|
|
92
|
+
batchPut: async () => {},
|
|
93
|
+
batchGet: async (keys) => keys.map(() => null),
|
|
94
|
+
batchDelete: async () => {},
|
|
95
|
+
deleteRange: async () => {},
|
|
96
|
+
},
|
|
97
|
+
nativeDatabaseProvider: { open: async () => database },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
describe("Drizzle database transactions", () => {
|
|
102
|
+
test("runs migrations in the shared transaction with a generous timeout", async () => {
|
|
103
|
+
const nativeDb = new FakeSqliteDatabase();
|
|
104
|
+
const provider = db({
|
|
105
|
+
onMigrate: async (client) => {
|
|
106
|
+
await client.execute(
|
|
107
|
+
"CREATE TABLE items(id INTEGER PRIMARY KEY)",
|
|
108
|
+
);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const client = await provider.createClient(
|
|
112
|
+
testProviderContext(nativeDb),
|
|
113
|
+
);
|
|
114
|
+
await provider.onMigrate(client);
|
|
115
|
+
|
|
116
|
+
expect(nativeDb.transactionTimeouts).toEqual([300_000]);
|
|
117
|
+
expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
|
|
118
|
+
"BEGIN",
|
|
119
|
+
"SAVEPOINT __rivet_on_migrate",
|
|
120
|
+
"CREATE TABLE items(id INTEGER PRIMARY KEY)",
|
|
121
|
+
"RELEASE SAVEPOINT __rivet_on_migrate",
|
|
122
|
+
"COMMIT",
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("routes transaction work through the transaction handle", async () => {
|
|
127
|
+
const nativeDb = new FakeSqliteDatabase();
|
|
128
|
+
const client = await db().createClient(testProviderContext(nativeDb));
|
|
129
|
+
await client.transaction(
|
|
130
|
+
async (tx) => {
|
|
131
|
+
await tx.execute(
|
|
132
|
+
"INSERT INTO items(value) VALUES (?)",
|
|
133
|
+
"inside",
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
{ timeout: 120_000 },
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(nativeDb.transactionTimeouts).toEqual([120_000]);
|
|
140
|
+
expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
|
|
141
|
+
"BEGIN",
|
|
142
|
+
"INSERT INTO items(value) VALUES (?)",
|
|
143
|
+
"COMMIT",
|
|
144
|
+
]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("validates zero, negative, and non-finite transaction timeouts", async () => {
|
|
148
|
+
const client = await db().createClient(
|
|
149
|
+
testProviderContext(new FakeSqliteDatabase()),
|
|
150
|
+
);
|
|
151
|
+
for (const timeout of [0, -1, Number.NaN, Number.POSITIVE_INFINITY]) {
|
|
152
|
+
await expect(
|
|
153
|
+
client.transaction(async () => {}, { timeout }),
|
|
154
|
+
).rejects.toThrow("positive finite");
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|