rivetkit 0.0.0-stack-chore-sync-engine-changes-from-enterprise-mszropyy.677d526 → 0.0.0-sync-sqlite.527e186
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 +25 -0
- package/dist/browser/client.js +17 -5
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +1 -1
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/agent-os/index.cjs +145 -3
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +40 -2
- package/dist/tsup/agent-os/index.d.ts +40 -2
- package/dist/tsup/agent-os/index.js +144 -2
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-GPD77M3M.js → chunk-2UJVBM5X.js} +2 -2
- package/dist/tsup/chunk-2UJVBM5X.js.map +1 -0
- package/dist/tsup/{chunk-OWSXJF7Z.js → chunk-6DC5T27N.js} +20 -8
- package/dist/tsup/chunk-6DC5T27N.js.map +1 -0
- package/dist/tsup/{chunk-XPT7SGBW.js → chunk-6QHFQDW4.js} +4 -4
- package/dist/tsup/{chunk-ZXV3CG4Y.cjs → chunk-7KYMUJOU.cjs} +7 -7
- package/dist/tsup/{chunk-ZXV3CG4Y.cjs.map → chunk-7KYMUJOU.cjs.map} +1 -1
- package/dist/tsup/{chunk-M4RSGECU.js → chunk-7XKSZBR7.js} +2 -2
- package/dist/tsup/{chunk-VXJ26VPL.cjs → chunk-BPBPNCCY.cjs} +10 -10
- package/dist/tsup/{chunk-VXJ26VPL.cjs.map → chunk-BPBPNCCY.cjs.map} +1 -1
- package/dist/tsup/{chunk-YHYNYVNZ.js → chunk-CV5KMH2U.js} +3 -3
- package/dist/tsup/{chunk-FSD52J3H.cjs → chunk-D72VXRS4.cjs} +3 -3
- package/dist/tsup/{chunk-FSD52J3H.cjs.map → chunk-D72VXRS4.cjs.map} +1 -1
- package/dist/tsup/{chunk-L6DNN72S.js → chunk-GE2H2DHD.js} +2 -2
- package/dist/tsup/{chunk-UBGN2UE2.cjs → chunk-GNKZNRNM.cjs} +3 -3
- package/dist/tsup/{chunk-UBGN2UE2.cjs.map → chunk-GNKZNRNM.cjs.map} +1 -1
- package/dist/tsup/{chunk-TFACXNOP.cjs → chunk-W5MTJGSD.cjs} +121 -10
- package/dist/tsup/chunk-W5MTJGSD.cjs.map +1 -0
- package/dist/tsup/{chunk-JTHHCZCZ.js → chunk-WCEJTJHO.js} +34 -1
- package/dist/tsup/chunk-WCEJTJHO.js.map +1 -0
- package/dist/tsup/{chunk-7ZPRFCTV.cjs → chunk-X5N4RMK4.cjs} +156 -144
- package/dist/tsup/chunk-X5N4RMK4.cjs.map +1 -0
- package/dist/tsup/{chunk-LHT3TRDM.js → chunk-XGCQ4JOX.js} +115 -4
- package/dist/tsup/chunk-XGCQ4JOX.js.map +1 -0
- package/dist/tsup/{chunk-KVFIONKQ.cjs → chunk-XMNL3AE2.cjs} +35 -2
- package/dist/tsup/chunk-XMNL3AE2.cjs.map +1 -0
- package/dist/tsup/{chunk-ZYHZOZUQ.js → chunk-XW3HQQDX.js} +2 -2
- package/dist/tsup/{chunk-XNLSA7TO.cjs → chunk-Y4YVQXM7.cjs} +4 -4
- package/dist/tsup/{chunk-XNLSA7TO.cjs.map → chunk-Y4YVQXM7.cjs.map} +1 -1
- package/dist/tsup/{chunk-2TAUHMAC.cjs → chunk-YHTH6K2K.cjs} +2 -2
- package/dist/tsup/chunk-YHTH6K2K.cjs.map +1 -0
- package/dist/tsup/client/mod.cjs +6 -6
- package/dist/tsup/client/mod.d.cts +3 -3
- package/dist/tsup/client/mod.d.ts +3 -3
- package/dist/tsup/client/mod.js +5 -5
- 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-ey2I2zz5.d.cts → config-B0q37XhG.d.cts} +31 -1
- package/dist/tsup/{config-ey2I2zz5.d.ts → config-B0q37XhG.d.ts} +31 -1
- package/dist/tsup/{config-BGTanB_3.d.ts → config-BPJQ0mDo.d.ts} +9 -1
- package/dist/tsup/{config-NHz6oMb9.d.cts → config-CGUJyT5L.d.cts} +9 -1
- package/dist/tsup/{context-SHomdVV8.d.ts → context-DZ_lu12i.d.ts} +2 -2
- package/dist/tsup/{context-DB8zG_Ib.d.cts → context-WLBsDXrQ.d.cts} +2 -2
- package/dist/tsup/db/drizzle.cjs +113 -10
- package/dist/tsup/db/drizzle.cjs.map +1 -1
- package/dist/tsup/db/drizzle.d.cts +2 -2
- package/dist/tsup/db/drizzle.d.ts +2 -2
- package/dist/tsup/db/drizzle.js +106 -3
- package/dist/tsup/db/drizzle.js.map +1 -1
- package/dist/tsup/db/mod.cjs +4 -4
- package/dist/tsup/db/mod.d.cts +4 -4
- package/dist/tsup/db/mod.d.ts +4 -4
- package/dist/tsup/db/mod.js +3 -3
- package/dist/tsup/dynamic/mod.d.cts +2 -2
- package/dist/tsup/dynamic/mod.d.ts +2 -2
- package/dist/tsup/inspector/mod.cjs +5 -5
- package/dist/tsup/inspector/mod.js +4 -4
- package/dist/tsup/inspector/workflow.cjs +4 -4
- package/dist/tsup/inspector/workflow.js +3 -3
- package/dist/tsup/inspector-tab/mod.d.cts +3 -3
- package/dist/tsup/inspector-tab/mod.d.ts +3 -3
- package/dist/tsup/mod.cjs +296 -88
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +4 -4
- package/dist/tsup/mod.d.ts +4 -4
- package/dist/tsup/mod.js +225 -17
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +7 -7
- package/dist/tsup/test/mod.d.cts +2 -2
- package/dist/tsup/test/mod.d.ts +2 -2
- package/dist/tsup/test/mod.js +5 -5
- package/dist/tsup/unstable/migrations.d.cts +1 -1
- package/dist/tsup/unstable/migrations.d.ts +1 -1
- package/dist/tsup/utils.cjs +2 -2
- package/dist/tsup/utils.js +1 -1
- package/dist/tsup/workflow/mod.cjs +7 -7
- package/dist/tsup/workflow/mod.d.cts +4 -4
- package/dist/tsup/workflow/mod.d.ts +4 -4
- package/dist/tsup/workflow/mod.js +4 -4
- package/package.json +8 -8
- package/src/agent-os/actor/index.ts +6 -3
- package/src/agent-os/actor/preview.ts +5 -2
- package/src/client/actor-handle.ts +15 -8
- package/src/client/raw-utils.ts +14 -0
- package/src/common/database/config.ts +54 -0
- package/src/common/database/mod.test.ts +162 -1
- package/src/common/database/mod.ts +154 -6
- package/src/common/database/native-database.test.ts +81 -2
- package/src/common/database/native-database.ts +172 -3
- package/src/common/database/shared.ts +49 -1
- package/src/db/drizzle.test.ts +82 -1
- package/src/db/drizzle.ts +136 -6
- package/src/db/mod.ts +2 -0
- package/src/registry/napi-runtime.ts +71 -0
- package/src/registry/native.ts +48 -14
- package/src/registry/runtime.ts +46 -0
- package/src/registry/wasm-runtime.ts +63 -0
- package/dist/tsup/chunk-2TAUHMAC.cjs.map +0 -1
- package/dist/tsup/chunk-7ZPRFCTV.cjs.map +0 -1
- package/dist/tsup/chunk-GPD77M3M.js.map +0 -1
- package/dist/tsup/chunk-JTHHCZCZ.js.map +0 -1
- package/dist/tsup/chunk-KVFIONKQ.cjs.map +0 -1
- package/dist/tsup/chunk-LHT3TRDM.js.map +0 -1
- package/dist/tsup/chunk-OWSXJF7Z.js.map +0 -1
- package/dist/tsup/chunk-TFACXNOP.cjs.map +0 -1
- /package/dist/tsup/{chunk-XPT7SGBW.js.map → chunk-6QHFQDW4.js.map} +0 -0
- /package/dist/tsup/{chunk-M4RSGECU.js.map → chunk-7XKSZBR7.js.map} +0 -0
- /package/dist/tsup/{chunk-YHYNYVNZ.js.map → chunk-CV5KMH2U.js.map} +0 -0
- /package/dist/tsup/{chunk-L6DNN72S.js.map → chunk-GE2H2DHD.js.map} +0 -0
- /package/dist/tsup/{chunk-ZYHZOZUQ.js.map → chunk-XW3HQQDX.js.map} +0 -0
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
SqliteExecuteResult,
|
|
7
7
|
SqliteNativeMetrics,
|
|
8
8
|
SqliteTransactionDatabase,
|
|
9
|
+
SynchronousSqliteTransactionDatabase,
|
|
9
10
|
} from "./config";
|
|
10
11
|
|
|
11
12
|
type NativeBindNoValues = {
|
|
@@ -74,10 +75,15 @@ interface NativeBatchStatement {
|
|
|
74
75
|
|
|
75
76
|
export interface JsNativeDatabaseLike {
|
|
76
77
|
exec(sql: string): Promise<NativeExecResult>;
|
|
78
|
+
execSync(sql: string): NativeExecResult;
|
|
77
79
|
execute(
|
|
78
80
|
sql: string,
|
|
79
81
|
params?: NativeBindParam[] | null,
|
|
80
82
|
): Promise<NativeExecuteResult>;
|
|
83
|
+
executeSync(
|
|
84
|
+
sql: string,
|
|
85
|
+
params?: NativeBindParam[] | null,
|
|
86
|
+
): NativeExecuteResult;
|
|
81
87
|
executeBatch?(
|
|
82
88
|
statements: NativeBatchStatement[],
|
|
83
89
|
): Promise<NativeExecuteResult[]>;
|
|
@@ -88,7 +94,11 @@ export interface JsNativeDatabaseLike {
|
|
|
88
94
|
beginTransaction(
|
|
89
95
|
timeoutMs?: number,
|
|
90
96
|
name?: string,
|
|
91
|
-
): Promise<
|
|
97
|
+
): Promise<JsNativeSynchronousTransactionLike>;
|
|
98
|
+
beginTransactionSync(
|
|
99
|
+
timeoutMs?: number,
|
|
100
|
+
name?: string,
|
|
101
|
+
): JsNativeSynchronousTransactionLike;
|
|
92
102
|
query(
|
|
93
103
|
sql: string,
|
|
94
104
|
params?: NativeBindParam[] | null,
|
|
@@ -110,14 +120,36 @@ export type StateAwareSqliteDatabase = SqliteDatabase & {
|
|
|
110
120
|
|
|
111
121
|
export interface JsNativeTransactionLike {
|
|
112
122
|
exec(sql: string): Promise<NativeExecResult>;
|
|
123
|
+
execSync(sql: string): NativeExecResult;
|
|
113
124
|
execute(
|
|
114
125
|
sql: string,
|
|
115
126
|
params?: NativeBindParam[] | null,
|
|
116
127
|
): Promise<NativeExecuteResult>;
|
|
128
|
+
executeSync(
|
|
129
|
+
sql: string,
|
|
130
|
+
params?: NativeBindParam[] | null,
|
|
131
|
+
): NativeExecuteResult;
|
|
117
132
|
commit(): Promise<void>;
|
|
118
133
|
rollback(): Promise<void>;
|
|
119
134
|
}
|
|
120
135
|
|
|
136
|
+
export interface JsNativeSynchronousTransactionLike
|
|
137
|
+
extends JsNativeTransactionLike {
|
|
138
|
+
commitSync(): void;
|
|
139
|
+
rollbackSync(): void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isSynchronousTransaction(
|
|
143
|
+
transaction: JsNativeTransactionLike,
|
|
144
|
+
): transaction is JsNativeSynchronousTransactionLike {
|
|
145
|
+
const candidate =
|
|
146
|
+
transaction as Partial<JsNativeSynchronousTransactionLike>;
|
|
147
|
+
return (
|
|
148
|
+
typeof candidate.commitSync === "function" &&
|
|
149
|
+
typeof candidate.rollbackSync === "function"
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
function shouldAttachNativeKvError(message: string): boolean {
|
|
122
154
|
return /i\/o error|unable to open database file/i.test(message);
|
|
123
155
|
}
|
|
@@ -358,6 +390,34 @@ export function wrapJsNativeDatabase(
|
|
|
358
390
|
release();
|
|
359
391
|
}
|
|
360
392
|
};
|
|
393
|
+
const executeNativeSync = (
|
|
394
|
+
sql: string,
|
|
395
|
+
params?: SqliteBindings,
|
|
396
|
+
): SqliteExecuteResult => {
|
|
397
|
+
const lastInsertRowIdColumn = lastInsertRowIdColumnName(sql);
|
|
398
|
+
if (lastInsertRowIdColumn) {
|
|
399
|
+
return {
|
|
400
|
+
columns: [lastInsertRowIdColumn],
|
|
401
|
+
rows: [[lastInsertRowId ?? 0]],
|
|
402
|
+
changes: 0,
|
|
403
|
+
lastInsertRowId,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const release = gate.enter();
|
|
408
|
+
try {
|
|
409
|
+
const nativeParams = toNativeBindings(sql, params);
|
|
410
|
+
const result = database.executeSync(sql, nativeParams);
|
|
411
|
+
if (result.lastInsertRowId !== undefined) {
|
|
412
|
+
lastInsertRowId = result.lastInsertRowId;
|
|
413
|
+
}
|
|
414
|
+
return result;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
enrichNativeDatabaseError(database, error);
|
|
417
|
+
} finally {
|
|
418
|
+
release();
|
|
419
|
+
}
|
|
420
|
+
};
|
|
361
421
|
|
|
362
422
|
return {
|
|
363
423
|
async exec(
|
|
@@ -380,12 +440,34 @@ export function wrapJsNativeDatabase(
|
|
|
380
440
|
callback(row, result.columns);
|
|
381
441
|
}
|
|
382
442
|
},
|
|
443
|
+
execSync(
|
|
444
|
+
sql: string,
|
|
445
|
+
callback?: (row: unknown[], columns: string[]) => void,
|
|
446
|
+
): void {
|
|
447
|
+
const release = gate.enter();
|
|
448
|
+
let result: NativeExecResult;
|
|
449
|
+
try {
|
|
450
|
+
result = database.execSync(sql);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
enrichNativeDatabaseError(database, error);
|
|
453
|
+
} finally {
|
|
454
|
+
release();
|
|
455
|
+
}
|
|
456
|
+
if (callback) {
|
|
457
|
+
for (const row of result.rows) {
|
|
458
|
+
callback(row, result.columns);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
},
|
|
383
462
|
async execute(
|
|
384
463
|
sql: string,
|
|
385
464
|
params?: SqliteBindings,
|
|
386
465
|
): Promise<SqliteExecuteResult> {
|
|
387
466
|
return await executeNative(sql, params);
|
|
388
467
|
},
|
|
468
|
+
executeSync(sql: string, params?: SqliteBindings): SqliteExecuteResult {
|
|
469
|
+
return executeNativeSync(sql, params);
|
|
470
|
+
},
|
|
389
471
|
async executeBatch(
|
|
390
472
|
statements: SqliteBatchStatement[],
|
|
391
473
|
): Promise<SqliteExecuteResult[]> {
|
|
@@ -435,7 +517,7 @@ export function wrapJsNativeDatabase(
|
|
|
435
517
|
name?: string,
|
|
436
518
|
): Promise<SqliteTransactionDatabase> {
|
|
437
519
|
const release = gate.enter();
|
|
438
|
-
let transaction:
|
|
520
|
+
let transaction: JsNativeSynchronousTransactionLike;
|
|
439
521
|
try {
|
|
440
522
|
transaction = await database.beginTransaction(timeoutMs, name);
|
|
441
523
|
} catch (error) {
|
|
@@ -449,6 +531,25 @@ export function wrapJsNativeDatabase(
|
|
|
449
531
|
}
|
|
450
532
|
});
|
|
451
533
|
},
|
|
534
|
+
beginTransactionSync(
|
|
535
|
+
timeoutMs?: number,
|
|
536
|
+
name?: string,
|
|
537
|
+
): SynchronousSqliteTransactionDatabase {
|
|
538
|
+
const release = gate.enter();
|
|
539
|
+
let transaction: JsNativeSynchronousTransactionLike;
|
|
540
|
+
try {
|
|
541
|
+
transaction = database.beginTransactionSync(timeoutMs, name);
|
|
542
|
+
} catch (error) {
|
|
543
|
+
enrichNativeDatabaseError(database, error);
|
|
544
|
+
} finally {
|
|
545
|
+
release();
|
|
546
|
+
}
|
|
547
|
+
return wrapTransaction(database, transaction, gate, (result) => {
|
|
548
|
+
if (result.lastInsertRowId !== undefined) {
|
|
549
|
+
lastInsertRowId = result.lastInsertRowId;
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
},
|
|
452
553
|
async beginStateTransaction(
|
|
453
554
|
timeoutMs?: number,
|
|
454
555
|
context?: unknown,
|
|
@@ -491,13 +592,25 @@ export function wrapJsNativeDatabase(
|
|
|
491
592
|
};
|
|
492
593
|
}
|
|
493
594
|
|
|
595
|
+
function wrapTransaction(
|
|
596
|
+
database: JsNativeDatabaseLike,
|
|
597
|
+
transaction: JsNativeSynchronousTransactionLike,
|
|
598
|
+
gate: NativeCloseGate,
|
|
599
|
+
onExecute: (result: NativeExecuteResult) => void,
|
|
600
|
+
): SynchronousSqliteTransactionDatabase;
|
|
601
|
+
function wrapTransaction(
|
|
602
|
+
database: JsNativeDatabaseLike,
|
|
603
|
+
transaction: JsNativeTransactionLike,
|
|
604
|
+
gate: NativeCloseGate,
|
|
605
|
+
onExecute: (result: NativeExecuteResult) => void,
|
|
606
|
+
): SqliteTransactionDatabase;
|
|
494
607
|
function wrapTransaction(
|
|
495
608
|
database: JsNativeDatabaseLike,
|
|
496
609
|
transaction: JsNativeTransactionLike,
|
|
497
610
|
gate: NativeCloseGate,
|
|
498
611
|
onExecute: (result: NativeExecuteResult) => void,
|
|
499
612
|
): SqliteTransactionDatabase {
|
|
500
|
-
|
|
613
|
+
const wrapped: SqliteTransactionDatabase = {
|
|
501
614
|
async exec(sql, callback) {
|
|
502
615
|
const release = gate.enter();
|
|
503
616
|
let result: NativeExecResult;
|
|
@@ -512,6 +625,20 @@ function wrapTransaction(
|
|
|
512
625
|
for (const row of result.rows) callback(row, result.columns);
|
|
513
626
|
}
|
|
514
627
|
},
|
|
628
|
+
execSync(sql, callback) {
|
|
629
|
+
const release = gate.enter();
|
|
630
|
+
let result: NativeExecResult;
|
|
631
|
+
try {
|
|
632
|
+
result = transaction.execSync(sql);
|
|
633
|
+
} catch (error) {
|
|
634
|
+
enrichNativeDatabaseError(database, error);
|
|
635
|
+
} finally {
|
|
636
|
+
release();
|
|
637
|
+
}
|
|
638
|
+
if (callback) {
|
|
639
|
+
for (const row of result.rows) callback(row, result.columns);
|
|
640
|
+
}
|
|
641
|
+
},
|
|
515
642
|
async execute(sql, params) {
|
|
516
643
|
const release = gate.enter();
|
|
517
644
|
try {
|
|
@@ -527,6 +654,21 @@ function wrapTransaction(
|
|
|
527
654
|
release();
|
|
528
655
|
}
|
|
529
656
|
},
|
|
657
|
+
executeSync(sql, params) {
|
|
658
|
+
const release = gate.enter();
|
|
659
|
+
try {
|
|
660
|
+
const result = transaction.executeSync(
|
|
661
|
+
sql,
|
|
662
|
+
toNativeBindings(sql, params),
|
|
663
|
+
);
|
|
664
|
+
onExecute(result);
|
|
665
|
+
return result;
|
|
666
|
+
} catch (error) {
|
|
667
|
+
enrichNativeDatabaseError(database, error);
|
|
668
|
+
} finally {
|
|
669
|
+
release();
|
|
670
|
+
}
|
|
671
|
+
},
|
|
530
672
|
async commit() {
|
|
531
673
|
const release = gate.enter();
|
|
532
674
|
try {
|
|
@@ -548,6 +690,33 @@ function wrapTransaction(
|
|
|
548
690
|
}
|
|
549
691
|
},
|
|
550
692
|
};
|
|
693
|
+
|
|
694
|
+
if (isSynchronousTransaction(transaction)) {
|
|
695
|
+
return Object.assign(wrapped, {
|
|
696
|
+
commitSync() {
|
|
697
|
+
const release = gate.enter();
|
|
698
|
+
try {
|
|
699
|
+
transaction.commitSync();
|
|
700
|
+
} catch (error) {
|
|
701
|
+
enrichNativeDatabaseError(database, error);
|
|
702
|
+
} finally {
|
|
703
|
+
release();
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
rollbackSync() {
|
|
707
|
+
const release = gate.enter();
|
|
708
|
+
try {
|
|
709
|
+
transaction.rollbackSync();
|
|
710
|
+
} catch (error) {
|
|
711
|
+
enrichNativeDatabaseError(database, error);
|
|
712
|
+
} finally {
|
|
713
|
+
release();
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
}) as SynchronousSqliteTransactionDatabase;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return wrapped;
|
|
551
720
|
}
|
|
552
721
|
|
|
553
722
|
function lastInsertRowIdColumnName(sql: string): string | undefined {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
SqliteBindings,
|
|
3
|
+
SqliteDatabase,
|
|
4
|
+
SqliteTransactionOptions,
|
|
5
|
+
SynchronousSqliteTransactionDatabase,
|
|
6
|
+
} from "./config";
|
|
2
7
|
|
|
3
8
|
/** Migrations may legitimately do substantially more work than request transactions. */
|
|
4
9
|
export const MIGRATION_TRANSACTION_TIMEOUT_MS = 5 * 60_000;
|
|
@@ -24,6 +29,49 @@ export function validateTransactionName(name: string | undefined): void {
|
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
|
|
32
|
+
export function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
|
33
|
+
return (typeof value === "object" && value !== null) ||
|
|
34
|
+
typeof value === "function"
|
|
35
|
+
? typeof (value as { then?: unknown }).then === "function"
|
|
36
|
+
: false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function runSqliteTransactionSync<T>(
|
|
40
|
+
database: SqliteDatabase,
|
|
41
|
+
callback: (transaction: SynchronousSqliteTransactionDatabase) => T,
|
|
42
|
+
options?: Omit<SqliteTransactionOptions, "experimental">,
|
|
43
|
+
): T {
|
|
44
|
+
validateTransactionTimeout(options?.timeout);
|
|
45
|
+
validateTransactionName(options?.name);
|
|
46
|
+
if (!database.beginTransactionSync) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"Synchronous SQLite transactions are only available in the Node.js native runtime.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const transaction = database.beginTransactionSync(
|
|
53
|
+
options?.timeout,
|
|
54
|
+
options?.name,
|
|
55
|
+
);
|
|
56
|
+
try {
|
|
57
|
+
const result = callback(transaction);
|
|
58
|
+
if (isPromiseLike(result)) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"db.transactionSync() callback must complete synchronously and must not return a promise.",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
transaction.commitSync();
|
|
64
|
+
return result;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
try {
|
|
67
|
+
transaction.rollbackSync();
|
|
68
|
+
} catch {
|
|
69
|
+
// Preserve the callback or commit error after cleanup failure.
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
27
75
|
type SqliteBindingObject = Record<string, unknown>;
|
|
28
76
|
|
|
29
77
|
function isSqliteBindingValue(value: unknown): boolean {
|
package/src/db/drizzle.test.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
SqliteDatabase,
|
|
7
7
|
SqliteExecuteResult,
|
|
8
8
|
SqliteTransactionDatabase,
|
|
9
|
+
SynchronousSqliteTransactionDatabase,
|
|
9
10
|
} from "@/common/database/config";
|
|
10
11
|
import { db } from "./drizzle";
|
|
11
12
|
|
|
@@ -14,7 +15,20 @@ class FakeSqliteDatabase implements SqliteDatabase {
|
|
|
14
15
|
transactionTimeouts: Array<number | undefined> = [];
|
|
15
16
|
transactionNames: Array<string | undefined> = [];
|
|
16
17
|
|
|
17
|
-
async exec(
|
|
18
|
+
async exec(
|
|
19
|
+
sql: string,
|
|
20
|
+
callback?: (row: unknown[], columns: string[]) => void,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
this.execSync(sql, callback);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
execSync(
|
|
26
|
+
sql: string,
|
|
27
|
+
callback?: (row: unknown[], columns: string[]) => void,
|
|
28
|
+
): void {
|
|
29
|
+
this.executeCalls.push({ sql });
|
|
30
|
+
callback?.([1], ["value"]);
|
|
31
|
+
}
|
|
18
32
|
|
|
19
33
|
async execute(
|
|
20
34
|
sql: string,
|
|
@@ -24,6 +38,11 @@ class FakeSqliteDatabase implements SqliteDatabase {
|
|
|
24
38
|
return emptyResult();
|
|
25
39
|
}
|
|
26
40
|
|
|
41
|
+
executeSync(sql: string, params?: SqliteBindings): SqliteExecuteResult {
|
|
42
|
+
this.executeCalls.push({ sql, params });
|
|
43
|
+
return emptyResult();
|
|
44
|
+
}
|
|
45
|
+
|
|
27
46
|
async executeBatch(
|
|
28
47
|
statements: SqliteBatchStatement[],
|
|
29
48
|
): Promise<SqliteExecuteResult[]> {
|
|
@@ -47,21 +66,39 @@ class FakeSqliteDatabase implements SqliteDatabase {
|
|
|
47
66
|
timeoutMs?: number,
|
|
48
67
|
name?: string,
|
|
49
68
|
): Promise<SqliteTransactionDatabase> {
|
|
69
|
+
return this.beginTransactionSync(timeoutMs, name);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
beginTransactionSync(
|
|
73
|
+
timeoutMs?: number,
|
|
74
|
+
name?: string,
|
|
75
|
+
): SynchronousSqliteTransactionDatabase {
|
|
50
76
|
this.transactionTimeouts.push(timeoutMs);
|
|
51
77
|
this.transactionNames.push(name);
|
|
52
78
|
this.executeCalls.push({ sql: "BEGIN" });
|
|
53
79
|
return {
|
|
54
80
|
exec: async () => {},
|
|
81
|
+
execSync: () => {},
|
|
55
82
|
execute: async (sql, params) => {
|
|
56
83
|
this.executeCalls.push({ sql, params });
|
|
57
84
|
return emptyResult();
|
|
58
85
|
},
|
|
86
|
+
executeSync: (sql, params) => {
|
|
87
|
+
this.executeCalls.push({ sql, params });
|
|
88
|
+
return emptyResult();
|
|
89
|
+
},
|
|
59
90
|
commit: async () => {
|
|
60
91
|
this.executeCalls.push({ sql: "COMMIT" });
|
|
61
92
|
},
|
|
93
|
+
commitSync: () => {
|
|
94
|
+
this.executeCalls.push({ sql: "COMMIT" });
|
|
95
|
+
},
|
|
62
96
|
rollback: async () => {
|
|
63
97
|
this.executeCalls.push({ sql: "ROLLBACK" });
|
|
64
98
|
},
|
|
99
|
+
rollbackSync: () => {
|
|
100
|
+
this.executeCalls.push({ sql: "ROLLBACK" });
|
|
101
|
+
},
|
|
65
102
|
};
|
|
66
103
|
}
|
|
67
104
|
|
|
@@ -151,6 +188,50 @@ describe("Drizzle database transactions", () => {
|
|
|
151
188
|
]);
|
|
152
189
|
});
|
|
153
190
|
|
|
191
|
+
test("exposes synchronous raw queries", async () => {
|
|
192
|
+
const nativeDb = new FakeSqliteDatabase();
|
|
193
|
+
const client = await db().createClient(testProviderContext(nativeDb));
|
|
194
|
+
|
|
195
|
+
client.executeSync("SELECT ?", 42);
|
|
196
|
+
expect(
|
|
197
|
+
client.executeSync<{ value: number }>("SELECT 1; SELECT 2"),
|
|
198
|
+
).toEqual([{ value: 1 }]);
|
|
199
|
+
|
|
200
|
+
expect(nativeDb.executeCalls).toEqual([
|
|
201
|
+
{ sql: "SELECT ?", params: [42] },
|
|
202
|
+
{ sql: "SELECT 1; SELECT 2" },
|
|
203
|
+
]);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("commits and rolls back synchronous raw transactions", async () => {
|
|
207
|
+
const nativeDb = new FakeSqliteDatabase();
|
|
208
|
+
const client = await db().createClient(testProviderContext(nativeDb));
|
|
209
|
+
|
|
210
|
+
const value = client.transactionSync(
|
|
211
|
+
(tx) => {
|
|
212
|
+
tx.executeSync("INSERT INTO items(value) VALUES (?)", "inside");
|
|
213
|
+
return 42;
|
|
214
|
+
},
|
|
215
|
+
{ name: "sync-drizzle", timeout: 120_000 },
|
|
216
|
+
);
|
|
217
|
+
expect(value).toBe(42);
|
|
218
|
+
expect(() =>
|
|
219
|
+
client.transactionSync(() => {
|
|
220
|
+
throw new Error("callback failed");
|
|
221
|
+
}),
|
|
222
|
+
).toThrow("callback failed");
|
|
223
|
+
|
|
224
|
+
expect(nativeDb.transactionTimeouts).toEqual([120_000, undefined]);
|
|
225
|
+
expect(nativeDb.transactionNames).toEqual(["sync-drizzle", undefined]);
|
|
226
|
+
expect(nativeDb.executeCalls.map(({ sql }) => sql)).toEqual([
|
|
227
|
+
"BEGIN",
|
|
228
|
+
"INSERT INTO items(value) VALUES (?)",
|
|
229
|
+
"COMMIT",
|
|
230
|
+
"BEGIN",
|
|
231
|
+
"ROLLBACK",
|
|
232
|
+
]);
|
|
233
|
+
});
|
|
234
|
+
|
|
154
235
|
test("validates zero, negative, and non-finite transaction timeouts", async () => {
|
|
155
236
|
const client = await db().createClient(
|
|
156
237
|
testProviderContext(new FakeSqliteDatabase()),
|
package/src/db/drizzle.ts
CHANGED
|
@@ -6,20 +6,22 @@ import {
|
|
|
6
6
|
import type {
|
|
7
7
|
DatabaseProvider,
|
|
8
8
|
DatabaseProviderContext,
|
|
9
|
-
RawAccess,
|
|
10
|
-
SqliteProfilingOptions,
|
|
11
|
-
SqliteTransactionOptions,
|
|
12
9
|
SqliteDatabase,
|
|
10
|
+
SqliteProfilingOptions,
|
|
13
11
|
SqliteTransactionDatabase,
|
|
12
|
+
SqliteTransactionOptions,
|
|
13
|
+
SynchronousRawAccess,
|
|
14
|
+
SynchronousTransactionAccess,
|
|
14
15
|
} from "@/common/database/config";
|
|
15
|
-
import { getLogger } from "@/common/log";
|
|
16
16
|
import {
|
|
17
17
|
isManualTransactionControl,
|
|
18
18
|
MIGRATION_TRANSACTION_TIMEOUT_MS,
|
|
19
|
+
runSqliteTransactionSync,
|
|
19
20
|
toSqliteBindings,
|
|
20
21
|
validateTransactionName,
|
|
21
22
|
validateTransactionTimeout,
|
|
22
23
|
} from "@/common/database/shared";
|
|
24
|
+
import { getLogger } from "@/common/log";
|
|
23
25
|
import { sha256Hex } from "@/utils/crypto";
|
|
24
26
|
|
|
25
27
|
export type { SQLiteTable } from "drizzle-orm/sqlite-core";
|
|
@@ -42,7 +44,7 @@ type DrizzleDatabase<TSchema extends DrizzleSchema> = Omit<
|
|
|
42
44
|
SqliteRemoteDatabase<TSchema>,
|
|
43
45
|
"transaction"
|
|
44
46
|
> &
|
|
45
|
-
Omit<
|
|
47
|
+
Omit<SynchronousRawAccess, "transaction"> & {
|
|
46
48
|
transaction: <T>(
|
|
47
49
|
callback: (tx: DrizzleDatabase<TSchema>) => Promise<T> | T,
|
|
48
50
|
options?: SqliteTransactionOptions,
|
|
@@ -114,6 +116,7 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
114
116
|
const nativeDb = await nativeDatabaseProvider.open(ctx.actorId);
|
|
115
117
|
let closed = false;
|
|
116
118
|
let manualTransactionWarned = false;
|
|
119
|
+
let synchronousTransactionActive = false;
|
|
117
120
|
const ensureOpen = () => {
|
|
118
121
|
if (closed) {
|
|
119
122
|
throw new Error(
|
|
@@ -121,6 +124,15 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
121
124
|
);
|
|
122
125
|
}
|
|
123
126
|
};
|
|
127
|
+
const ensureSynchronousTransactionClient = (
|
|
128
|
+
transactionScoped: boolean,
|
|
129
|
+
) => {
|
|
130
|
+
if (!transactionScoped && synchronousTransactionActive) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
"Use the transaction callback's tx value for queries inside db.transactionSync().",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
124
136
|
|
|
125
137
|
const createDrizzleClient = (
|
|
126
138
|
target: SqliteDatabase | SqliteTransactionDatabase,
|
|
@@ -132,6 +144,7 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
132
144
|
method: "run" | "all" | "values" | "get",
|
|
133
145
|
) => {
|
|
134
146
|
ensureOpen();
|
|
147
|
+
ensureSynchronousTransactionClient(transactionScoped);
|
|
135
148
|
warnForManualTransaction(query, transactionScoped);
|
|
136
149
|
|
|
137
150
|
const start = performance.now();
|
|
@@ -186,6 +199,7 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
186
199
|
query: string,
|
|
187
200
|
...args: unknown[]
|
|
188
201
|
): Promise<TRow[]> => {
|
|
202
|
+
ensureSynchronousTransactionClient(transactionScoped);
|
|
189
203
|
return await executeRaw<TRow>(
|
|
190
204
|
target,
|
|
191
205
|
ctx,
|
|
@@ -196,12 +210,34 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
196
210
|
warnForManualTransaction(query, transactionScoped),
|
|
197
211
|
);
|
|
198
212
|
};
|
|
213
|
+
drizzleDb.executeSync = <
|
|
214
|
+
TRow extends Record<string, unknown> = Record<
|
|
215
|
+
string,
|
|
216
|
+
unknown
|
|
217
|
+
>,
|
|
218
|
+
>(
|
|
219
|
+
query: string,
|
|
220
|
+
...args: unknown[]
|
|
221
|
+
): TRow[] => {
|
|
222
|
+
ensureSynchronousTransactionClient(transactionScoped);
|
|
223
|
+
return executeRawSync<TRow>(
|
|
224
|
+
target,
|
|
225
|
+
ctx,
|
|
226
|
+
ensureOpen,
|
|
227
|
+
query,
|
|
228
|
+
args,
|
|
229
|
+
() =>
|
|
230
|
+
warnForManualTransaction(query, transactionScoped),
|
|
231
|
+
);
|
|
232
|
+
};
|
|
199
233
|
drizzleDb.transaction = async <T>(
|
|
200
234
|
transactionCallback: (
|
|
201
235
|
tx: DrizzleDatabase<TSchema>,
|
|
202
236
|
) => Promise<T> | T,
|
|
203
237
|
options?: SqliteTransactionOptions,
|
|
204
238
|
): Promise<T> => {
|
|
239
|
+
ensureOpen();
|
|
240
|
+
ensureSynchronousTransactionClient(transactionScoped);
|
|
205
241
|
validateTransactionTimeout(options?.timeout);
|
|
206
242
|
validateTransactionName(options?.name);
|
|
207
243
|
const transaction = await nativeDb.beginTransaction(
|
|
@@ -222,6 +258,38 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
222
258
|
throw error;
|
|
223
259
|
}
|
|
224
260
|
};
|
|
261
|
+
drizzleDb.transactionSync = <T>(
|
|
262
|
+
transactionCallback: (
|
|
263
|
+
tx: SynchronousTransactionAccess,
|
|
264
|
+
) => T,
|
|
265
|
+
options?: Omit<SqliteTransactionOptions, "experimental">,
|
|
266
|
+
): T => {
|
|
267
|
+
ensureOpen();
|
|
268
|
+
if (transactionScoped || synchronousTransactionActive) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
"Nested synchronous SQLite transactions are not supported.",
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return runSqliteTransactionSync(
|
|
274
|
+
nativeDb,
|
|
275
|
+
(transaction) => {
|
|
276
|
+
const transactionClient = createDrizzleClient(
|
|
277
|
+
transaction,
|
|
278
|
+
true,
|
|
279
|
+
);
|
|
280
|
+
const tx: SynchronousTransactionAccess = {
|
|
281
|
+
executeSync: transactionClient.executeSync,
|
|
282
|
+
};
|
|
283
|
+
synchronousTransactionActive = true;
|
|
284
|
+
try {
|
|
285
|
+
return transactionCallback(tx);
|
|
286
|
+
} finally {
|
|
287
|
+
synchronousTransactionActive = false;
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
options,
|
|
291
|
+
);
|
|
292
|
+
};
|
|
225
293
|
drizzleDb.close = async () => {
|
|
226
294
|
if (!closed) {
|
|
227
295
|
closed = true;
|
|
@@ -248,7 +316,7 @@ export function db<TSchema extends DrizzleSchema = Record<string, never>>({
|
|
|
248
316
|
manualTransactionWarned = true;
|
|
249
317
|
getLogger("database").warn(
|
|
250
318
|
{ actorId: ctx.actorId },
|
|
251
|
-
"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.",
|
|
319
|
+
"Manual cross-call SQLite transactions can interleave with other actor work. Use db.transaction() or db.transactionSync() for coordinated transactions. Set warnOnManualTransactions: false in your db(...) configuration to disable this warning.",
|
|
252
320
|
);
|
|
253
321
|
};
|
|
254
322
|
|
|
@@ -431,3 +499,65 @@ async function executeRaw<TRow extends Record<string, unknown>>(
|
|
|
431
499
|
}
|
|
432
500
|
}
|
|
433
501
|
}
|
|
502
|
+
|
|
503
|
+
function executeRawSync<TRow extends Record<string, unknown>>(
|
|
504
|
+
db: SqliteDatabase | SqliteTransactionDatabase,
|
|
505
|
+
ctx: DatabaseProviderContext,
|
|
506
|
+
ensureOpen: () => void,
|
|
507
|
+
query: string,
|
|
508
|
+
args: unknown[],
|
|
509
|
+
warnForManualTransaction: () => void,
|
|
510
|
+
): TRow[] {
|
|
511
|
+
ensureOpen();
|
|
512
|
+
warnForManualTransaction();
|
|
513
|
+
if (!db.executeSync) {
|
|
514
|
+
throw new Error(
|
|
515
|
+
"Synchronous SQLite queries are only available in the Node.js native runtime.",
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const start = performance.now();
|
|
520
|
+
const kvReadsBefore = ctx.metrics?.totalKvReads ?? 0;
|
|
521
|
+
const kvWritesBefore = ctx.metrics?.totalKvWrites ?? 0;
|
|
522
|
+
try {
|
|
523
|
+
if (args.length > 0) {
|
|
524
|
+
const { rows, columns } = db.executeSync(
|
|
525
|
+
query,
|
|
526
|
+
toSqliteBindings(args),
|
|
527
|
+
);
|
|
528
|
+
return rows.map((row) => rowToObject<TRow>(row, columns));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (!hasMultipleStatements(query)) {
|
|
532
|
+
const { rows, columns } = db.executeSync(query, undefined);
|
|
533
|
+
return rows.map((row) => rowToObject<TRow>(row, columns));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (!db.execSync) {
|
|
537
|
+
throw new Error(
|
|
538
|
+
"Synchronous SQLite queries are only available in the Node.js native runtime.",
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
const results: Record<string, unknown>[] = [];
|
|
542
|
+
let columnNames: string[] | null = null;
|
|
543
|
+
db.execSync(query, (row, columns) => {
|
|
544
|
+
if (!columnNames) {
|
|
545
|
+
columnNames = columns;
|
|
546
|
+
}
|
|
547
|
+
results.push(rowToObject(row, columnNames));
|
|
548
|
+
});
|
|
549
|
+
return results as TRow[];
|
|
550
|
+
} finally {
|
|
551
|
+
const durationMs = performance.now() - start;
|
|
552
|
+
ctx.metrics?.trackSql(query, durationMs);
|
|
553
|
+
if (ctx.metrics) {
|
|
554
|
+
ctx.log?.debug({
|
|
555
|
+
msg: "sql query",
|
|
556
|
+
query: query.slice(0, 120),
|
|
557
|
+
durationMs,
|
|
558
|
+
kvReads: ctx.metrics.totalKvReads - kvReadsBefore,
|
|
559
|
+
kvWrites: ctx.metrics.totalKvWrites - kvWritesBefore,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
package/src/db/mod.ts
CHANGED