@bastani/atomic 0.9.45 → 0.9.46
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/CHANGELOG.md +79 -0
- package/dist/builtin/intercom/CHANGELOG.md +22 -0
- package/dist/builtin/intercom/broker/broker.ts +124 -10
- package/dist/builtin/intercom/broker/client.ts +177 -25
- package/dist/builtin/intercom/broker/multinode-router.ts +228 -27
- package/dist/builtin/intercom/broker/multinode-state-store.ts +10 -0
- package/dist/builtin/intercom/broker/recipient-receipts.ts +38 -4
- package/dist/builtin/intercom/broker/send-handler.ts +9 -2
- package/dist/builtin/intercom/broker/sql-outbox-store.ts +29 -4
- package/dist/builtin/intercom/group.ts +25 -0
- package/dist/builtin/intercom/index.bundle.mjs +177 -35
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/retry-policy.ts +7 -0
- package/dist/builtin/intercom/types.ts +21 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +21 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +152 -56
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +79 -0
- package/dist/builtin/workflows/builtin/{chunk-6901nsd6.js → chunk-6jpwc09k.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-vwx023ge.js → chunk-qhm35ntx.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-jvna28mq.js → chunk-zhyqnf5g.js} +331 -68
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +1 -0
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6.md +2 -2
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6_1_sol.md +2 -2
- package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6_1_terra.md +77 -0
- package/dist/builtin/workflows/src/authoring.d.ts +1 -1
- package/dist/builtin/workflows/src/durable/journal/internal.d.ts +2 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +7104 -3387
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +11105 -7264
- package/dist/builtin/workflows/src/index.js +6796 -3606
- package/dist/builtin/workflows/src/local-worker-entry.mjs +11105 -7264
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +19 -0
- package/dist/core/agent-session-boundaries.d.ts.map +1 -1
- package/dist/core/agent-session-boundaries.js +1 -0
- package/dist/core/agent-session-boundaries.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +2 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +15 -2
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +3 -2
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts +4 -2
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +13 -8
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-recovery.d.ts.map +1 -1
- package/dist/core/agent-session-recovery.js +92 -1
- package/dist/core/agent-session-recovery.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +8 -1
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/agent-session-transfer.d.ts.map +1 -1
- package/dist/core/agent-session-transfer.js +5 -0
- package/dist/core/agent-session-transfer.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/copilot-errors.d.ts +6 -0
- package/dist/core/copilot-errors.d.ts.map +1 -0
- package/dist/core/copilot-errors.js +17 -0
- package/dist/core/copilot-errors.js.map +1 -0
- package/dist/core/execution-model-router.d.ts.map +1 -1
- package/dist/core/execution-model-router.js +12 -2
- package/dist/core/execution-model-router.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +7 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +6 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/ui-types.d.ts +9 -1
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.js.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.d.ts +4 -0
- package/dist/core/extensions/workflow-activity-hub.d.ts.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.js +26 -5
- package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
- package/dist/core/extensions/workflow-events.d.ts +5 -0
- package/dist/core/extensions/workflow-events.d.ts.map +1 -1
- package/dist/core/extensions/workflow-events.js.map +1 -1
- package/dist/core/messages.d.ts +5 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +1 -1
- package/dist/core/model-fallback-failures.d.ts.map +1 -1
- package/dist/core/model-fallback-failures.js +37 -3
- package/dist/core/model-fallback-failures.js.map +1 -1
- package/dist/core/model-resolver-defaults.js +2 -2
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/model-runtime-streaming.js +2 -2
- package/dist/core/model-runtime-streaming.js.map +1 -1
- package/dist/core/package-manager-npm.d.ts.map +1 -1
- package/dist/core/package-manager-npm.js +7 -3
- package/dist/core/package-manager-npm.js.map +1 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +19 -11
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/provider-rate-limits.d.ts +55 -6
- package/dist/core/provider-rate-limits.d.ts.map +1 -1
- package/dist/core/provider-rate-limits.js +182 -29
- package/dist/core/provider-rate-limits.js.map +1 -1
- package/dist/core/provider-request-admission.d.ts.map +1 -1
- package/dist/core/provider-request-admission.js +42 -18
- package/dist/core/provider-request-admission.js.map +1 -1
- package/dist/core/storage/node-sqlite.d.ts.map +1 -1
- package/dist/core/storage/node-sqlite.js +176 -19
- package/dist/core/storage/node-sqlite.js.map +1 -1
- package/dist/core/storage/provider.d.ts +4 -2
- package/dist/core/storage/provider.d.ts.map +1 -1
- package/dist/core/storage/provider.js +94 -5
- package/dist/core/storage/provider.js.map +1 -1
- package/dist/core/structured-output/index.d.ts.map +1 -1
- package/dist/core/structured-output/index.js +15 -8
- package/dist/core/structured-output/index.js.map +1 -1
- package/dist/core/structured-output/provider-failure.d.ts +17 -0
- package/dist/core/structured-output/provider-failure.d.ts.map +1 -0
- package/dist/core/structured-output/provider-failure.js +28 -0
- package/dist/core/structured-output/provider-failure.js.map +1 -0
- package/dist/core/tasks/completion.d.ts +6 -1
- package/dist/core/tasks/completion.d.ts.map +1 -1
- package/dist/core/tasks/completion.js +33 -18
- package/dist/core/tasks/completion.js.map +1 -1
- package/dist/core/tasks/pause.d.ts +2 -1
- package/dist/core/tasks/pause.d.ts.map +1 -1
- package/dist/core/tasks/pause.js +3 -2
- package/dist/core/tasks/pause.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +13 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +6 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/shell-task-render.d.ts +1 -0
- package/dist/core/tools/shell-task-render.d.ts.map +1 -1
- package/dist/core/tools/shell-task-render.js +7 -2
- package/dist/core/tools/shell-task-render.js.map +1 -1
- package/dist/core/tools/shell-task-status.d.ts.map +1 -1
- package/dist/core/tools/shell-task-status.js +2 -1
- package/dist/core/tools/shell-task-status.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +5 -0
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +38 -5
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +20 -12
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +3 -2
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +42 -14
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-context.js +2 -1
- package/dist/modes/interactive/interactive-extension-context.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-custom-ui.js +1 -1
- package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-dialogs.js +10 -4
- package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +5 -6
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts +3 -0
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
- package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts +6 -0
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +9 -0
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-component.js +3 -2
- package/dist/modes/interactive-engine/remote-component.js.map +1 -1
- package/dist/modes/rpc/rpc-client-process.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-process.js +8 -1
- package/dist/modes/rpc/rpc-client-process.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js +5 -0
- package/dist/utils/ansi.js.map +1 -1
- package/docs/codemode.md +1 -1
- package/docs/intercom/reference.md +3 -3
- package/docs/llama-cpp.md +25 -14
- package/docs/models/evals.md +31 -12
- package/docs/models/reference.md +23 -51
- package/docs/models.md +3 -4
- package/docs/providers.md +5 -15
- package/docs/settings.md +1 -1
- package/docs/storage.md +2 -2
- package/docs/tools.md +1 -1
- package/docs/tui.md +2 -0
- package/docs/workflows/api-reference.md +20 -1
- package/docs/workflows/operations.md +17 -4
- package/npm-shrinkwrap.json +64 -44
- package/package.json +4 -4
|
@@ -1,6 +1,111 @@
|
|
|
1
|
+
import { mkdirSync, readdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
|
|
1
2
|
import { mkdir, realpath } from "node:fs/promises";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
3
4
|
import { StorageAdapterLoadError, StorageInvalidTextError, StorageRollbackError, StorageTransactionClosedError, StorageUnavailableError, StoreClosedError, } from "./errors.js";
|
|
5
|
+
/** A ticket its owner has not refreshed for this long belongs to a process that died or stopped waiting. */
|
|
6
|
+
const TICKET_STALE_MS = 2_000;
|
|
7
|
+
/** Stale tickets older than this are removed by whichever writer notices them. */
|
|
8
|
+
const TICKET_REMOVE_AFTER_MS = 10 * TICKET_STALE_MS;
|
|
9
|
+
let ticketSequence = 0;
|
|
10
|
+
function ticketName() {
|
|
11
|
+
ticketSequence += 1;
|
|
12
|
+
return `${String(Date.now()).padStart(15, "0")}-${process.pid}-${ticketSequence}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* First come, first served for SQLite's write lock across processes. SQLite has no queue for `BEGIN IMMEDIATE`: a
|
|
16
|
+
* writer that polls after `SQLITE_BUSY` loses to one that begins the moment the lock is free, and a busy process
|
|
17
|
+
* can take the lock again and again while another waits for its whole deadline (#3978). A writer that has been
|
|
18
|
+
* refused takes a ticket, a file named by the time it started waiting, in a directory next to the database; it then
|
|
19
|
+
* attempts the lock only once no live older ticket is ahead of it, and a writer that arrives while tickets wait
|
|
20
|
+
* queues behind them instead of overtaking. Uncontended writers only list an absent or empty directory.
|
|
21
|
+
*/
|
|
22
|
+
class SqliteWriteQueue {
|
|
23
|
+
directory;
|
|
24
|
+
constructor(databasePath) {
|
|
25
|
+
this.directory = `${databasePath}-writers`;
|
|
26
|
+
}
|
|
27
|
+
/** Whether another writer's live ticket is waiting, so a new writer must queue behind it. */
|
|
28
|
+
othersWaiting() {
|
|
29
|
+
return this.liveTickets().length > 0;
|
|
30
|
+
}
|
|
31
|
+
join() {
|
|
32
|
+
mkdirSync(this.directory, { recursive: true });
|
|
33
|
+
const name = ticketName();
|
|
34
|
+
const path = join(this.directory, name);
|
|
35
|
+
writeFileSync(path, "", { flag: "wx" });
|
|
36
|
+
return new SqliteWriteTicket(this, name, path);
|
|
37
|
+
}
|
|
38
|
+
/** Live tickets, oldest first; stale ones long abandoned are removed on the way. */
|
|
39
|
+
liveTickets(except) {
|
|
40
|
+
let names;
|
|
41
|
+
try {
|
|
42
|
+
names = readdirSync(this.directory);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
const live = [];
|
|
49
|
+
for (const name of names) {
|
|
50
|
+
if (name === except)
|
|
51
|
+
continue;
|
|
52
|
+
let age;
|
|
53
|
+
try {
|
|
54
|
+
age = now - statSync(join(this.directory, name)).mtimeMs;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (age < TICKET_STALE_MS)
|
|
60
|
+
live.push(name);
|
|
61
|
+
else if (age > TICKET_REMOVE_AFTER_MS) {
|
|
62
|
+
try {
|
|
63
|
+
unlinkSync(join(this.directory, name));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Another writer removed it first.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return live.sort();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class SqliteWriteTicket {
|
|
74
|
+
left = false;
|
|
75
|
+
queue;
|
|
76
|
+
name;
|
|
77
|
+
path;
|
|
78
|
+
constructor(queue, name, path) {
|
|
79
|
+
this.queue = queue;
|
|
80
|
+
this.name = name;
|
|
81
|
+
this.path = path;
|
|
82
|
+
}
|
|
83
|
+
/** Marks this ticket live and reports whether an older live ticket is still ahead of it. */
|
|
84
|
+
behindOthers() {
|
|
85
|
+
if (this.left)
|
|
86
|
+
return false;
|
|
87
|
+
const now = new Date();
|
|
88
|
+
try {
|
|
89
|
+
utimesSync(this.path, now, now);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// The ticket was removed as stale while this writer stalled: take the place it would have had.
|
|
93
|
+
writeFileSync(this.path, "");
|
|
94
|
+
}
|
|
95
|
+
return this.queue.liveTickets(this.name).some((other) => other < this.name);
|
|
96
|
+
}
|
|
97
|
+
leave() {
|
|
98
|
+
if (this.left)
|
|
99
|
+
return;
|
|
100
|
+
this.left = true;
|
|
101
|
+
try {
|
|
102
|
+
unlinkSync(this.path);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Already removed.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
4
109
|
// Share gates across module reloads as well as adapter instances. Only live queues retain file identities.
|
|
5
110
|
const TRANSACTION_GATES = Symbol.for("atomic-storage/node-sqlite-transaction-gates@1");
|
|
6
111
|
const gateBag = globalThis;
|
|
@@ -37,10 +142,16 @@ function snapshotParams(params) {
|
|
|
37
142
|
function finalizeReleasedStatements() {
|
|
38
143
|
globalThis.Bun?.gc(true);
|
|
39
144
|
}
|
|
40
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Default for how long a transaction keeps retrying `BEGIN IMMEDIATE` while the write lock is held and nobody makes
|
|
147
|
+
* progress through it: every commit by another connection restarts the wait, so only a lock held without commits
|
|
148
|
+
* for this long fails the transaction.
|
|
149
|
+
*/
|
|
41
150
|
const DEFAULT_NODE_SQLITE_LOCK_WAIT_MS = 30_000;
|
|
42
151
|
const LOCK_RETRY_BASE_DELAY_MS = 5;
|
|
43
152
|
const LOCK_RETRY_MAX_DELAY_MS = 100;
|
|
153
|
+
/** A writer at the head of the cross-process queue retries at least this often, so the lock it is owed does not sit idle. */
|
|
154
|
+
const LOCK_RETRY_HEAD_MAX_DELAY_MS = 20;
|
|
44
155
|
/** Most transactions one group commit carries, so a batch cannot keep the write lock from other processes for long. */
|
|
45
156
|
const MAX_GROUP_COMMIT_TRANSACTIONS = 128;
|
|
46
157
|
/** SQLITE_BUSY, including its extended codes: another connection holds the lock this statement needs. */
|
|
@@ -81,6 +192,8 @@ class NodeSqliteDatabase {
|
|
|
81
192
|
ownsConnection;
|
|
82
193
|
transactionIdentity;
|
|
83
194
|
lockWaitMs;
|
|
195
|
+
/** Cross-process first-come-first-served order for the write lock; absent for in-memory databases. */
|
|
196
|
+
writeQueue;
|
|
84
197
|
constructor(connection, descriptor, ownsConnection = true, transactionIdentity = connection, lockWaitMs = DEFAULT_NODE_SQLITE_LOCK_WAIT_MS) {
|
|
85
198
|
this.lockWaitMs = lockWaitMs;
|
|
86
199
|
this.transactionIdentity = transactionIdentity;
|
|
@@ -88,6 +201,8 @@ class NodeSqliteDatabase {
|
|
|
88
201
|
this.connection = connection;
|
|
89
202
|
this.descriptor = descriptor;
|
|
90
203
|
this.executor = this.createExecutor(() => true);
|
|
204
|
+
if (typeof transactionIdentity === "string")
|
|
205
|
+
this.writeQueue = new SqliteWriteQueue(transactionIdentity);
|
|
91
206
|
}
|
|
92
207
|
driver(operation) {
|
|
93
208
|
try {
|
|
@@ -127,30 +242,72 @@ class NodeSqliteDatabase {
|
|
|
127
242
|
}
|
|
128
243
|
});
|
|
129
244
|
}
|
|
245
|
+
/** Changes whenever another connection commits to the database: the lock is being used, not held idle. */
|
|
246
|
+
dataVersion() {
|
|
247
|
+
return this.driver(() => Number(this.connection.prepare("PRAGMA data_version").get()?.data_version ?? 0));
|
|
248
|
+
}
|
|
130
249
|
/**
|
|
131
250
|
* Takes the write lock without blocking the event loop. Nothing has run yet when `BEGIN IMMEDIATE` reports
|
|
132
|
-
* SQLITE_BUSY, so the attempt is retried after a
|
|
133
|
-
*
|
|
251
|
+
* SQLITE_BUSY, so the attempt is retried after a timer. A refused writer queues with writers in other processes
|
|
252
|
+
* and attempts the lock only when no earlier writer is still waiting, so none starves (#3978). The wait ends only
|
|
253
|
+
* when no other connection has committed for `lockWaitMs`, whether this writer is still queued or already trying
|
|
254
|
+
* the lock: a queued writer counts only real commits as progress, not older tickets ahead of it. Every other
|
|
255
|
+
* failure, including a writers' queue that cannot be used, rejects at once with its cause.
|
|
134
256
|
*/
|
|
135
257
|
async begin() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
258
|
+
let ticket;
|
|
259
|
+
try {
|
|
260
|
+
// Writers already waiting in other processes go first.
|
|
261
|
+
if (this.queueOp(() => this.writeQueue?.othersWaiting()))
|
|
262
|
+
ticket = this.queueOp(() => this.writeQueue?.join());
|
|
263
|
+
// Read only once this writer waits, so an uncontended transaction pays nothing for it.
|
|
264
|
+
let version = ticket === undefined ? undefined : this.dataVersion();
|
|
265
|
+
let stalledSince = Date.now();
|
|
266
|
+
let backoff = LOCK_RETRY_BASE_DELAY_MS;
|
|
267
|
+
let lastCause;
|
|
268
|
+
for (;;) {
|
|
269
|
+
const behind = ticket !== undefined && this.queueOp(() => ticket.behindOthers());
|
|
270
|
+
if (!behind) {
|
|
271
|
+
try {
|
|
272
|
+
this.tryBegin();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
const cause = error instanceof StorageUnavailableError ? error.cause : undefined;
|
|
277
|
+
if (!isSqliteBusy(cause))
|
|
278
|
+
throw error;
|
|
279
|
+
lastCause = cause;
|
|
280
|
+
ticket ??= this.queueOp(() => this.writeQueue?.join());
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Only another connection's commit is progress; a queued writer measures its stall the same way.
|
|
284
|
+
const current = this.dataVersion();
|
|
285
|
+
if (version === undefined)
|
|
286
|
+
version = current;
|
|
287
|
+
else if (current !== version) {
|
|
288
|
+
version = current;
|
|
289
|
+
stalledSince = Date.now();
|
|
149
290
|
}
|
|
150
|
-
const
|
|
151
|
-
|
|
291
|
+
const stalledMs = Date.now() - stalledSince;
|
|
292
|
+
if (stalledMs >= this.lockWaitMs)
|
|
293
|
+
throw unavailable(this.descriptor, lastCause, `${sqliteFailureDetail(lastCause) ?? "database is locked"}; gave up after ${stalledMs} ms waiting for the write lock${behind ? " in the writers' queue" : ""}, held all that time with no other connection committing`);
|
|
294
|
+
const delay = ticket !== undefined && !behind ? Math.min(backoff, LOCK_RETRY_HEAD_MAX_DELAY_MS) : backoff;
|
|
295
|
+
backoff = Math.min(LOCK_RETRY_MAX_DELAY_MS, backoff * 2);
|
|
296
|
+
await new Promise((resolve) => setTimeout(resolve, delay * (0.5 + Math.random() / 2)));
|
|
152
297
|
}
|
|
153
298
|
}
|
|
299
|
+
finally {
|
|
300
|
+
ticket?.leave();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** Runs a writers'-queue file operation; a failure (an unwritable queue directory, say) is a storage failure. */
|
|
304
|
+
queueOp(operation) {
|
|
305
|
+
try {
|
|
306
|
+
return operation();
|
|
307
|
+
}
|
|
308
|
+
catch (cause) {
|
|
309
|
+
throw unavailable(this.descriptor, cause, `the writers' queue next to the database is unusable: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
310
|
+
}
|
|
154
311
|
}
|
|
155
312
|
createExecutor(active) {
|
|
156
313
|
const execute = async (operation, params = []) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-sqlite.js","sourceRoot":"","sources":["../../../src/core/storage/node-sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, realpath } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type { SqliteDatabase, SqliteExecutor, SqliteRow, SqliteValue, StorageDescriptor } from \"./database.js\";\nimport {\n\tStorageAdapterLoadError,\n\ttype StorageFailureCause,\n\tStorageInvalidTextError,\n\tStorageRollbackError,\n\tStorageTransactionClosedError,\n\tStorageUnavailableError,\n\tStoreClosedError,\n} from \"./errors.js\";\n\ninterface TransactionGates {\n\treadonly files: Map<string, Promise<void>>;\n\treadonly connections: WeakMap<DatabaseSync, Promise<void>>;\n}\n\n// Share gates across module reloads as well as adapter instances. Only live queues retain file identities.\nconst TRANSACTION_GATES = Symbol.for(\"atomic-storage/node-sqlite-transaction-gates@1\");\nconst gateBag = globalThis as typeof globalThis & Record<symbol, TransactionGates | undefined>;\nconst gates: TransactionGates = gateBag[TRANSACTION_GATES] ?? { files: new Map(), connections: new WeakMap() };\ngateBag[TRANSACTION_GATES] = gates;\n\nfunction gateTransaction<T>(identity: string | DatabaseSync, operation: () => Promise<T>): Promise<T> {\n\tconst prior = typeof identity === \"string\" ? gates.files.get(identity) : gates.connections.get(identity);\n\tconst result = (prior ?? Promise.resolve()).then(operation);\n\tconst settled = result.then(\n\t\t() => {},\n\t\t() => {},\n\t);\n\tif (typeof identity === \"string\") gates.files.set(identity, settled);\n\telse gates.connections.set(identity, settled);\n\tvoid settled.then(() => {\n\t\tif (typeof identity === \"string\") {\n\t\t\tif (gates.files.get(identity) === settled) gates.files.delete(identity);\n\t\t} else if (gates.connections.get(identity) === settled) gates.connections.delete(identity);\n\t});\n\treturn result;\n}\n\n/** Copies binary parameters so queued work binds the bytes the caller passed, not later buffer contents. */\nfunction snapshotParams(params: readonly SqliteValue[]): SqliteValue[] {\n\treturn params.map((value) => (value instanceof Uint8Array ? new Uint8Array(value) : value));\n}\n\n/**\n * Bun's `DatabaseSync.close()` defers closing the file until garbage collection finalizes every statement the\n * connection prepared, so the database, WAL and shared-memory files stay open (and locked on Windows). The adapter\n * keeps no statement references, so a synchronous collection finalizes them and releases the files. Node finalizes\n * statements inside `close()` and has no `Bun` global.\n */\nfunction finalizeReleasedStatements(): void {\n\t(globalThis as { Bun?: { gc(force: boolean): void } }).Bun?.gc(true);\n}\n\n/** Default for how long a transaction keeps retrying `BEGIN IMMEDIATE` while another connection holds the write lock. */\nconst DEFAULT_NODE_SQLITE_LOCK_WAIT_MS = 30_000;\nconst LOCK_RETRY_BASE_DELAY_MS = 5;\nconst LOCK_RETRY_MAX_DELAY_MS = 100;\n/** Most transactions one group commit carries, so a batch cannot keep the write lock from other processes for long. */\nconst MAX_GROUP_COMMIT_TRANSACTIONS = 128;\n\ninterface QueuedTransaction {\n\treadonly callback: (transaction: SqliteExecutor) => Promise<unknown>;\n\treadonly resolve: (value: unknown) => void;\n\treadonly reject: (error: unknown) => void;\n}\n\ntype TransactionOutcome =\n\t| { readonly ok: true; readonly value: unknown }\n\t| { readonly ok: false; readonly error: unknown };\n\n/** SQLITE_BUSY, including its extended codes: another connection holds the lock this statement needs. */\nfunction isSqliteBusy(cause: unknown): boolean {\n\tconst code = (cause as { errcode?: unknown } | null | undefined)?.errcode;\n\treturn typeof code === \"number\" && (code & 0xff) === 5;\n}\n\n/** The driver's own reason, kept in the error message so it survives relays that forward only `message`. */\nfunction sqliteFailureDetail(cause: unknown): string | undefined {\n\tif (!(cause instanceof Error) || cause.message === \"\") return undefined;\n\tconst code = (cause as { errcode?: unknown }).errcode;\n\treturn typeof code === \"number\" ? `${cause.message} (SQLite code ${code})` : cause.message;\n}\n\nfunction unavailable(descriptor: StorageDescriptor, cause: unknown, detail = sqliteFailureDetail(cause)) {\n\treturn new StorageUnavailableError(descriptor, cause as StorageFailureCause, detail);\n}\n\nfunction normalizeRow(row: Record<string, SqliteValue>): SqliteRow {\n\treturn Object.fromEntries(\n\t\tObject.entries(row).map(([key, value]) => [\n\t\t\tkey,\n\t\t\ttypeof value === \"bigint\" &&\n\t\t\tvalue >= -BigInt(Number.MAX_SAFE_INTEGER) &&\n\t\t\tvalue <= BigInt(Number.MAX_SAFE_INTEGER)\n\t\t\t\t? Number(value)\n\t\t\t\t: value instanceof Uint8Array\n\t\t\t\t\t? new Uint8Array(value)\n\t\t\t\t\t: value,\n\t\t]),\n\t);\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\treadonly descriptor: StorageDescriptor;\n\tprivate readonly connection: DatabaseSync;\n\tprivate tail: Promise<void> = Promise.resolve();\n\tprivate openBatch?: QueuedTransaction[];\n\tprivate closing = false;\n\tprivate closePromise?: Promise<void>;\n\tprivate readonly executor: SqliteExecutor;\n\n\tprivate readonly ownsConnection: boolean;\n\tprivate readonly transactionIdentity: string | DatabaseSync;\n\tprivate readonly lockWaitMs: number;\n\n\tconstructor(\n\t\tconnection: DatabaseSync,\n\t\tdescriptor: StorageDescriptor,\n\t\townsConnection = true,\n\t\ttransactionIdentity: string | DatabaseSync = connection,\n\t\tlockWaitMs = DEFAULT_NODE_SQLITE_LOCK_WAIT_MS,\n\t) {\n\t\tthis.lockWaitMs = lockWaitMs;\n\t\tthis.transactionIdentity = transactionIdentity;\n\t\tthis.ownsConnection = ownsConnection;\n\t\tthis.connection = connection;\n\t\tthis.descriptor = descriptor;\n\t\tthis.executor = this.createExecutor(() => true);\n\t}\n\n\tprivate driver<T>(operation: () => T): T {\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (cause) {\n\t\t\tthrow unavailable(this.descriptor, cause);\n\t\t}\n\t}\n\n\t/**\n\t * One non-blocking `BEGIN IMMEDIATE`. node:sqlite runs `busy_timeout` synchronously, so a lock held by another\n\t * process would freeze this process's event loop for the whole timeout. The attempt runs with `busy_timeout=0`\n\t * and the connection's own value is restored before returning or throwing, so single statements outside a\n\t * transaction keep it. Callers reach this only through `enqueue` and the transaction gate, so nothing else runs\n\t * on the connection in between.\n\t */\n\tprivate tryBegin(): void {\n\t\tthis.driver(() => {\n\t\t\tconst configured = Number(this.connection.prepare(\"PRAGMA busy_timeout\").get()?.timeout ?? 0);\n\t\t\tthis.connection.exec(\"PRAGMA busy_timeout=0\");\n\t\t\tlet began = false;\n\t\t\ttry {\n\t\t\t\tthis.connection.exec(\"BEGIN IMMEDIATE\");\n\t\t\t\tbegan = true;\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tthis.connection.exec(`PRAGMA busy_timeout=${configured}`);\n\t\t\t\t} catch (restoreFailure) {\n\t\t\t\t\t// Never hand back a transaction on a connection whose lock wait is no longer the configured one.\n\t\t\t\t\tif (began) this.connection.exec(\"ROLLBACK\");\n\t\t\t\t\t// biome-ignore lint/correctness/noUnsafeFinally: a failed restore must replace the attempt's outcome.\n\t\t\t\t\tthrow restoreFailure;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Takes the write lock without blocking the event loop. Nothing has run yet when `BEGIN IMMEDIATE` reports\n\t * SQLITE_BUSY, so the attempt is retried after a jittered timer until `lockWaitMs` has passed; every other\n\t * failure, and a lock still held at the deadline, rejects at once with its cause.\n\t */\n\tprivate async begin(): Promise<void> {\n\t\tconst started = Date.now();\n\t\tfor (let attempt = 0; ; attempt += 1) {\n\t\t\ttry {\n\t\t\t\tthis.tryBegin();\n\t\t\t\treturn;\n\t\t\t} catch (error) {\n\t\t\t\tconst cause = error instanceof StorageUnavailableError ? error.cause : undefined;\n\t\t\t\tif (!isSqliteBusy(cause)) throw error;\n\t\t\t\tconst remaining = started + this.lockWaitMs - Date.now();\n\t\t\t\tif (remaining <= 0) {\n\t\t\t\t\tthrow unavailable(\n\t\t\t\t\t\tthis.descriptor,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t\t`${sqliteFailureDetail(cause)}; gave up after waiting ${Date.now() - started} ms for the write lock`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst backoff = Math.min(LOCK_RETRY_MAX_DELAY_MS, LOCK_RETRY_BASE_DELAY_MS * 2 ** attempt);\n\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\tsetTimeout(resolve, Math.min(remaining, backoff * (0.5 + Math.random() / 2))),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate createExecutor(active: () => boolean): SqliteExecutor {\n\t\tconst execute = async <T>(operation: () => T, params: readonly SqliteValue[] = []): Promise<T> => {\n\t\t\tif (!active()) throw new StorageTransactionClosedError();\n\t\t\tconst invalidIndex = params.findIndex((value) => typeof value === \"string\" && value.includes(\"\\0\"));\n\t\t\tif (invalidIndex !== -1) throw new StorageInvalidTextError(invalidIndex);\n\t\t\treturn this.driver(operation);\n\t\t};\n\t\tconst statement = (sql: string) => {\n\t\t\tconst prepared = this.connection.prepare(sql);\n\t\t\tprepared.setReadBigInts(true);\n\t\t\treturn prepared;\n\t\t};\n\t\treturn {\n\t\t\texec: (sql) => execute(() => this.connection.exec(sql)),\n\t\t\trun: (sql, ...params) => execute(() => ({ changes: Number(statement(sql).run(...params).changes) }), params),\n\t\t\tget: <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) =>\n\t\t\t\texecute(() => {\n\t\t\t\t\tconst row = statement(sql).get(...params);\n\t\t\t\t\treturn row === undefined ? undefined : (normalizeRow(row) as T);\n\t\t\t\t}, params),\n\t\t\tall: <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) =>\n\t\t\t\texecute(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tstatement(sql)\n\t\t\t\t\t\t\t.all(...params)\n\t\t\t\t\t\t\t.map((row) => normalizeRow(row) as T),\n\t\t\t\t\tparams,\n\t\t\t\t),\n\t\t};\n\t}\n\n\tprivate enqueue<T>(operation: () => Promise<T>): Promise<T> {\n\t\tif (this.closing) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\tconst result = this.tail.then(operation);\n\t\tthis.tail = result.then(\n\t\t\t() => {},\n\t\t\t() => {},\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** A statement queued after open transactions runs after them, so later transactions start a new batch. */\n\tprivate enqueueStatement<T>(operation: () => Promise<T>): Promise<T> {\n\t\tthis.openBatch = undefined;\n\t\treturn this.enqueue(operation);\n\t}\n\n\texec(sql: string): Promise<void> {\n\t\treturn this.enqueueStatement(() => this.executor.exec(sql));\n\t}\n\n\trun(sql: string, ...params: readonly SqliteValue[]) {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.run(sql, ...bound));\n\t}\n\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined> {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.get<T>(sql, ...bound));\n\t}\n\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]> {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.all<T>(sql, ...bound));\n\t}\n\n\t/**\n\t * Group commit: transactions queued while earlier work holds the connection join one `BEGIN IMMEDIATE … COMMIT`,\n\t * each inside its own savepoint and in the order they were requested. A transaction that throws rolls back only\n\t * its savepoint and rejects only its caller; every caller settles after the shared commit, so durability is the\n\t * same as a transaction of its own. Under load one lock acquisition and one sync serve the whole batch.\n\t */\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T> {\n\t\tif (this.closing) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst queued: QueuedTransaction = { callback, resolve: resolve as (value: unknown) => void, reject };\n\t\t\tif (this.openBatch !== undefined && this.openBatch.length < MAX_GROUP_COMMIT_TRANSACTIONS) {\n\t\t\t\tthis.openBatch.push(queued);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.startBatch([queued]);\n\t\t});\n\t}\n\n\tprivate startBatch(batch: QueuedTransaction[]): void {\n\t\tthis.openBatch = batch;\n\t\tvoid this.enqueue(() => this.commitBatch(batch));\n\t}\n\n\tprivate commitBatch(batch: QueuedTransaction[]): Promise<void> {\n\t\tif (this.openBatch === batch) this.openBatch = undefined;\n\t\treturn gateTransaction(this.transactionIdentity, () =>\n\t\t\tbatch.length === 1 ? this.commitAlone(batch[0]!) : this.commitMembers(batch),\n\t\t);\n\t}\n\n\t/** A transaction with nobody queued behind it commits on its own, without savepoints. */\n\tprivate async commitAlone(queued: QueuedTransaction): Promise<void> {\n\t\ttry {\n\t\t\tawait this.begin();\n\t\t} catch (cause) {\n\t\t\tqueued.reject(cause);\n\t\t\treturn;\n\t\t}\n\t\tlet active = true;\n\t\ttry {\n\t\t\tconst value = await queued.callback(this.createExecutor(() => active));\n\t\t\tactive = false;\n\t\t\tawait this.executor.exec(\"COMMIT\");\n\t\t\tqueued.resolve(value);\n\t\t} catch (cause) {\n\t\t\tactive = false;\n\t\t\ttry {\n\t\t\t\tawait this.executor.exec(\"ROLLBACK\");\n\t\t\t} catch (rollbackCause) {\n\t\t\t\tqueued.reject(new StorageRollbackError(cause as StorageFailureCause, rollbackCause as StorageFailureCause));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tqueued.reject(cause);\n\t\t}\n\t}\n\n\tprivate async commitMembers(batch: QueuedTransaction[]): Promise<void> {\n\t\ttry {\n\t\t\tawait this.begin();\n\t\t} catch (cause) {\n\t\t\tfor (const queued of batch) queued.reject(cause);\n\t\t\treturn;\n\t\t}\n\t\tconst outcomes: TransactionOutcome[] = [];\n\t\tfor (const queued of batch) {\n\t\t\tconst savepoint = `atomic_group_${outcomes.length}`;\n\t\t\tlet active = true;\n\t\t\ttry {\n\t\t\t\tawait this.executor.exec(`SAVEPOINT ${savepoint}`);\n\t\t\t\tconst value = await queued.callback(this.createExecutor(() => active));\n\t\t\t\tactive = false;\n\t\t\t\tawait this.executor.exec(`RELEASE ${savepoint}`);\n\t\t\t\toutcomes.push({ ok: true, value });\n\t\t\t} catch (cause) {\n\t\t\t\tactive = false;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executor.exec(`ROLLBACK TO ${savepoint}`);\n\t\t\t\t\tawait this.executor.exec(`RELEASE ${savepoint}`);\n\t\t\t\t} catch (rollbackCause) {\n\t\t\t\t\tawait this.abandonMembers(batch, outcomes, cause, rollbackCause);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\toutcomes.push({ ok: false, error: cause });\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait this.executor.exec(\"COMMIT\");\n\t\t} catch (commitCause) {\n\t\t\tawait this.rollbackQuietly();\n\t\t\tbatch.forEach((queued, index) => {\n\t\t\t\tconst outcome = outcomes[index]!;\n\t\t\t\tqueued.reject(outcome.ok ? commitCause : outcome.error);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tbatch.forEach((queued, index) => {\n\t\t\tconst outcome = outcomes[index]!;\n\t\t\tif (outcome.ok) queued.resolve(outcome.value);\n\t\t\telse queued.reject(outcome.error);\n\t\t});\n\t}\n\n\t/**\n\t * A savepoint that cannot be rolled back leaves the whole transaction unusable: earlier members lose their\n\t * uncommitted writes and fail, the failing member reports both causes, and members that have not run yet get a\n\t * fresh transaction right away, still ahead of anything queued after them, because nothing of theirs has happened.\n\t */\n\tprivate async abandonMembers(\n\t\tbatch: QueuedTransaction[],\n\t\toutcomes: TransactionOutcome[],\n\t\tcause: unknown,\n\t\trollbackCause: unknown,\n\t): Promise<void> {\n\t\tawait this.rollbackQuietly();\n\t\tconst failed = outcomes.length;\n\t\tbatch.slice(0, failed).forEach((queued, index) => {\n\t\t\tconst outcome = outcomes[index]!;\n\t\t\tqueued.reject(outcome.ok ? unavailable(this.descriptor, rollbackCause) : outcome.error);\n\t\t});\n\t\tbatch[failed]!.reject(\n\t\t\tnew StorageRollbackError(cause as StorageFailureCause, rollbackCause as StorageFailureCause),\n\t\t);\n\t\tconst remaining = batch.slice(failed + 1);\n\t\tif (remaining.length > 0) await this.commitMembers(remaining);\n\t}\n\n\tprivate async rollbackQuietly(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.executor.exec(\"ROLLBACK\");\n\t\t} catch {\n\t\t\t// SQLite already rolled the transaction back; there is nothing left to undo.\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\tif (!this.closePromise) {\n\t\t\tthis.closing = true;\n\t\t\tthis.closePromise = this.tail.then(() =>\n\t\t\t\tthis.driver(() => {\n\t\t\t\t\tif (this.ownsConnection) this.connection.close();\n\t\t\t\t\tfinalizeReleasedStatements();\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn this.closePromise;\n\t}\n}\n\nexport async function openNodeSqliteDatabase(\n\tpath: string,\n\t{\n\t\tbusyTimeoutMs = 5000,\n\t\tlockWaitMs = DEFAULT_NODE_SQLITE_LOCK_WAIT_MS,\n\t\treadOnly = false,\n\t}: { busyTimeoutMs?: number; lockWaitMs?: number; readOnly?: boolean } = {},\n): Promise<SqliteDatabase> {\n\tconst descriptor = { adapter: \"node-sqlite\", location: path };\n\t// Load node:sqlite on first open: importing it prints Node's experimental warning, which every importer of the\n\t// package entry point would otherwise see.\n\tlet Database: typeof DatabaseSync;\n\ttry {\n\t\t({ DatabaseSync: Database } = await import(\"node:sqlite\"));\n\t} catch (cause) {\n\t\tthrow new StorageAdapterLoadError(\"node:sqlite\", cause as StorageFailureCause);\n\t}\n\tlet connection: DatabaseSync | undefined;\n\ttry {\n\t\tif (!readOnly && path !== \":memory:\") await mkdir(dirname(path), { recursive: true });\n\t\tconnection = new Database(path, { readOnly });\n\t\tconnection.exec(`PRAGMA busy_timeout=${busyTimeoutMs}`);\n\t\tif (!readOnly) connection.exec(\"PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON\");\n\t\tconst location = connection.location();\n\t\tconst identity = location === null ? connection : await realpath(location);\n\t\treturn new NodeSqliteDatabase(connection, descriptor, true, identity, lockWaitMs);\n\t} catch (cause) {\n\t\ttry {\n\t\t\tconnection?.close();\n\t\t} catch {\n\t\t\t// Preserve the opening failure if cleanup also fails.\n\t\t}\n\t\tthrow unavailable(descriptor, cause);\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(connection: DatabaseSync): SqliteDatabase {\n\tconst descriptor = { adapter: \"node-sqlite\", location: \":memory:\" };\n\ttry {\n\t\tdescriptor.location = connection.location() || \":memory:\";\n\t\tconnection.exec(\n\t\t\t\"PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON\",\n\t\t);\n\t\treturn new NodeSqliteDatabase(connection, descriptor, false);\n\t} catch (cause) {\n\t\tthrow unavailable(descriptor, cause);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-sqlite.js","sourceRoot":"","sources":["../../../src/core/storage/node-sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, readdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from \"node:fs\";\nimport { mkdir, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type { SqliteDatabase, SqliteExecutor, SqliteRow, SqliteValue, StorageDescriptor } from \"./database.js\";\nimport {\n\tStorageAdapterLoadError,\n\ttype StorageFailureCause,\n\tStorageInvalidTextError,\n\tStorageRollbackError,\n\tStorageTransactionClosedError,\n\tStorageUnavailableError,\n\tStoreClosedError,\n} from \"./errors.js\";\n\n/** A ticket its owner has not refreshed for this long belongs to a process that died or stopped waiting. */\nconst TICKET_STALE_MS = 2_000;\n/** Stale tickets older than this are removed by whichever writer notices them. */\nconst TICKET_REMOVE_AFTER_MS = 10 * TICKET_STALE_MS;\n\nlet ticketSequence = 0;\n\nfunction ticketName(): string {\n\tticketSequence += 1;\n\treturn `${String(Date.now()).padStart(15, \"0\")}-${process.pid}-${ticketSequence}`;\n}\n\n/**\n * First come, first served for SQLite's write lock across processes. SQLite has no queue for `BEGIN IMMEDIATE`: a\n * writer that polls after `SQLITE_BUSY` loses to one that begins the moment the lock is free, and a busy process\n * can take the lock again and again while another waits for its whole deadline (#3978). A writer that has been\n * refused takes a ticket, a file named by the time it started waiting, in a directory next to the database; it then\n * attempts the lock only once no live older ticket is ahead of it, and a writer that arrives while tickets wait\n * queues behind them instead of overtaking. Uncontended writers only list an absent or empty directory.\n */\nclass SqliteWriteQueue {\n\tprivate readonly directory: string;\n\n\tconstructor(databasePath: string) {\n\t\tthis.directory = `${databasePath}-writers`;\n\t}\n\n\t/** Whether another writer's live ticket is waiting, so a new writer must queue behind it. */\n\tothersWaiting(): boolean {\n\t\treturn this.liveTickets().length > 0;\n\t}\n\n\tjoin(): SqliteWriteTicket {\n\t\tmkdirSync(this.directory, { recursive: true });\n\t\tconst name = ticketName();\n\t\tconst path = join(this.directory, name);\n\t\twriteFileSync(path, \"\", { flag: \"wx\" });\n\t\treturn new SqliteWriteTicket(this, name, path);\n\t}\n\n\t/** Live tickets, oldest first; stale ones long abandoned are removed on the way. */\n\tliveTickets(except?: string): string[] {\n\t\tlet names: string[];\n\t\ttry {\n\t\t\tnames = readdirSync(this.directory);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t\tconst now = Date.now();\n\t\tconst live: string[] = [];\n\t\tfor (const name of names) {\n\t\t\tif (name === except) continue;\n\t\t\tlet age: number;\n\t\t\ttry {\n\t\t\t\tage = now - statSync(join(this.directory, name)).mtimeMs;\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (age < TICKET_STALE_MS) live.push(name);\n\t\t\telse if (age > TICKET_REMOVE_AFTER_MS) {\n\t\t\t\ttry {\n\t\t\t\t\tunlinkSync(join(this.directory, name));\n\t\t\t\t} catch {\n\t\t\t\t\t// Another writer removed it first.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn live.sort();\n\t}\n}\n\nclass SqliteWriteTicket {\n\tprivate left = false;\n\tprivate readonly queue: SqliteWriteQueue;\n\tprivate readonly name: string;\n\tprivate readonly path: string;\n\n\tconstructor(queue: SqliteWriteQueue, name: string, path: string) {\n\t\tthis.queue = queue;\n\t\tthis.name = name;\n\t\tthis.path = path;\n\t}\n\n\t/** Marks this ticket live and reports whether an older live ticket is still ahead of it. */\n\tbehindOthers(): boolean {\n\t\tif (this.left) return false;\n\t\tconst now = new Date();\n\t\ttry {\n\t\t\tutimesSync(this.path, now, now);\n\t\t} catch {\n\t\t\t// The ticket was removed as stale while this writer stalled: take the place it would have had.\n\t\t\twriteFileSync(this.path, \"\");\n\t\t}\n\t\treturn this.queue.liveTickets(this.name).some((other) => other < this.name);\n\t}\n\n\tleave(): void {\n\t\tif (this.left) return;\n\t\tthis.left = true;\n\t\ttry {\n\t\t\tunlinkSync(this.path);\n\t\t} catch {\n\t\t\t// Already removed.\n\t\t}\n\t}\n}\n\ninterface TransactionGates {\n\treadonly files: Map<string, Promise<void>>;\n\treadonly connections: WeakMap<DatabaseSync, Promise<void>>;\n}\n\n// Share gates across module reloads as well as adapter instances. Only live queues retain file identities.\nconst TRANSACTION_GATES = Symbol.for(\"atomic-storage/node-sqlite-transaction-gates@1\");\nconst gateBag = globalThis as typeof globalThis & Record<symbol, TransactionGates | undefined>;\nconst gates: TransactionGates = gateBag[TRANSACTION_GATES] ?? { files: new Map(), connections: new WeakMap() };\ngateBag[TRANSACTION_GATES] = gates;\n\nfunction gateTransaction<T>(identity: string | DatabaseSync, operation: () => Promise<T>): Promise<T> {\n\tconst prior = typeof identity === \"string\" ? gates.files.get(identity) : gates.connections.get(identity);\n\tconst result = (prior ?? Promise.resolve()).then(operation);\n\tconst settled = result.then(\n\t\t() => {},\n\t\t() => {},\n\t);\n\tif (typeof identity === \"string\") gates.files.set(identity, settled);\n\telse gates.connections.set(identity, settled);\n\tvoid settled.then(() => {\n\t\tif (typeof identity === \"string\") {\n\t\t\tif (gates.files.get(identity) === settled) gates.files.delete(identity);\n\t\t} else if (gates.connections.get(identity) === settled) gates.connections.delete(identity);\n\t});\n\treturn result;\n}\n\n/** Copies binary parameters so queued work binds the bytes the caller passed, not later buffer contents. */\nfunction snapshotParams(params: readonly SqliteValue[]): SqliteValue[] {\n\treturn params.map((value) => (value instanceof Uint8Array ? new Uint8Array(value) : value));\n}\n\n/**\n * Bun's `DatabaseSync.close()` defers closing the file until garbage collection finalizes every statement the\n * connection prepared, so the database, WAL and shared-memory files stay open (and locked on Windows). The adapter\n * keeps no statement references, so a synchronous collection finalizes them and releases the files. Node finalizes\n * statements inside `close()` and has no `Bun` global.\n */\nfunction finalizeReleasedStatements(): void {\n\t(globalThis as { Bun?: { gc(force: boolean): void } }).Bun?.gc(true);\n}\n\n/**\n * Default for how long a transaction keeps retrying `BEGIN IMMEDIATE` while the write lock is held and nobody makes\n * progress through it: every commit by another connection restarts the wait, so only a lock held without commits\n * for this long fails the transaction.\n */\nconst DEFAULT_NODE_SQLITE_LOCK_WAIT_MS = 30_000;\nconst LOCK_RETRY_BASE_DELAY_MS = 5;\nconst LOCK_RETRY_MAX_DELAY_MS = 100;\n/** A writer at the head of the cross-process queue retries at least this often, so the lock it is owed does not sit idle. */\nconst LOCK_RETRY_HEAD_MAX_DELAY_MS = 20;\n/** Most transactions one group commit carries, so a batch cannot keep the write lock from other processes for long. */\nconst MAX_GROUP_COMMIT_TRANSACTIONS = 128;\n\ninterface QueuedTransaction {\n\treadonly callback: (transaction: SqliteExecutor) => Promise<unknown>;\n\treadonly resolve: (value: unknown) => void;\n\treadonly reject: (error: unknown) => void;\n}\n\ntype TransactionOutcome =\n\t| { readonly ok: true; readonly value: unknown }\n\t| { readonly ok: false; readonly error: unknown };\n\n/** SQLITE_BUSY, including its extended codes: another connection holds the lock this statement needs. */\nfunction isSqliteBusy(cause: unknown): boolean {\n\tconst code = (cause as { errcode?: unknown } | null | undefined)?.errcode;\n\treturn typeof code === \"number\" && (code & 0xff) === 5;\n}\n\n/** The driver's own reason, kept in the error message so it survives relays that forward only `message`. */\nfunction sqliteFailureDetail(cause: unknown): string | undefined {\n\tif (!(cause instanceof Error) || cause.message === \"\") return undefined;\n\tconst code = (cause as { errcode?: unknown }).errcode;\n\treturn typeof code === \"number\" ? `${cause.message} (SQLite code ${code})` : cause.message;\n}\n\nfunction unavailable(descriptor: StorageDescriptor, cause: unknown, detail = sqliteFailureDetail(cause)) {\n\treturn new StorageUnavailableError(descriptor, cause as StorageFailureCause, detail);\n}\n\nfunction normalizeRow(row: Record<string, SqliteValue>): SqliteRow {\n\treturn Object.fromEntries(\n\t\tObject.entries(row).map(([key, value]) => [\n\t\t\tkey,\n\t\t\ttypeof value === \"bigint\" &&\n\t\t\tvalue >= -BigInt(Number.MAX_SAFE_INTEGER) &&\n\t\t\tvalue <= BigInt(Number.MAX_SAFE_INTEGER)\n\t\t\t\t? Number(value)\n\t\t\t\t: value instanceof Uint8Array\n\t\t\t\t\t? new Uint8Array(value)\n\t\t\t\t\t: value,\n\t\t]),\n\t);\n}\n\nclass NodeSqliteDatabase implements SqliteDatabase {\n\treadonly descriptor: StorageDescriptor;\n\tprivate readonly connection: DatabaseSync;\n\tprivate tail: Promise<void> = Promise.resolve();\n\tprivate openBatch?: QueuedTransaction[];\n\tprivate closing = false;\n\tprivate closePromise?: Promise<void>;\n\tprivate readonly executor: SqliteExecutor;\n\n\tprivate readonly ownsConnection: boolean;\n\tprivate readonly transactionIdentity: string | DatabaseSync;\n\tprivate readonly lockWaitMs: number;\n\t/** Cross-process first-come-first-served order for the write lock; absent for in-memory databases. */\n\tprivate readonly writeQueue?: SqliteWriteQueue;\n\n\tconstructor(\n\t\tconnection: DatabaseSync,\n\t\tdescriptor: StorageDescriptor,\n\t\townsConnection = true,\n\t\ttransactionIdentity: string | DatabaseSync = connection,\n\t\tlockWaitMs = DEFAULT_NODE_SQLITE_LOCK_WAIT_MS,\n\t) {\n\t\tthis.lockWaitMs = lockWaitMs;\n\t\tthis.transactionIdentity = transactionIdentity;\n\t\tthis.ownsConnection = ownsConnection;\n\t\tthis.connection = connection;\n\t\tthis.descriptor = descriptor;\n\t\tthis.executor = this.createExecutor(() => true);\n\t\tif (typeof transactionIdentity === \"string\") this.writeQueue = new SqliteWriteQueue(transactionIdentity);\n\t}\n\n\tprivate driver<T>(operation: () => T): T {\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (cause) {\n\t\t\tthrow unavailable(this.descriptor, cause);\n\t\t}\n\t}\n\n\t/**\n\t * One non-blocking `BEGIN IMMEDIATE`. node:sqlite runs `busy_timeout` synchronously, so a lock held by another\n\t * process would freeze this process's event loop for the whole timeout. The attempt runs with `busy_timeout=0`\n\t * and the connection's own value is restored before returning or throwing, so single statements outside a\n\t * transaction keep it. Callers reach this only through `enqueue` and the transaction gate, so nothing else runs\n\t * on the connection in between.\n\t */\n\tprivate tryBegin(): void {\n\t\tthis.driver(() => {\n\t\t\tconst configured = Number(this.connection.prepare(\"PRAGMA busy_timeout\").get()?.timeout ?? 0);\n\t\t\tthis.connection.exec(\"PRAGMA busy_timeout=0\");\n\t\t\tlet began = false;\n\t\t\ttry {\n\t\t\t\tthis.connection.exec(\"BEGIN IMMEDIATE\");\n\t\t\t\tbegan = true;\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tthis.connection.exec(`PRAGMA busy_timeout=${configured}`);\n\t\t\t\t} catch (restoreFailure) {\n\t\t\t\t\t// Never hand back a transaction on a connection whose lock wait is no longer the configured one.\n\t\t\t\t\tif (began) this.connection.exec(\"ROLLBACK\");\n\t\t\t\t\t// biome-ignore lint/correctness/noUnsafeFinally: a failed restore must replace the attempt's outcome.\n\t\t\t\t\tthrow restoreFailure;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/** Changes whenever another connection commits to the database: the lock is being used, not held idle. */\n\tprivate dataVersion(): number {\n\t\treturn this.driver(() => Number(this.connection.prepare(\"PRAGMA data_version\").get()?.data_version ?? 0));\n\t}\n\n\t/**\n\t * Takes the write lock without blocking the event loop. Nothing has run yet when `BEGIN IMMEDIATE` reports\n\t * SQLITE_BUSY, so the attempt is retried after a timer. A refused writer queues with writers in other processes\n\t * and attempts the lock only when no earlier writer is still waiting, so none starves (#3978). The wait ends only\n\t * when no other connection has committed for `lockWaitMs`, whether this writer is still queued or already trying\n\t * the lock: a queued writer counts only real commits as progress, not older tickets ahead of it. Every other\n\t * failure, including a writers' queue that cannot be used, rejects at once with its cause.\n\t */\n\tprivate async begin(): Promise<void> {\n\t\tlet ticket: SqliteWriteTicket | undefined;\n\t\ttry {\n\t\t\t// Writers already waiting in other processes go first.\n\t\t\tif (this.queueOp(() => this.writeQueue?.othersWaiting())) ticket = this.queueOp(() => this.writeQueue?.join());\n\t\t\t// Read only once this writer waits, so an uncontended transaction pays nothing for it.\n\t\t\tlet version = ticket === undefined ? undefined : this.dataVersion();\n\t\t\tlet stalledSince = Date.now();\n\t\t\tlet backoff = LOCK_RETRY_BASE_DELAY_MS;\n\t\t\tlet lastCause: unknown;\n\t\t\tfor (;;) {\n\t\t\t\tconst behind = ticket !== undefined && this.queueOp(() => ticket!.behindOthers());\n\t\t\t\tif (!behind) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.tryBegin();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst cause = error instanceof StorageUnavailableError ? error.cause : undefined;\n\t\t\t\t\t\tif (!isSqliteBusy(cause)) throw error;\n\t\t\t\t\t\tlastCause = cause;\n\t\t\t\t\t\tticket ??= this.queueOp(() => this.writeQueue?.join());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Only another connection's commit is progress; a queued writer measures its stall the same way.\n\t\t\t\tconst current = this.dataVersion();\n\t\t\t\tif (version === undefined) version = current;\n\t\t\t\telse if (current !== version) {\n\t\t\t\t\tversion = current;\n\t\t\t\t\tstalledSince = Date.now();\n\t\t\t\t}\n\t\t\t\tconst stalledMs = Date.now() - stalledSince;\n\t\t\t\tif (stalledMs >= this.lockWaitMs)\n\t\t\t\t\tthrow unavailable(\n\t\t\t\t\t\tthis.descriptor,\n\t\t\t\t\t\tlastCause,\n\t\t\t\t\t\t`${sqliteFailureDetail(lastCause) ?? \"database is locked\"}; gave up after ${stalledMs} ms waiting for the write lock${behind ? \" in the writers' queue\" : \"\"}, held all that time with no other connection committing`,\n\t\t\t\t\t);\n\t\t\t\tconst delay = ticket !== undefined && !behind ? Math.min(backoff, LOCK_RETRY_HEAD_MAX_DELAY_MS) : backoff;\n\t\t\t\tbackoff = Math.min(LOCK_RETRY_MAX_DELAY_MS, backoff * 2);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay * (0.5 + Math.random() / 2)));\n\t\t\t}\n\t\t} finally {\n\t\t\tticket?.leave();\n\t\t}\n\t}\n\n\t/** Runs a writers'-queue file operation; a failure (an unwritable queue directory, say) is a storage failure. */\n\tprivate queueOp<T>(operation: () => T): T {\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (cause) {\n\t\t\tthrow unavailable(\n\t\t\t\tthis.descriptor,\n\t\t\t\tcause,\n\t\t\t\t`the writers' queue next to the database is unusable: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate createExecutor(active: () => boolean): SqliteExecutor {\n\t\tconst execute = async <T>(operation: () => T, params: readonly SqliteValue[] = []): Promise<T> => {\n\t\t\tif (!active()) throw new StorageTransactionClosedError();\n\t\t\tconst invalidIndex = params.findIndex((value) => typeof value === \"string\" && value.includes(\"\\0\"));\n\t\t\tif (invalidIndex !== -1) throw new StorageInvalidTextError(invalidIndex);\n\t\t\treturn this.driver(operation);\n\t\t};\n\t\tconst statement = (sql: string) => {\n\t\t\tconst prepared = this.connection.prepare(sql);\n\t\t\tprepared.setReadBigInts(true);\n\t\t\treturn prepared;\n\t\t};\n\t\treturn {\n\t\t\texec: (sql) => execute(() => this.connection.exec(sql)),\n\t\t\trun: (sql, ...params) => execute(() => ({ changes: Number(statement(sql).run(...params).changes) }), params),\n\t\t\tget: <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) =>\n\t\t\t\texecute(() => {\n\t\t\t\t\tconst row = statement(sql).get(...params);\n\t\t\t\t\treturn row === undefined ? undefined : (normalizeRow(row) as T);\n\t\t\t\t}, params),\n\t\t\tall: <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) =>\n\t\t\t\texecute(\n\t\t\t\t\t() =>\n\t\t\t\t\t\tstatement(sql)\n\t\t\t\t\t\t\t.all(...params)\n\t\t\t\t\t\t\t.map((row) => normalizeRow(row) as T),\n\t\t\t\t\tparams,\n\t\t\t\t),\n\t\t};\n\t}\n\n\tprivate enqueue<T>(operation: () => Promise<T>): Promise<T> {\n\t\tif (this.closing) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\tconst result = this.tail.then(operation);\n\t\tthis.tail = result.then(\n\t\t\t() => {},\n\t\t\t() => {},\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** A statement queued after open transactions runs after them, so later transactions start a new batch. */\n\tprivate enqueueStatement<T>(operation: () => Promise<T>): Promise<T> {\n\t\tthis.openBatch = undefined;\n\t\treturn this.enqueue(operation);\n\t}\n\n\texec(sql: string): Promise<void> {\n\t\treturn this.enqueueStatement(() => this.executor.exec(sql));\n\t}\n\n\trun(sql: string, ...params: readonly SqliteValue[]) {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.run(sql, ...bound));\n\t}\n\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined> {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.get<T>(sql, ...bound));\n\t}\n\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]> {\n\t\tconst bound = snapshotParams(params);\n\t\treturn this.enqueueStatement(() => this.executor.all<T>(sql, ...bound));\n\t}\n\n\t/**\n\t * Group commit: transactions queued while earlier work holds the connection join one `BEGIN IMMEDIATE … COMMIT`,\n\t * each inside its own savepoint and in the order they were requested. A transaction that throws rolls back only\n\t * its savepoint and rejects only its caller; every caller settles after the shared commit, so durability is the\n\t * same as a transaction of its own. Under load one lock acquisition and one sync serve the whole batch.\n\t */\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T> {\n\t\tif (this.closing) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst queued: QueuedTransaction = { callback, resolve: resolve as (value: unknown) => void, reject };\n\t\t\tif (this.openBatch !== undefined && this.openBatch.length < MAX_GROUP_COMMIT_TRANSACTIONS) {\n\t\t\t\tthis.openBatch.push(queued);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.startBatch([queued]);\n\t\t});\n\t}\n\n\tprivate startBatch(batch: QueuedTransaction[]): void {\n\t\tthis.openBatch = batch;\n\t\tvoid this.enqueue(() => this.commitBatch(batch));\n\t}\n\n\tprivate commitBatch(batch: QueuedTransaction[]): Promise<void> {\n\t\tif (this.openBatch === batch) this.openBatch = undefined;\n\t\treturn gateTransaction(this.transactionIdentity, () =>\n\t\t\tbatch.length === 1 ? this.commitAlone(batch[0]!) : this.commitMembers(batch),\n\t\t);\n\t}\n\n\t/** A transaction with nobody queued behind it commits on its own, without savepoints. */\n\tprivate async commitAlone(queued: QueuedTransaction): Promise<void> {\n\t\ttry {\n\t\t\tawait this.begin();\n\t\t} catch (cause) {\n\t\t\tqueued.reject(cause);\n\t\t\treturn;\n\t\t}\n\t\tlet active = true;\n\t\ttry {\n\t\t\tconst value = await queued.callback(this.createExecutor(() => active));\n\t\t\tactive = false;\n\t\t\tawait this.executor.exec(\"COMMIT\");\n\t\t\tqueued.resolve(value);\n\t\t} catch (cause) {\n\t\t\tactive = false;\n\t\t\ttry {\n\t\t\t\tawait this.executor.exec(\"ROLLBACK\");\n\t\t\t} catch (rollbackCause) {\n\t\t\t\tqueued.reject(new StorageRollbackError(cause as StorageFailureCause, rollbackCause as StorageFailureCause));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tqueued.reject(cause);\n\t\t}\n\t}\n\n\tprivate async commitMembers(batch: QueuedTransaction[]): Promise<void> {\n\t\ttry {\n\t\t\tawait this.begin();\n\t\t} catch (cause) {\n\t\t\tfor (const queued of batch) queued.reject(cause);\n\t\t\treturn;\n\t\t}\n\t\tconst outcomes: TransactionOutcome[] = [];\n\t\tfor (const queued of batch) {\n\t\t\tconst savepoint = `atomic_group_${outcomes.length}`;\n\t\t\tlet active = true;\n\t\t\ttry {\n\t\t\t\tawait this.executor.exec(`SAVEPOINT ${savepoint}`);\n\t\t\t\tconst value = await queued.callback(this.createExecutor(() => active));\n\t\t\t\tactive = false;\n\t\t\t\tawait this.executor.exec(`RELEASE ${savepoint}`);\n\t\t\t\toutcomes.push({ ok: true, value });\n\t\t\t} catch (cause) {\n\t\t\t\tactive = false;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.executor.exec(`ROLLBACK TO ${savepoint}`);\n\t\t\t\t\tawait this.executor.exec(`RELEASE ${savepoint}`);\n\t\t\t\t} catch (rollbackCause) {\n\t\t\t\t\tawait this.abandonMembers(batch, outcomes, cause, rollbackCause);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\toutcomes.push({ ok: false, error: cause });\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tawait this.executor.exec(\"COMMIT\");\n\t\t} catch (commitCause) {\n\t\t\tawait this.rollbackQuietly();\n\t\t\tbatch.forEach((queued, index) => {\n\t\t\t\tconst outcome = outcomes[index]!;\n\t\t\t\tqueued.reject(outcome.ok ? commitCause : outcome.error);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tbatch.forEach((queued, index) => {\n\t\t\tconst outcome = outcomes[index]!;\n\t\t\tif (outcome.ok) queued.resolve(outcome.value);\n\t\t\telse queued.reject(outcome.error);\n\t\t});\n\t}\n\n\t/**\n\t * A savepoint that cannot be rolled back leaves the whole transaction unusable: earlier members lose their\n\t * uncommitted writes and fail, the failing member reports both causes, and members that have not run yet get a\n\t * fresh transaction right away, still ahead of anything queued after them, because nothing of theirs has happened.\n\t */\n\tprivate async abandonMembers(\n\t\tbatch: QueuedTransaction[],\n\t\toutcomes: TransactionOutcome[],\n\t\tcause: unknown,\n\t\trollbackCause: unknown,\n\t): Promise<void> {\n\t\tawait this.rollbackQuietly();\n\t\tconst failed = outcomes.length;\n\t\tbatch.slice(0, failed).forEach((queued, index) => {\n\t\t\tconst outcome = outcomes[index]!;\n\t\t\tqueued.reject(outcome.ok ? unavailable(this.descriptor, rollbackCause) : outcome.error);\n\t\t});\n\t\tbatch[failed]!.reject(\n\t\t\tnew StorageRollbackError(cause as StorageFailureCause, rollbackCause as StorageFailureCause),\n\t\t);\n\t\tconst remaining = batch.slice(failed + 1);\n\t\tif (remaining.length > 0) await this.commitMembers(remaining);\n\t}\n\n\tprivate async rollbackQuietly(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.executor.exec(\"ROLLBACK\");\n\t\t} catch {\n\t\t\t// SQLite already rolled the transaction back; there is nothing left to undo.\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\tif (!this.closePromise) {\n\t\t\tthis.closing = true;\n\t\t\tthis.closePromise = this.tail.then(() =>\n\t\t\t\tthis.driver(() => {\n\t\t\t\t\tif (this.ownsConnection) this.connection.close();\n\t\t\t\t\tfinalizeReleasedStatements();\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn this.closePromise;\n\t}\n}\n\nexport async function openNodeSqliteDatabase(\n\tpath: string,\n\t{\n\t\tbusyTimeoutMs = 5000,\n\t\tlockWaitMs = DEFAULT_NODE_SQLITE_LOCK_WAIT_MS,\n\t\treadOnly = false,\n\t}: { busyTimeoutMs?: number; lockWaitMs?: number; readOnly?: boolean } = {},\n): Promise<SqliteDatabase> {\n\tconst descriptor = { adapter: \"node-sqlite\", location: path };\n\t// Load node:sqlite on first open: importing it prints Node's experimental warning, which every importer of the\n\t// package entry point would otherwise see.\n\tlet Database: typeof DatabaseSync;\n\ttry {\n\t\t({ DatabaseSync: Database } = await import(\"node:sqlite\"));\n\t} catch (cause) {\n\t\tthrow new StorageAdapterLoadError(\"node:sqlite\", cause as StorageFailureCause);\n\t}\n\tlet connection: DatabaseSync | undefined;\n\ttry {\n\t\tif (!readOnly && path !== \":memory:\") await mkdir(dirname(path), { recursive: true });\n\t\tconnection = new Database(path, { readOnly });\n\t\tconnection.exec(`PRAGMA busy_timeout=${busyTimeoutMs}`);\n\t\tif (!readOnly) connection.exec(\"PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON\");\n\t\tconst location = connection.location();\n\t\tconst identity = location === null ? connection : await realpath(location);\n\t\treturn new NodeSqliteDatabase(connection, descriptor, true, identity, lockWaitMs);\n\t} catch (cause) {\n\t\ttry {\n\t\t\tconnection?.close();\n\t\t} catch {\n\t\t\t// Preserve the opening failure if cleanup also fails.\n\t\t}\n\t\tthrow unavailable(descriptor, cause);\n\t}\n}\n\nexport function wrapNodeSqliteDatabase(connection: DatabaseSync): SqliteDatabase {\n\tconst descriptor = { adapter: \"node-sqlite\", location: \":memory:\" };\n\ttry {\n\t\tdescriptor.location = connection.location() || \":memory:\";\n\t\tconnection.exec(\n\t\t\t\"PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL; PRAGMA synchronous=FULL; PRAGMA foreign_keys=ON\",\n\t\t);\n\t\treturn new NodeSqliteDatabase(connection, descriptor, false);\n\t} catch (cause) {\n\t\tthrow unavailable(descriptor, cause);\n\t}\n}\n"]}
|
|
@@ -70,8 +70,10 @@ export declare function storageSelectionKey(selection: StorageSelection, agentDi
|
|
|
70
70
|
* Loads an adapter module the way the extension loader loads extensions: `@bastani/atomic/storage` (and
|
|
71
71
|
* `@bastani/atomic`) resolve to this host's own modules, so adapters need no installed copy of Atomic and share its
|
|
72
72
|
* error classes. `hostModules` adds live modules by specifier; run journals pass the running
|
|
73
|
-
* `@bastani/atomic/workflows`.
|
|
74
|
-
*
|
|
73
|
+
* `@bastani/atomic/workflows`. The ES module and TypeScript files the adapter imports by path get the same host
|
|
74
|
+
* modules; nested CommonJS files resolve them from `node_modules`. A package name selects an adapter listed by an
|
|
75
|
+
* installed Atomic package; other specifiers, and package names no installed package lists, resolve from the agent
|
|
76
|
+
* directory.
|
|
75
77
|
*/
|
|
76
78
|
export declare function loadStorageAdapter(module: string, context: StorageOpenContext, hostModules?: Readonly<Record<string, object>>): Promise<StorageAdapterModule>;
|
|
77
79
|
/** The adapter's options with every `secrets` reference resolved, as the provider passes them to its hooks. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/core/storage/provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/core/storage/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -41,12 +42,88 @@ export function storageSelectionKey(selection, agentDir) {
|
|
|
41
42
|
}
|
|
42
43
|
return JSON.stringify(selection);
|
|
43
44
|
}
|
|
45
|
+
/** Virtual module through which transformed adapter modules make their imports. */
|
|
46
|
+
const ADAPTER_IMPORTS = "atomic:storage-adapter-imports";
|
|
47
|
+
/**
|
|
48
|
+
* Appended to every module the adapter loader transforms. The hoisted declaration replaces the `jitiImport` that jiti
|
|
49
|
+
* passes each module, so the module's static and dynamic imports reach {@link createAdapterImports} with its own loader
|
|
50
|
+
* and the importing module's filename.
|
|
51
|
+
*/
|
|
52
|
+
const ADAPTER_IMPORT_HOOK = `\nfunction jitiImport(id, options) { return require(${JSON.stringify(ADAPTER_IMPORTS)}).import(require, id, options, __filename); }\n`;
|
|
53
|
+
/** Whether Node loads a file as ESM: jiti imports such files natively, outside the loader's host modules. */
|
|
54
|
+
function isNativeEsm(filename) {
|
|
55
|
+
if (filename.endsWith(".mjs"))
|
|
56
|
+
return true;
|
|
57
|
+
if (!filename.endsWith(".js"))
|
|
58
|
+
return false;
|
|
59
|
+
for (let directory = dirname(filename);; directory = dirname(directory)) {
|
|
60
|
+
const manifest = join(directory, "package.json");
|
|
61
|
+
if (existsSync(manifest)) {
|
|
62
|
+
const { type } = JSON.parse(readFileSync(manifest, "utf8"));
|
|
63
|
+
return type === "module";
|
|
64
|
+
}
|
|
65
|
+
if (directory === dirname(directory))
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Evaluates the ESM files an adapter module imports by path through the adapter loader, once per load, so their own
|
|
71
|
+
* imports get the host modules too. Package imports, such as an adapter's driver, load as jiti loads them. A module
|
|
72
|
+
* imported again waits for its evaluation, top-level `await` included, unless the importer is part of that evaluation:
|
|
73
|
+
* an import cycle gets the partly evaluated module, as it would natively. Other files imported by path load as jiti
|
|
74
|
+
* loads them, but still count as part of their importer's evaluation, so cycles through them are detected too.
|
|
75
|
+
* Filenames are jiti's resolved paths, the keys of its module cache.
|
|
76
|
+
*/
|
|
77
|
+
function createAdapterImports() {
|
|
78
|
+
const evaluations = new Map();
|
|
79
|
+
const awaiting = new Map();
|
|
80
|
+
const awaits = (importer, filename, seen = new Set()) => {
|
|
81
|
+
if (importer === filename)
|
|
82
|
+
return true;
|
|
83
|
+
if (seen.has(importer))
|
|
84
|
+
return false;
|
|
85
|
+
seen.add(importer);
|
|
86
|
+
return [...(awaiting.get(importer) ?? [])].some((next) => awaits(next, filename, seen));
|
|
87
|
+
};
|
|
88
|
+
const wait = async (importer, filename, load) => {
|
|
89
|
+
const pending = awaiting.get(importer) ?? new Set();
|
|
90
|
+
awaiting.set(importer, pending.add(filename));
|
|
91
|
+
try {
|
|
92
|
+
return await load();
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
pending.delete(filename);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
import(jiti, id, options, importer) {
|
|
100
|
+
const byPath = id.startsWith(".") || id.startsWith("file:") || isAbsolute(id);
|
|
101
|
+
const filename = byPath ? jiti.resolve(id) : undefined;
|
|
102
|
+
if (filename === undefined)
|
|
103
|
+
return jiti.import(id, options);
|
|
104
|
+
if (!isNativeEsm(filename))
|
|
105
|
+
return wait(importer, filename, () => jiti.import(id, options));
|
|
106
|
+
const evaluation = evaluations.get(filename);
|
|
107
|
+
if (evaluation === undefined) {
|
|
108
|
+
const source = readFileSync(filename, "utf8");
|
|
109
|
+
const started = Promise.resolve().then(() => jiti.evalModule(source, { filename, async: true, forceTranspile: true }));
|
|
110
|
+
evaluations.set(filename, started);
|
|
111
|
+
return wait(importer, filename, () => started);
|
|
112
|
+
}
|
|
113
|
+
if (awaits(filename, importer))
|
|
114
|
+
return jiti.import(id, options);
|
|
115
|
+
return wait(importer, filename, () => evaluation);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
44
119
|
/**
|
|
45
120
|
* Loads an adapter module the way the extension loader loads extensions: `@bastani/atomic/storage` (and
|
|
46
121
|
* `@bastani/atomic`) resolve to this host's own modules, so adapters need no installed copy of Atomic and share its
|
|
47
122
|
* error classes. `hostModules` adds live modules by specifier; run journals pass the running
|
|
48
|
-
* `@bastani/atomic/workflows`.
|
|
49
|
-
*
|
|
123
|
+
* `@bastani/atomic/workflows`. The ES module and TypeScript files the adapter imports by path get the same host
|
|
124
|
+
* modules; nested CommonJS files resolve them from `node_modules`. A package name selects an adapter listed by an
|
|
125
|
+
* installed Atomic package; other specifiers, and package names no installed package lists, resolve from the agent
|
|
126
|
+
* directory.
|
|
50
127
|
*/
|
|
51
128
|
export async function loadStorageAdapter(module, context, hostModules = {}) {
|
|
52
129
|
try {
|
|
@@ -55,9 +132,21 @@ export async function loadStorageAdapter(module, context, hostModules = {}) {
|
|
|
55
132
|
import("../extensions/loader-host-modules.js"),
|
|
56
133
|
import("../package-manager-storage-adapters.js"),
|
|
57
134
|
]);
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
{
|
|
135
|
+
const id = pathToFileURL(join(context.agentDir, "storage-adapter.js")).href;
|
|
136
|
+
const babel = await createHostModuleJiti(id, {});
|
|
137
|
+
const loader = await createHostModuleJiti(id, { ...(await getStorageAdapterHostModules()), ...hostModules, [ADAPTER_IMPORTS]: createAdapterImports() },
|
|
138
|
+
// JS adapters must also pass through virtual host modules, not native-import a second host copy. A load
|
|
139
|
+
// given extra host modules must not reuse a module another load evaluated without them: the cached
|
|
140
|
+
// module's imports stay bound to that first loader, so a .ts adapter serving several domains would miss
|
|
141
|
+
// them. Such loads evaluate afresh, as JS adapters always do. jiti's source cache would return transforms
|
|
142
|
+
// without the import hook, so only the Babel step uses it.
|
|
143
|
+
{
|
|
144
|
+
interopDefault: true,
|
|
145
|
+
tryNative: false,
|
|
146
|
+
fsCache: false,
|
|
147
|
+
moduleCache: Object.keys(hostModules).length === 0,
|
|
148
|
+
transform: (options) => ({ code: `${babel.transform(options)}${ADAPTER_IMPORT_HOOK}` }),
|
|
149
|
+
});
|
|
61
150
|
const specifier = (await resolvePackageStorageAdapter(module, context.agentDir)) ?? module;
|
|
62
151
|
const location = loader.esmResolve(specifier);
|
|
63
152
|
const filename = location.startsWith("file:") ? fileURLToPath(location) : location;
|