@bastani/atomic 0.9.48-alpha.1 → 0.9.49-alpha.1
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 +10 -0
- package/dist/builtin/intercom/CHANGELOG.md +7 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +69 -0
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +69 -0
- package/dist/builtin/workflows/src/index.js +69 -0
- package/dist/builtin/workflows/src/local-worker-entry.mjs +69 -0
- package/dist/core/storage/database.d.ts +11 -0
- package/dist/core/storage/database.d.ts.map +1 -1
- package/dist/core/storage/database.js.map +1 -1
- package/dist/core/storage/index.d.ts +1 -1
- package/dist/core/storage/index.d.ts.map +1 -1
- package/dist/core/storage/index.js.map +1 -1
- package/dist/core/storage/sqlite-facade.d.ts +6 -1
- package/dist/core/storage/sqlite-facade.d.ts.map +1 -1
- package/dist/core/storage/sqlite-facade.js +18 -0
- package/dist/core/storage/sqlite-facade.js.map +1 -1
- package/docs/storage.md +3 -0
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.49-alpha.1] - 2026-10-27
|
|
6
|
+
|
|
7
|
+
Faster workflow journals on remote databases.
|
|
8
|
+
|
|
9
|
+
- **One request per journal batch:** `SqliteDatabase.batch` sends several statements in one write transaction and one request, so workflow journals on a remote database save a network round trip per statement ([#4083](https://github.com/bastani-inc/atomic/issues/4083), [#4084](https://github.com/bastani-inc/atomic/pull/4084))
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `createSqliteDatabase` accepts an optional `batch` driver call that sends several statements in one write transaction and one request, exposed as `SqliteDatabase.batch`. Workflow journals use it to write a batch of events in one request, which saves a network round trip per statement on remote databases ([#4083](https://github.com/bastani-inc/atomic/issues/4083))
|
|
14
|
+
|
|
5
15
|
## [0.9.47] - 2026-10-27
|
|
6
16
|
|
|
7
17
|
Two fixes for model errors and MCP tool names.
|
|
@@ -4,6 +4,13 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.48] - 2026-10-27
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- A session restored after Atomic restarts now rejoins the Intercom groups it had joined, so it can still reach its restored subagents in those groups without joining again. Each `join` and `leave` is saved with the session, and a restored session rejoins exactly the groups its own last record lists before it first connects. A group it left before the restart is not rejoined, a forked session does not inherit the record, and a session restored under a different home group keeps only its home group. The same holds for a resumed workflow stage, in process or on a replacement local worker: it comes back in its invocation group or subgroup and in every group it joined, so the launcher reaches it by path and its teammates by name ([#4079](https://github.com/bastani-inc/atomic/issues/4079))
|
|
12
|
+
- A send to a session that is not in any of the sender's groups, but is live in a group the sender's read-only `intercom list` peek can show, now fails with `<name> is live in group <group>; join it to send` instead of `Session not found`. Workflow groups keep their own rules: a workflow stage never gets the hint, no sender is told to join a `workflow:` group, and a session visible only in a group the peek refuses still gets `Session not found` ([#4079](https://github.com/bastani-inc/atomic/issues/4079))
|
|
13
|
+
|
|
7
14
|
## [0.9.48-alpha.1] - 2026-10-27
|
|
8
15
|
|
|
9
16
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
|
|
6
6
|
"contributors": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -60,6 +60,12 @@ export declare class SqlRunJournal implements RunJournal {
|
|
|
60
60
|
* failure rejects the whole batch, with nothing written.
|
|
61
61
|
*/
|
|
62
62
|
appendMany(lease: Lease, appends: readonly JournalBatchAppend[]): Promise<readonly PromiseSettledResult<AppendOutcome>[]>;
|
|
63
|
+
/**
|
|
64
|
+
* `appendMany` as one `SqliteDatabase.batch` request, for a batch with no pool guards and no payload errors. Every
|
|
65
|
+
* write checks the lease, the key and the sequence limit in SQL, so the outcomes match the savepoint path: a stale
|
|
66
|
+
* lease writes nothing and rejects the batch, a known key reports `exists`, and each append settles alone, in order.
|
|
67
|
+
*/
|
|
68
|
+
private appendInOneRequest;
|
|
63
69
|
/** Validate an append outside any transaction; its payload error is raised where `append` always raised it. */
|
|
64
70
|
private prepare;
|
|
65
71
|
private insert;
|
|
@@ -9491,6 +9491,9 @@ class SqlRunJournal {
|
|
|
9491
9491
|
return error;
|
|
9492
9492
|
}
|
|
9493
9493
|
});
|
|
9494
|
+
const batch = this.database.batch?.bind(this.database);
|
|
9495
|
+
if (batch && prepared.every((append) => append instanceof Error || append.guard === undefined && typeof append.payload === "string"))
|
|
9496
|
+
return this.operation(() => this.appendInOneRequest(batch, owned, prepared));
|
|
9494
9497
|
return this.operation(() => this.database.transaction(async (tx) => {
|
|
9495
9498
|
await this.checkLease(tx, owned);
|
|
9496
9499
|
const results = [];
|
|
@@ -9511,6 +9514,72 @@ class SqlRunJournal {
|
|
|
9511
9514
|
return results;
|
|
9512
9515
|
}));
|
|
9513
9516
|
}
|
|
9517
|
+
async appendInOneRequest(batch, owned, prepared) {
|
|
9518
|
+
const t = this.tables;
|
|
9519
|
+
const holds = `EXISTS (SELECT 1 FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.holderId} = ? AND ${JOURNAL_COLUMNS.epoch} = ?)`;
|
|
9520
|
+
const held = [owned.runId, owned.holderId, owned.epoch];
|
|
9521
|
+
const latest = `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.seq} = (SELECT MAX(${JOURNAL_COLUMNS.seq}) FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?)`;
|
|
9522
|
+
const statements = [
|
|
9523
|
+
{ sql: `SELECT * FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ?`, params: [owned.runId] }
|
|
9524
|
+
];
|
|
9525
|
+
const at = (statement) => statements.push(statement) - 1;
|
|
9526
|
+
const plans = prepared.map((append) => {
|
|
9527
|
+
if (append instanceof Error)
|
|
9528
|
+
return append;
|
|
9529
|
+
const { key, type, payload, status } = append;
|
|
9530
|
+
const existing = key === undefined ? undefined : at({
|
|
9531
|
+
sql: `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?`,
|
|
9532
|
+
params: [owned.runId, key]
|
|
9533
|
+
});
|
|
9534
|
+
at({
|
|
9535
|
+
sql: `INSERT INTO ${t.events}
|
|
9536
|
+
SELECT ?, current.latest + 1, ?, ?, ?, ?, ${STORE_NOW}
|
|
9537
|
+
FROM (SELECT COALESCE(MAX(${JOURNAL_COLUMNS.seq}), 0) AS latest FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?) AS current
|
|
9538
|
+
WHERE current.latest < ? AND ${holds}${key === undefined ? "" : ` AND NOT EXISTS (SELECT 1 FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?)`}`,
|
|
9539
|
+
params: [
|
|
9540
|
+
owned.runId,
|
|
9541
|
+
owned.epoch,
|
|
9542
|
+
key ?? null,
|
|
9543
|
+
type,
|
|
9544
|
+
payload,
|
|
9545
|
+
owned.runId,
|
|
9546
|
+
Number.MAX_SAFE_INTEGER,
|
|
9547
|
+
...held,
|
|
9548
|
+
...key === undefined ? [] : [owned.runId, key]
|
|
9549
|
+
]
|
|
9550
|
+
});
|
|
9551
|
+
const inserted = at({ sql: "SELECT changes() AS inserted", params: [] });
|
|
9552
|
+
if (status !== undefined)
|
|
9553
|
+
at({
|
|
9554
|
+
sql: `UPDATE ${t.runs} SET ${JOURNAL_COLUMNS.status} = ? WHERE ${JOURNAL_COLUMNS.runId} = ? AND changes() = 1`,
|
|
9555
|
+
params: [status, owned.runId]
|
|
9556
|
+
});
|
|
9557
|
+
const row = at({ sql: latest, params: [owned.runId, owned.runId] });
|
|
9558
|
+
return { existing, inserted, row };
|
|
9559
|
+
});
|
|
9560
|
+
const rows = await batch(statements);
|
|
9561
|
+
const lease = rows[0][0];
|
|
9562
|
+
const epoch = lease === undefined ? undefined : journalCounter(owned.runId, "epoch", lease[JOURNAL_COLUMNS.epoch]);
|
|
9563
|
+
if (lease?.[JOURNAL_COLUMNS.holderId] !== owned.holderId || epoch !== owned.epoch)
|
|
9564
|
+
throw new StaleLeaseError(owned.runId, owned.epoch, epoch ?? JOURNAL_LEASE.absentEpoch);
|
|
9565
|
+
return plans.map((plan) => {
|
|
9566
|
+
if (plan instanceof Error)
|
|
9567
|
+
return { status: "rejected", reason: plan };
|
|
9568
|
+
try {
|
|
9569
|
+
const existing = plan.existing === undefined ? undefined : rows[plan.existing][0];
|
|
9570
|
+
if (existing)
|
|
9571
|
+
return { status: "fulfilled", value: { status: "exists", entry: entryFromRow(existing) } };
|
|
9572
|
+
const row = rows[plan.row][0];
|
|
9573
|
+
if (Number(rows[plan.inserted][0].inserted) === 1)
|
|
9574
|
+
return { status: "fulfilled", value: { status: "appended", entry: entryFromRow(row) } };
|
|
9575
|
+
const actual = journalCounter(owned.runId, "seq", row?.[JOURNAL_COLUMNS.seq] ?? 0);
|
|
9576
|
+
journalCounter(owned.runId, "seq", actual + 1, "overflow");
|
|
9577
|
+
throw new StorageUnavailableError2(this.descriptor, new Error("The batched append was not written."));
|
|
9578
|
+
} catch (error) {
|
|
9579
|
+
return { status: "rejected", reason: error };
|
|
9580
|
+
}
|
|
9581
|
+
});
|
|
9582
|
+
}
|
|
9514
9583
|
prepare(event, key, appendGuard) {
|
|
9515
9584
|
if (key !== undefined)
|
|
9516
9585
|
validateText("key", key);
|
|
@@ -3570,6 +3570,9 @@ class SqlRunJournal {
|
|
|
3570
3570
|
return error;
|
|
3571
3571
|
}
|
|
3572
3572
|
});
|
|
3573
|
+
const batch = this.database.batch?.bind(this.database);
|
|
3574
|
+
if (batch && prepared.every((append) => append instanceof Error || append.guard === undefined && typeof append.payload === "string"))
|
|
3575
|
+
return this.operation(() => this.appendInOneRequest(batch, owned, prepared));
|
|
3573
3576
|
return this.operation(() => this.database.transaction(async (tx) => {
|
|
3574
3577
|
await this.checkLease(tx, owned);
|
|
3575
3578
|
const results = [];
|
|
@@ -3590,6 +3593,72 @@ class SqlRunJournal {
|
|
|
3590
3593
|
return results;
|
|
3591
3594
|
}));
|
|
3592
3595
|
}
|
|
3596
|
+
async appendInOneRequest(batch, owned, prepared) {
|
|
3597
|
+
const t = this.tables;
|
|
3598
|
+
const holds = `EXISTS (SELECT 1 FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.holderId} = ? AND ${JOURNAL_COLUMNS.epoch} = ?)`;
|
|
3599
|
+
const held = [owned.runId, owned.holderId, owned.epoch];
|
|
3600
|
+
const latest = `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.seq} = (SELECT MAX(${JOURNAL_COLUMNS.seq}) FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?)`;
|
|
3601
|
+
const statements = [
|
|
3602
|
+
{ sql: `SELECT * FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ?`, params: [owned.runId] }
|
|
3603
|
+
];
|
|
3604
|
+
const at = (statement) => statements.push(statement) - 1;
|
|
3605
|
+
const plans = prepared.map((append) => {
|
|
3606
|
+
if (append instanceof Error)
|
|
3607
|
+
return append;
|
|
3608
|
+
const { key, type, payload, status } = append;
|
|
3609
|
+
const existing = key === undefined ? undefined : at({
|
|
3610
|
+
sql: `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?`,
|
|
3611
|
+
params: [owned.runId, key]
|
|
3612
|
+
});
|
|
3613
|
+
at({
|
|
3614
|
+
sql: `INSERT INTO ${t.events}
|
|
3615
|
+
SELECT ?, current.latest + 1, ?, ?, ?, ?, ${STORE_NOW}
|
|
3616
|
+
FROM (SELECT COALESCE(MAX(${JOURNAL_COLUMNS.seq}), 0) AS latest FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?) AS current
|
|
3617
|
+
WHERE current.latest < ? AND ${holds}${key === undefined ? "" : ` AND NOT EXISTS (SELECT 1 FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?)`}`,
|
|
3618
|
+
params: [
|
|
3619
|
+
owned.runId,
|
|
3620
|
+
owned.epoch,
|
|
3621
|
+
key ?? null,
|
|
3622
|
+
type,
|
|
3623
|
+
payload,
|
|
3624
|
+
owned.runId,
|
|
3625
|
+
Number.MAX_SAFE_INTEGER,
|
|
3626
|
+
...held,
|
|
3627
|
+
...key === undefined ? [] : [owned.runId, key]
|
|
3628
|
+
]
|
|
3629
|
+
});
|
|
3630
|
+
const inserted = at({ sql: "SELECT changes() AS inserted", params: [] });
|
|
3631
|
+
if (status !== undefined)
|
|
3632
|
+
at({
|
|
3633
|
+
sql: `UPDATE ${t.runs} SET ${JOURNAL_COLUMNS.status} = ? WHERE ${JOURNAL_COLUMNS.runId} = ? AND changes() = 1`,
|
|
3634
|
+
params: [status, owned.runId]
|
|
3635
|
+
});
|
|
3636
|
+
const row = at({ sql: latest, params: [owned.runId, owned.runId] });
|
|
3637
|
+
return { existing, inserted, row };
|
|
3638
|
+
});
|
|
3639
|
+
const rows = await batch(statements);
|
|
3640
|
+
const lease = rows[0][0];
|
|
3641
|
+
const epoch = lease === undefined ? undefined : journalCounter(owned.runId, "epoch", lease[JOURNAL_COLUMNS.epoch]);
|
|
3642
|
+
if (lease?.[JOURNAL_COLUMNS.holderId] !== owned.holderId || epoch !== owned.epoch)
|
|
3643
|
+
throw new StaleLeaseError(owned.runId, owned.epoch, epoch ?? JOURNAL_LEASE.absentEpoch);
|
|
3644
|
+
return plans.map((plan) => {
|
|
3645
|
+
if (plan instanceof Error)
|
|
3646
|
+
return { status: "rejected", reason: plan };
|
|
3647
|
+
try {
|
|
3648
|
+
const existing = plan.existing === undefined ? undefined : rows[plan.existing][0];
|
|
3649
|
+
if (existing)
|
|
3650
|
+
return { status: "fulfilled", value: { status: "exists", entry: entryFromRow(existing) } };
|
|
3651
|
+
const row = rows[plan.row][0];
|
|
3652
|
+
if (Number(rows[plan.inserted][0].inserted) === 1)
|
|
3653
|
+
return { status: "fulfilled", value: { status: "appended", entry: entryFromRow(row) } };
|
|
3654
|
+
const actual = journalCounter(owned.runId, "seq", row?.[JOURNAL_COLUMNS.seq] ?? 0);
|
|
3655
|
+
journalCounter(owned.runId, "seq", actual + 1, "overflow");
|
|
3656
|
+
throw new StorageUnavailableError2(this.descriptor, new Error("The batched append was not written."));
|
|
3657
|
+
} catch (error) {
|
|
3658
|
+
return { status: "rejected", reason: error };
|
|
3659
|
+
}
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3593
3662
|
prepare(event, key, appendGuard) {
|
|
3594
3663
|
if (key !== undefined)
|
|
3595
3664
|
validateText("key", key);
|
|
@@ -1742,6 +1742,9 @@ class SqlRunJournal {
|
|
|
1742
1742
|
return error;
|
|
1743
1743
|
}
|
|
1744
1744
|
});
|
|
1745
|
+
const batch = this.database.batch?.bind(this.database);
|
|
1746
|
+
if (batch && prepared.every((append) => append instanceof Error || append.guard === undefined && typeof append.payload === "string"))
|
|
1747
|
+
return this.operation(() => this.appendInOneRequest(batch, owned, prepared));
|
|
1745
1748
|
return this.operation(() => this.database.transaction(async (tx) => {
|
|
1746
1749
|
await this.checkLease(tx, owned);
|
|
1747
1750
|
const results = [];
|
|
@@ -1762,6 +1765,72 @@ class SqlRunJournal {
|
|
|
1762
1765
|
return results;
|
|
1763
1766
|
}));
|
|
1764
1767
|
}
|
|
1768
|
+
async appendInOneRequest(batch, owned, prepared) {
|
|
1769
|
+
const t = this.tables;
|
|
1770
|
+
const holds = `EXISTS (SELECT 1 FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.holderId} = ? AND ${JOURNAL_COLUMNS.epoch} = ?)`;
|
|
1771
|
+
const held = [owned.runId, owned.holderId, owned.epoch];
|
|
1772
|
+
const latest = `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.seq} = (SELECT MAX(${JOURNAL_COLUMNS.seq}) FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?)`;
|
|
1773
|
+
const statements = [
|
|
1774
|
+
{ sql: `SELECT * FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ?`, params: [owned.runId] }
|
|
1775
|
+
];
|
|
1776
|
+
const at = (statement) => statements.push(statement) - 1;
|
|
1777
|
+
const plans = prepared.map((append) => {
|
|
1778
|
+
if (append instanceof Error)
|
|
1779
|
+
return append;
|
|
1780
|
+
const { key, type, payload, status } = append;
|
|
1781
|
+
const existing = key === undefined ? undefined : at({
|
|
1782
|
+
sql: `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?`,
|
|
1783
|
+
params: [owned.runId, key]
|
|
1784
|
+
});
|
|
1785
|
+
at({
|
|
1786
|
+
sql: `INSERT INTO ${t.events}
|
|
1787
|
+
SELECT ?, current.latest + 1, ?, ?, ?, ?, ${STORE_NOW}
|
|
1788
|
+
FROM (SELECT COALESCE(MAX(${JOURNAL_COLUMNS.seq}), 0) AS latest FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?) AS current
|
|
1789
|
+
WHERE current.latest < ? AND ${holds}${key === undefined ? "" : ` AND NOT EXISTS (SELECT 1 FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?)`}`,
|
|
1790
|
+
params: [
|
|
1791
|
+
owned.runId,
|
|
1792
|
+
owned.epoch,
|
|
1793
|
+
key ?? null,
|
|
1794
|
+
type,
|
|
1795
|
+
payload,
|
|
1796
|
+
owned.runId,
|
|
1797
|
+
Number.MAX_SAFE_INTEGER,
|
|
1798
|
+
...held,
|
|
1799
|
+
...key === undefined ? [] : [owned.runId, key]
|
|
1800
|
+
]
|
|
1801
|
+
});
|
|
1802
|
+
const inserted = at({ sql: "SELECT changes() AS inserted", params: [] });
|
|
1803
|
+
if (status !== undefined)
|
|
1804
|
+
at({
|
|
1805
|
+
sql: `UPDATE ${t.runs} SET ${JOURNAL_COLUMNS.status} = ? WHERE ${JOURNAL_COLUMNS.runId} = ? AND changes() = 1`,
|
|
1806
|
+
params: [status, owned.runId]
|
|
1807
|
+
});
|
|
1808
|
+
const row = at({ sql: latest, params: [owned.runId, owned.runId] });
|
|
1809
|
+
return { existing, inserted, row };
|
|
1810
|
+
});
|
|
1811
|
+
const rows = await batch(statements);
|
|
1812
|
+
const lease = rows[0][0];
|
|
1813
|
+
const epoch = lease === undefined ? undefined : journalCounter(owned.runId, "epoch", lease[JOURNAL_COLUMNS.epoch]);
|
|
1814
|
+
if (lease?.[JOURNAL_COLUMNS.holderId] !== owned.holderId || epoch !== owned.epoch)
|
|
1815
|
+
throw new StaleLeaseError(owned.runId, owned.epoch, epoch ?? JOURNAL_LEASE.absentEpoch);
|
|
1816
|
+
return plans.map((plan) => {
|
|
1817
|
+
if (plan instanceof Error)
|
|
1818
|
+
return { status: "rejected", reason: plan };
|
|
1819
|
+
try {
|
|
1820
|
+
const existing = plan.existing === undefined ? undefined : rows[plan.existing][0];
|
|
1821
|
+
if (existing)
|
|
1822
|
+
return { status: "fulfilled", value: { status: "exists", entry: entryFromRow(existing) } };
|
|
1823
|
+
const row = rows[plan.row][0];
|
|
1824
|
+
if (Number(rows[plan.inserted][0].inserted) === 1)
|
|
1825
|
+
return { status: "fulfilled", value: { status: "appended", entry: entryFromRow(row) } };
|
|
1826
|
+
const actual = journalCounter(owned.runId, "seq", row?.[JOURNAL_COLUMNS.seq] ?? 0);
|
|
1827
|
+
journalCounter(owned.runId, "seq", actual + 1, "overflow");
|
|
1828
|
+
throw new StorageUnavailableError2(this.descriptor, new Error("The batched append was not written."));
|
|
1829
|
+
} catch (error) {
|
|
1830
|
+
return { status: "rejected", reason: error };
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1765
1834
|
prepare(event, key, appendGuard) {
|
|
1766
1835
|
if (key !== undefined)
|
|
1767
1836
|
validateText("key", key);
|
|
@@ -3570,6 +3570,9 @@ class SqlRunJournal {
|
|
|
3570
3570
|
return error;
|
|
3571
3571
|
}
|
|
3572
3572
|
});
|
|
3573
|
+
const batch = this.database.batch?.bind(this.database);
|
|
3574
|
+
if (batch && prepared.every((append) => append instanceof Error || append.guard === undefined && typeof append.payload === "string"))
|
|
3575
|
+
return this.operation(() => this.appendInOneRequest(batch, owned, prepared));
|
|
3573
3576
|
return this.operation(() => this.database.transaction(async (tx) => {
|
|
3574
3577
|
await this.checkLease(tx, owned);
|
|
3575
3578
|
const results = [];
|
|
@@ -3590,6 +3593,72 @@ class SqlRunJournal {
|
|
|
3590
3593
|
return results;
|
|
3591
3594
|
}));
|
|
3592
3595
|
}
|
|
3596
|
+
async appendInOneRequest(batch, owned, prepared) {
|
|
3597
|
+
const t = this.tables;
|
|
3598
|
+
const holds = `EXISTS (SELECT 1 FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.holderId} = ? AND ${JOURNAL_COLUMNS.epoch} = ?)`;
|
|
3599
|
+
const held = [owned.runId, owned.holderId, owned.epoch];
|
|
3600
|
+
const latest = `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.seq} = (SELECT MAX(${JOURNAL_COLUMNS.seq}) FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?)`;
|
|
3601
|
+
const statements = [
|
|
3602
|
+
{ sql: `SELECT * FROM ${t.leases} WHERE ${JOURNAL_COLUMNS.runId} = ?`, params: [owned.runId] }
|
|
3603
|
+
];
|
|
3604
|
+
const at = (statement) => statements.push(statement) - 1;
|
|
3605
|
+
const plans = prepared.map((append) => {
|
|
3606
|
+
if (append instanceof Error)
|
|
3607
|
+
return append;
|
|
3608
|
+
const { key, type, payload, status } = append;
|
|
3609
|
+
const existing = key === undefined ? undefined : at({
|
|
3610
|
+
sql: `SELECT * FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?`,
|
|
3611
|
+
params: [owned.runId, key]
|
|
3612
|
+
});
|
|
3613
|
+
at({
|
|
3614
|
+
sql: `INSERT INTO ${t.events}
|
|
3615
|
+
SELECT ?, current.latest + 1, ?, ?, ?, ?, ${STORE_NOW}
|
|
3616
|
+
FROM (SELECT COALESCE(MAX(${JOURNAL_COLUMNS.seq}), 0) AS latest FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ?) AS current
|
|
3617
|
+
WHERE current.latest < ? AND ${holds}${key === undefined ? "" : ` AND NOT EXISTS (SELECT 1 FROM ${t.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.key} = ?)`}`,
|
|
3618
|
+
params: [
|
|
3619
|
+
owned.runId,
|
|
3620
|
+
owned.epoch,
|
|
3621
|
+
key ?? null,
|
|
3622
|
+
type,
|
|
3623
|
+
payload,
|
|
3624
|
+
owned.runId,
|
|
3625
|
+
Number.MAX_SAFE_INTEGER,
|
|
3626
|
+
...held,
|
|
3627
|
+
...key === undefined ? [] : [owned.runId, key]
|
|
3628
|
+
]
|
|
3629
|
+
});
|
|
3630
|
+
const inserted = at({ sql: "SELECT changes() AS inserted", params: [] });
|
|
3631
|
+
if (status !== undefined)
|
|
3632
|
+
at({
|
|
3633
|
+
sql: `UPDATE ${t.runs} SET ${JOURNAL_COLUMNS.status} = ? WHERE ${JOURNAL_COLUMNS.runId} = ? AND changes() = 1`,
|
|
3634
|
+
params: [status, owned.runId]
|
|
3635
|
+
});
|
|
3636
|
+
const row = at({ sql: latest, params: [owned.runId, owned.runId] });
|
|
3637
|
+
return { existing, inserted, row };
|
|
3638
|
+
});
|
|
3639
|
+
const rows = await batch(statements);
|
|
3640
|
+
const lease = rows[0][0];
|
|
3641
|
+
const epoch = lease === undefined ? undefined : journalCounter(owned.runId, "epoch", lease[JOURNAL_COLUMNS.epoch]);
|
|
3642
|
+
if (lease?.[JOURNAL_COLUMNS.holderId] !== owned.holderId || epoch !== owned.epoch)
|
|
3643
|
+
throw new StaleLeaseError(owned.runId, owned.epoch, epoch ?? JOURNAL_LEASE.absentEpoch);
|
|
3644
|
+
return plans.map((plan) => {
|
|
3645
|
+
if (plan instanceof Error)
|
|
3646
|
+
return { status: "rejected", reason: plan };
|
|
3647
|
+
try {
|
|
3648
|
+
const existing = plan.existing === undefined ? undefined : rows[plan.existing][0];
|
|
3649
|
+
if (existing)
|
|
3650
|
+
return { status: "fulfilled", value: { status: "exists", entry: entryFromRow(existing) } };
|
|
3651
|
+
const row = rows[plan.row][0];
|
|
3652
|
+
if (Number(rows[plan.inserted][0].inserted) === 1)
|
|
3653
|
+
return { status: "fulfilled", value: { status: "appended", entry: entryFromRow(row) } };
|
|
3654
|
+
const actual = journalCounter(owned.runId, "seq", row?.[JOURNAL_COLUMNS.seq] ?? 0);
|
|
3655
|
+
journalCounter(owned.runId, "seq", actual + 1, "overflow");
|
|
3656
|
+
throw new StorageUnavailableError2(this.descriptor, new Error("The batched append was not written."));
|
|
3657
|
+
} catch (error) {
|
|
3658
|
+
return { status: "rejected", reason: error };
|
|
3659
|
+
}
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3593
3662
|
prepare(event, key, appendGuard) {
|
|
3594
3663
|
if (key !== undefined)
|
|
3595
3664
|
validateText("key", key);
|
|
@@ -13,9 +13,20 @@ export interface StorageDescriptor {
|
|
|
13
13
|
readonly adapter: string;
|
|
14
14
|
readonly location: string;
|
|
15
15
|
}
|
|
16
|
+
/** One statement of a batch: SQL with positional `?` parameters. */
|
|
17
|
+
export interface SqliteStatement {
|
|
18
|
+
readonly sql: string;
|
|
19
|
+
readonly params: readonly SqliteValue[];
|
|
20
|
+
}
|
|
16
21
|
export interface SqliteDatabase extends SqliteExecutor {
|
|
17
22
|
readonly descriptor: StorageDescriptor;
|
|
18
23
|
transaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Runs the statements in order, in one write transaction, as one call to the database: all of them commit or none
|
|
26
|
+
* do. Resolves with each statement's rows. Present only when the driver can send a batch in one request, which
|
|
27
|
+
* saves a round trip per statement against a remote database.
|
|
28
|
+
*/
|
|
29
|
+
batch?(statements: readonly SqliteStatement[]): Promise<SqliteRow[][]>;
|
|
19
30
|
close(): Promise<void>;
|
|
20
31
|
}
|
|
21
32
|
//# sourceMappingURL=database.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/core/storage/database.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9E,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACjG,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACvF;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;IACrD,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/core/storage/database.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9E,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACjG,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACvF;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;IACrD,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClF;;;;OAIG;IACH,KAAK,CAAC,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/core/storage/database.ts"],"names":[],"mappings":"","sourcesContent":["export type SqliteValue = null | number | bigint | string | Uint8Array;\nexport type SqliteRow = Readonly<Record<string, SqliteValue>>;\n\nexport interface SqliteRunResult {\n\treadonly changes: number;\n}\n\nexport interface SqliteExecutor {\n\texec(sql: string): Promise<void>;\n\trun(sql: string, ...params: readonly SqliteValue[]): Promise<SqliteRunResult>;\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined>;\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]>;\n}\n\nexport interface StorageDescriptor {\n\treadonly adapter: string;\n\treadonly location: string;\n}\n\nexport interface SqliteDatabase extends SqliteExecutor {\n\treadonly descriptor: StorageDescriptor;\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T>;\n\tclose(): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/core/storage/database.ts"],"names":[],"mappings":"","sourcesContent":["export type SqliteValue = null | number | bigint | string | Uint8Array;\nexport type SqliteRow = Readonly<Record<string, SqliteValue>>;\n\nexport interface SqliteRunResult {\n\treadonly changes: number;\n}\n\nexport interface SqliteExecutor {\n\texec(sql: string): Promise<void>;\n\trun(sql: string, ...params: readonly SqliteValue[]): Promise<SqliteRunResult>;\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined>;\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]>;\n}\n\nexport interface StorageDescriptor {\n\treadonly adapter: string;\n\treadonly location: string;\n}\n\n/** One statement of a batch: SQL with positional `?` parameters. */\nexport interface SqliteStatement {\n\treadonly sql: string;\n\treadonly params: readonly SqliteValue[];\n}\n\nexport interface SqliteDatabase extends SqliteExecutor {\n\treadonly descriptor: StorageDescriptor;\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T>;\n\t/**\n\t * Runs the statements in order, in one write transaction, as one call to the database: all of them commit or none\n\t * do. Resolves with each statement's rows. Present only when the driver can send a batch in one request, which\n\t * saves a round trip per statement against a remote database.\n\t */\n\tbatch?(statements: readonly SqliteStatement[]): Promise<SqliteRow[][]>;\n\tclose(): Promise<void>;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { SqliteDatabase, SqliteExecutor, SqliteRow, SqliteRunResult, SqliteValue, StorageDescriptor, } from "./database.js";
|
|
1
|
+
export type { SqliteDatabase, SqliteExecutor, SqliteRow, SqliteRunResult, SqliteStatement, SqliteValue, StorageDescriptor, } from "./database.js";
|
|
2
2
|
export * from "./errors.js";
|
|
3
3
|
export { openNodeSqliteDatabase, wrapNodeSqliteDatabase } from "./node-sqlite.js";
|
|
4
4
|
export { renderStorageIdentifiers, validateStoragePrefix } from "./prefix.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,cAAc,EACd,cAAc,EACd,SAAS,EACT,eAAe,EACf,WAAW,EACX,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,cAAc,gBAAgB,CAAC;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/storage/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,cAAc,EACd,cAAc,EACd,SAAS,EACT,eAAe,EACf,eAAe,EACf,WAAW,EACX,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,cAAc,gBAAgB,CAAC;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,cAAc,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/storage/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/storage/index.ts"],"names":[],"mappings":"AASA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,cAAc,gBAAgB,CAAC;AAE/B,cAAc,oBAAoB,CAAC","sourcesContent":["export type {\n\tSqliteDatabase,\n\tSqliteExecutor,\n\tSqliteRow,\n\tSqliteRunResult,\n\tSqliteStatement,\n\tSqliteValue,\n\tStorageDescriptor,\n} from \"./database.js\";\nexport * from \"./errors.js\";\nexport { openNodeSqliteDatabase, wrapNodeSqliteDatabase } from \"./node-sqlite.js\";\nexport { renderStorageIdentifiers, validateStoragePrefix } from \"./prefix.js\";\nexport * from \"./provider.js\";\nexport * from \"./run-journal.js\";\nexport { assertStorageSchemaVersion } from \"./schema.js\";\nexport * from \"./selection.js\";\nexport type { SessionStore } from \"./session/types.js\";\nexport * from \"./sqlite-facade.js\";\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SqliteDatabase, SqliteValue, StorageDescriptor } from "./database.js";
|
|
1
|
+
import type { SqliteDatabase, SqliteStatement, SqliteValue, StorageDescriptor } from "./database.js";
|
|
2
2
|
type Awaitable<T> = T | Promise<T>;
|
|
3
3
|
/** A value as a driver returns it. Blobs may be any binary view; the facade returns them as `Uint8Array` copies. */
|
|
4
4
|
export type SqliteDriverValue = SqliteValue | ArrayBuffer | ArrayBufferView;
|
|
@@ -27,6 +27,11 @@ export interface SqliteDriver extends SqliteDriverExecutor {
|
|
|
27
27
|
readonly descriptor: StorageDescriptor;
|
|
28
28
|
/** Begins a write transaction that holds the database's write lock, like `BEGIN IMMEDIATE`. */
|
|
29
29
|
beginTransaction(): Awaitable<SqliteDriverTransaction>;
|
|
30
|
+
/**
|
|
31
|
+
* Optional. Runs the statements in order in one write transaction, in one request: all commit or none do. Provide it
|
|
32
|
+
* only when the driver sends the whole batch at once; the facade then offers `SqliteDatabase.batch`.
|
|
33
|
+
*/
|
|
34
|
+
batch?(statements: readonly SqliteStatement[]): Awaitable<readonly SqliteDriverResult[]>;
|
|
30
35
|
/** Releases the connection. Called once, after accepted work drains. */
|
|
31
36
|
close(): Awaitable<void>;
|
|
32
37
|
/** Removes credentials from diagnostic text: the descriptor location and driver failure messages and stacks. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-facade.d.ts","sourceRoot":"","sources":["../../../src/core/storage/sqlite-facade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sqlite-facade.d.ts","sourceRoot":"","sources":["../../../src/core/storage/sqlite-facade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,cAAc,EAGd,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,MAAM,eAAe,CAAC;AAWvB,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEnC,oHAAoH;AACpH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,WAAW,GAAG,eAAe,CAAC;AAE5E,6GAA6G;AAC7G,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,wEAAwE;AACxE,MAAM,WAAW,oBAAoB;IACpC,yDAAyD;IACzD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAC;IACpF,4DAA4D;IAC5D,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACpE,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,+DAA+D;IAC/D,KAAK,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAa,SAAQ,oBAAoB;IACzD,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,+FAA+F;IAC/F,gBAAgB,IAAI,SAAS,CAAC,uBAAuB,CAAC,CAAC;IACvD;;;OAGG;IACH,KAAK,CAAC,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IACzF,wEAAwE;IACxE,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,gHAAgH;IAChH,MAAM,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAajF;AAwLD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAEzE"}
|
|
@@ -71,6 +71,7 @@ class DriverDatabase {
|
|
|
71
71
|
queue = new CallQueue();
|
|
72
72
|
closePromise;
|
|
73
73
|
executor;
|
|
74
|
+
batch;
|
|
74
75
|
constructor(driver, redact) {
|
|
75
76
|
this.driver = driver;
|
|
76
77
|
this.redact = redact;
|
|
@@ -80,6 +81,23 @@ class DriverDatabase {
|
|
|
80
81
|
return Promise.reject(new StoreClosedError(this.descriptor));
|
|
81
82
|
return this.queue.push(operation);
|
|
82
83
|
});
|
|
84
|
+
const batch = driver.batch?.bind(driver);
|
|
85
|
+
if (batch)
|
|
86
|
+
this.batch = (statements) => this.runBatch(batch, statements);
|
|
87
|
+
}
|
|
88
|
+
runBatch(batch, statements) {
|
|
89
|
+
if (this.closePromise)
|
|
90
|
+
return Promise.reject(new StoreClosedError(this.descriptor));
|
|
91
|
+
const bound = statements.map((statement) => ({ sql: statement.sql, params: snapshotParams(statement.params) }));
|
|
92
|
+
return this.queue.push(async () => {
|
|
93
|
+
for (const statement of bound) {
|
|
94
|
+
const invalidIndex = statement.params.findIndex((value) => typeof value === "string" && value.includes("\0"));
|
|
95
|
+
if (invalidIndex !== -1)
|
|
96
|
+
throw new StorageInvalidTextError(invalidIndex);
|
|
97
|
+
}
|
|
98
|
+
const results = await this.call(() => batch(bound));
|
|
99
|
+
return results.map((result) => result.rows.map((row) => normalizeRow(row, result.columns)));
|
|
100
|
+
});
|
|
83
101
|
}
|
|
84
102
|
/** Maps a driver failure to `StorageUnavailableError` with a credential-free cause. */
|
|
85
103
|
async call(operation) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-facade.js","sourceRoot":"","sources":["../../../src/core/storage/sqlite-facade.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SqliteDatabase, SqliteExecutor, SqliteRow, SqliteValue, StorageDescriptor } from \"./database.js\";\nimport {\n\tStorageError,\n\ttype StorageFailureCause,\n\tStorageInvalidTextError,\n\tStorageRollbackError,\n\tStorageTransactionClosedError,\n\tStorageUnavailableError,\n\tStoreClosedError,\n} from \"./errors.js\";\n\ntype Awaitable<T> = T | Promise<T>;\n\n/** A value as a driver returns it. Blobs may be any binary view; the facade returns them as `Uint8Array` copies. */\nexport type SqliteDriverValue = SqliteValue | ArrayBuffer | ArrayBufferView;\n\n/** One statement's result as a driver returns it: column names, positional rows, and the rows it changed. */\nexport interface SqliteDriverResult {\n\treadonly columns: readonly string[];\n\treadonly rows: readonly ArrayLike<SqliteDriverValue>[];\n\treadonly changes: number;\n}\n\n/** Runs SQL on a driver connection or on an open driver transaction. */\nexport interface SqliteDriverExecutor {\n\t/** Runs one statement with positional `?` parameters. */\n\texecute(sql: string, params: readonly SqliteValue[]): Awaitable<SqliteDriverResult>;\n\t/** Runs zero or more statements that take no parameters. */\n\texecuteMultiple(sql: string): Awaitable<void>;\n}\n\nexport interface SqliteDriverTransaction extends SqliteDriverExecutor {\n\tcommit(): Awaitable<void>;\n\trollback(): Awaitable<void>;\n\t/** Releases the transaction after it commits or rolls back. */\n\tclose?(): Awaitable<void>;\n}\n\n/** The driver calls `createSqliteDatabase` turns into a `SqliteDatabase`. */\nexport interface SqliteDriver extends SqliteDriverExecutor {\n\t/** Diagnostic identity. Its `location` passes through `redact` before the facade exposes it. */\n\treadonly descriptor: StorageDescriptor;\n\t/** Begins a write transaction that holds the database's write lock, like `BEGIN IMMEDIATE`. */\n\tbeginTransaction(): Awaitable<SqliteDriverTransaction>;\n\t/** Releases the connection. Called once, after accepted work drains. */\n\tclose(): Awaitable<void>;\n\t/** Removes credentials from diagnostic text: the descriptor location and driver failure messages and stacks. */\n\tredact?(text: string): string;\n}\n\n/**\n * A redactor that replaces every non-empty secret, and its URI-encoded and URI-decoded forms, with `[redacted]`.\n * Longer secrets are replaced first, so a secret that contains another is removed whole.\n */\nexport function redactSecrets(secrets: Iterable<string>): (text: string) => string {\n\tconst variants = new Set<string>();\n\tfor (const secret of secrets) {\n\t\tvariants.add(secret);\n\t\ttry {\n\t\t\tvariants.add(encodeURIComponent(secret));\n\t\t} catch {}\n\t\ttry {\n\t\t\tvariants.add(decodeURIComponent(secret));\n\t\t} catch {}\n\t}\n\tconst ordered = [...variants].filter(Boolean).sort((first, second) => second.length - first.length);\n\treturn (text) => ordered.reduce((value, secret) => value.replaceAll(secret, \"[redacted]\"), text);\n}\n\nfunction redactCause(cause: StorageFailureCause, redact: (text: string) => string): StorageFailureCause {\n\tif (typeof cause === \"string\") return redact(cause);\n\tif (!(cause instanceof Error)) return cause;\n\tconst nested = cause.cause as StorageFailureCause;\n\tconst safeCause = redactCause(nested, redact);\n\tconst message = redact(cause.message);\n\tconst stack = cause.stack === undefined ? undefined : redact(cause.stack);\n\tif (message === cause.message && stack === cause.stack && safeCause === nested) return cause;\n\tconst safe = new StorageError(message, { cause: safeCause });\n\tsafe.stack = stack;\n\treturn safe;\n}\n\nfunction snapshotParams(params: readonly SqliteValue[]): SqliteValue[] {\n\treturn params.map((value) => (value instanceof Uint8Array ? new Uint8Array(value) : value));\n}\n\nfunction normalizeValue(value: SqliteDriverValue): SqliteValue {\n\tif (typeof value === \"bigint\") {\n\t\treturn value >= -BigInt(Number.MAX_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER)\n\t\t\t? Number(value)\n\t\t\t: value;\n\t}\n\tif (value instanceof ArrayBuffer) return new Uint8Array(value.slice(0));\n\tif (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength).slice();\n\treturn value;\n}\n\nfunction normalizeRow(row: ArrayLike<SqliteDriverValue>, columns: readonly string[]): SqliteRow {\n\treturn Object.fromEntries(columns.map((column, index) => [column, normalizeValue(row[index] ?? null)]));\n}\n\n/** Serializes operations in call order; a failed operation does not stop the ones queued after it. */\nclass CallQueue {\n\tprivate tail: Promise<void> = Promise.resolve();\n\n\tpush<T>(operation: () => Promise<T>): Promise<T> {\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\tdrained(): Promise<void> {\n\t\treturn this.tail;\n\t}\n}\n\nclass DriverDatabase implements SqliteDatabase {\n\treadonly descriptor: StorageDescriptor;\n\tprivate readonly driver: SqliteDriver;\n\tprivate readonly redact: (text: string) => string;\n\tprivate readonly queue = new CallQueue();\n\tprivate closePromise?: Promise<void>;\n\tprivate readonly executor: SqliteExecutor;\n\n\tconstructor(driver: SqliteDriver, redact: (text: string) => string) {\n\t\tthis.driver = driver;\n\t\tthis.redact = redact;\n\t\tthis.descriptor = { adapter: driver.descriptor.adapter, location: redact(driver.descriptor.location) };\n\t\tthis.executor = this.createExecutor(driver, (operation) => {\n\t\t\tif (this.closePromise) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\t\treturn this.queue.push(operation);\n\t\t});\n\t}\n\n\t/** Maps a driver failure to `StorageUnavailableError` with a credential-free cause. */\n\tprivate async call<T>(operation: () => Awaitable<T>): Promise<T> {\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} catch (cause) {\n\t\t\tthrow new StorageUnavailableError(this.descriptor, redactCause(cause as StorageFailureCause, this.redact));\n\t\t}\n\t}\n\n\tprivate createExecutor(\n\t\tconnection: SqliteDriverExecutor,\n\t\tadmit: <T>(operation: () => Promise<T>) => Promise<T>,\n\t): SqliteExecutor {\n\t\tconst statement = (sql: string, params: readonly SqliteValue[]) => {\n\t\t\tconst bound = snapshotParams(params);\n\t\t\treturn admit(async () => {\n\t\t\t\tconst invalidIndex = bound.findIndex((value) => typeof value === \"string\" && value.includes(\"\\0\"));\n\t\t\t\tif (invalidIndex !== -1) throw new StorageInvalidTextError(invalidIndex);\n\t\t\t\treturn this.call(() => connection.execute(sql, bound));\n\t\t\t});\n\t\t};\n\t\treturn {\n\t\t\texec: (sql) => admit(() => this.call(() => connection.executeMultiple(sql))),\n\t\t\trun: async (sql, ...params) => ({ changes: (await statement(sql, params)).changes }),\n\t\t\tget: async <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) => {\n\t\t\t\tconst result = await statement(sql, params);\n\t\t\t\tconst row = result.rows[0];\n\t\t\t\treturn row === undefined ? undefined : (normalizeRow(row, result.columns) as T);\n\t\t\t},\n\t\t\tall: async <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) => {\n\t\t\t\tconst result = await statement(sql, params);\n\t\t\t\treturn result.rows.map((row) => normalizeRow(row, result.columns) as T);\n\t\t\t},\n\t\t};\n\t}\n\n\texec(sql: string): Promise<void> {\n\t\treturn this.executor.exec(sql);\n\t}\n\n\trun(sql: string, ...params: readonly SqliteValue[]) {\n\t\treturn this.executor.run(sql, ...params);\n\t}\n\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined> {\n\t\treturn this.executor.get<T>(sql, ...params);\n\t}\n\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]> {\n\t\treturn this.executor.all<T>(sql, ...params);\n\t}\n\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T> {\n\t\tif (this.closePromise) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\treturn this.queue.push(async () => {\n\t\t\tconst connection = await this.call(() => this.driver.beginTransaction());\n\t\t\tconst handleQueue = new CallQueue();\n\t\t\tlet active = true;\n\t\t\tlet result: T;\n\t\t\tconst handle = this.createExecutor(connection, (operation) =>\n\t\t\t\tactive ? handleQueue.push(operation) : Promise.reject(new StorageTransactionClosedError()),\n\t\t\t);\n\t\t\tconst close = () => this.call(() => connection.close?.());\n\t\t\ttry {\n\t\t\t\ttry {\n\t\t\t\t\tresult = await callback(handle);\n\t\t\t\t} finally {\n\t\t\t\t\tactive = false;\n\t\t\t\t\tawait handleQueue.drained();\n\t\t\t\t}\n\t\t\t\tawait this.call(() => connection.commit());\n\t\t\t} catch (cause) {\n\t\t\t\tlet failure = cause as StorageFailureCause;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.call(() => connection.rollback());\n\t\t\t\t} catch (rollbackCause) {\n\t\t\t\t\tfailure = new StorageRollbackError(failure, rollbackCause as StorageFailureCause);\n\t\t\t\t}\n\t\t\t\t// Cleanup must not replace a callback, commit, or rollback failure.\n\t\t\t\tawait close().catch(() => {});\n\t\t\t\tthrow failure;\n\t\t\t}\n\t\t\tawait close();\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.closePromise ??= this.queue.drained().then(() => this.call(() => this.driver.close()));\n\t\treturn this.closePromise;\n\t}\n}\n\n/**\n * Wraps a SQLite-compatible driver as a `SqliteDatabase`. The facade queues operations in call order and keeps them\n * outside active transactions, snapshots binary parameters at call time, rejects NUL text, returns safe-range integers\n * as numbers and blobs as `Uint8Array` copies, expires transaction handles when their callback settles, maps driver\n * failures to `StorageUnavailableError` with credentials redacted, and reports failed rollbacks with\n * `StorageRollbackError`. Closing rejects new calls, drains accepted work, then closes the driver once.\n */\nexport function createSqliteDatabase(driver: SqliteDriver): SqliteDatabase {\n\treturn new DriverDatabase(driver, driver.redact?.bind(driver) ?? ((text) => text));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sqlite-facade.js","sourceRoot":"","sources":["../../../src/core/storage/sqlite-facade.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tSqliteDatabase,\n\tSqliteExecutor,\n\tSqliteRow,\n\tSqliteStatement,\n\tSqliteValue,\n\tStorageDescriptor,\n} from \"./database.js\";\nimport {\n\tStorageError,\n\ttype StorageFailureCause,\n\tStorageInvalidTextError,\n\tStorageRollbackError,\n\tStorageTransactionClosedError,\n\tStorageUnavailableError,\n\tStoreClosedError,\n} from \"./errors.js\";\n\ntype Awaitable<T> = T | Promise<T>;\n\n/** A value as a driver returns it. Blobs may be any binary view; the facade returns them as `Uint8Array` copies. */\nexport type SqliteDriverValue = SqliteValue | ArrayBuffer | ArrayBufferView;\n\n/** One statement's result as a driver returns it: column names, positional rows, and the rows it changed. */\nexport interface SqliteDriverResult {\n\treadonly columns: readonly string[];\n\treadonly rows: readonly ArrayLike<SqliteDriverValue>[];\n\treadonly changes: number;\n}\n\n/** Runs SQL on a driver connection or on an open driver transaction. */\nexport interface SqliteDriverExecutor {\n\t/** Runs one statement with positional `?` parameters. */\n\texecute(sql: string, params: readonly SqliteValue[]): Awaitable<SqliteDriverResult>;\n\t/** Runs zero or more statements that take no parameters. */\n\texecuteMultiple(sql: string): Awaitable<void>;\n}\n\nexport interface SqliteDriverTransaction extends SqliteDriverExecutor {\n\tcommit(): Awaitable<void>;\n\trollback(): Awaitable<void>;\n\t/** Releases the transaction after it commits or rolls back. */\n\tclose?(): Awaitable<void>;\n}\n\n/** The driver calls `createSqliteDatabase` turns into a `SqliteDatabase`. */\nexport interface SqliteDriver extends SqliteDriverExecutor {\n\t/** Diagnostic identity. Its `location` passes through `redact` before the facade exposes it. */\n\treadonly descriptor: StorageDescriptor;\n\t/** Begins a write transaction that holds the database's write lock, like `BEGIN IMMEDIATE`. */\n\tbeginTransaction(): Awaitable<SqliteDriverTransaction>;\n\t/**\n\t * Optional. Runs the statements in order in one write transaction, in one request: all commit or none do. Provide it\n\t * only when the driver sends the whole batch at once; the facade then offers `SqliteDatabase.batch`.\n\t */\n\tbatch?(statements: readonly SqliteStatement[]): Awaitable<readonly SqliteDriverResult[]>;\n\t/** Releases the connection. Called once, after accepted work drains. */\n\tclose(): Awaitable<void>;\n\t/** Removes credentials from diagnostic text: the descriptor location and driver failure messages and stacks. */\n\tredact?(text: string): string;\n}\n\n/**\n * A redactor that replaces every non-empty secret, and its URI-encoded and URI-decoded forms, with `[redacted]`.\n * Longer secrets are replaced first, so a secret that contains another is removed whole.\n */\nexport function redactSecrets(secrets: Iterable<string>): (text: string) => string {\n\tconst variants = new Set<string>();\n\tfor (const secret of secrets) {\n\t\tvariants.add(secret);\n\t\ttry {\n\t\t\tvariants.add(encodeURIComponent(secret));\n\t\t} catch {}\n\t\ttry {\n\t\t\tvariants.add(decodeURIComponent(secret));\n\t\t} catch {}\n\t}\n\tconst ordered = [...variants].filter(Boolean).sort((first, second) => second.length - first.length);\n\treturn (text) => ordered.reduce((value, secret) => value.replaceAll(secret, \"[redacted]\"), text);\n}\n\nfunction redactCause(cause: StorageFailureCause, redact: (text: string) => string): StorageFailureCause {\n\tif (typeof cause === \"string\") return redact(cause);\n\tif (!(cause instanceof Error)) return cause;\n\tconst nested = cause.cause as StorageFailureCause;\n\tconst safeCause = redactCause(nested, redact);\n\tconst message = redact(cause.message);\n\tconst stack = cause.stack === undefined ? undefined : redact(cause.stack);\n\tif (message === cause.message && stack === cause.stack && safeCause === nested) return cause;\n\tconst safe = new StorageError(message, { cause: safeCause });\n\tsafe.stack = stack;\n\treturn safe;\n}\n\nfunction snapshotParams(params: readonly SqliteValue[]): SqliteValue[] {\n\treturn params.map((value) => (value instanceof Uint8Array ? new Uint8Array(value) : value));\n}\n\nfunction normalizeValue(value: SqliteDriverValue): SqliteValue {\n\tif (typeof value === \"bigint\") {\n\t\treturn value >= -BigInt(Number.MAX_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER)\n\t\t\t? Number(value)\n\t\t\t: value;\n\t}\n\tif (value instanceof ArrayBuffer) return new Uint8Array(value.slice(0));\n\tif (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength).slice();\n\treturn value;\n}\n\nfunction normalizeRow(row: ArrayLike<SqliteDriverValue>, columns: readonly string[]): SqliteRow {\n\treturn Object.fromEntries(columns.map((column, index) => [column, normalizeValue(row[index] ?? null)]));\n}\n\n/** Serializes operations in call order; a failed operation does not stop the ones queued after it. */\nclass CallQueue {\n\tprivate tail: Promise<void> = Promise.resolve();\n\n\tpush<T>(operation: () => Promise<T>): Promise<T> {\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\tdrained(): Promise<void> {\n\t\treturn this.tail;\n\t}\n}\n\nclass DriverDatabase implements SqliteDatabase {\n\treadonly descriptor: StorageDescriptor;\n\tprivate readonly driver: SqliteDriver;\n\tprivate readonly redact: (text: string) => string;\n\tprivate readonly queue = new CallQueue();\n\tprivate closePromise?: Promise<void>;\n\tprivate readonly executor: SqliteExecutor;\n\treadonly batch?: (statements: readonly SqliteStatement[]) => Promise<SqliteRow[][]>;\n\n\tconstructor(driver: SqliteDriver, redact: (text: string) => string) {\n\t\tthis.driver = driver;\n\t\tthis.redact = redact;\n\t\tthis.descriptor = { adapter: driver.descriptor.adapter, location: redact(driver.descriptor.location) };\n\t\tthis.executor = this.createExecutor(driver, (operation) => {\n\t\t\tif (this.closePromise) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\t\treturn this.queue.push(operation);\n\t\t});\n\t\tconst batch = driver.batch?.bind(driver);\n\t\tif (batch) this.batch = (statements) => this.runBatch(batch, statements);\n\t}\n\n\tprivate runBatch(\n\t\tbatch: NonNullable<SqliteDriver[\"batch\"]>,\n\t\tstatements: readonly SqliteStatement[],\n\t): Promise<SqliteRow[][]> {\n\t\tif (this.closePromise) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\tconst bound = statements.map((statement) => ({ sql: statement.sql, params: snapshotParams(statement.params) }));\n\t\treturn this.queue.push(async () => {\n\t\t\tfor (const statement of bound) {\n\t\t\t\tconst invalidIndex = statement.params.findIndex(\n\t\t\t\t\t(value) => typeof value === \"string\" && value.includes(\"\\0\"),\n\t\t\t\t);\n\t\t\t\tif (invalidIndex !== -1) throw new StorageInvalidTextError(invalidIndex);\n\t\t\t}\n\t\t\tconst results = await this.call(() => batch(bound));\n\t\t\treturn results.map((result) => result.rows.map((row) => normalizeRow(row, result.columns)));\n\t\t});\n\t}\n\n\t/** Maps a driver failure to `StorageUnavailableError` with a credential-free cause. */\n\tprivate async call<T>(operation: () => Awaitable<T>): Promise<T> {\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} catch (cause) {\n\t\t\tthrow new StorageUnavailableError(this.descriptor, redactCause(cause as StorageFailureCause, this.redact));\n\t\t}\n\t}\n\n\tprivate createExecutor(\n\t\tconnection: SqliteDriverExecutor,\n\t\tadmit: <T>(operation: () => Promise<T>) => Promise<T>,\n\t): SqliteExecutor {\n\t\tconst statement = (sql: string, params: readonly SqliteValue[]) => {\n\t\t\tconst bound = snapshotParams(params);\n\t\t\treturn admit(async () => {\n\t\t\t\tconst invalidIndex = bound.findIndex((value) => typeof value === \"string\" && value.includes(\"\\0\"));\n\t\t\t\tif (invalidIndex !== -1) throw new StorageInvalidTextError(invalidIndex);\n\t\t\t\treturn this.call(() => connection.execute(sql, bound));\n\t\t\t});\n\t\t};\n\t\treturn {\n\t\t\texec: (sql) => admit(() => this.call(() => connection.executeMultiple(sql))),\n\t\t\trun: async (sql, ...params) => ({ changes: (await statement(sql, params)).changes }),\n\t\t\tget: async <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) => {\n\t\t\t\tconst result = await statement(sql, params);\n\t\t\t\tconst row = result.rows[0];\n\t\t\t\treturn row === undefined ? undefined : (normalizeRow(row, result.columns) as T);\n\t\t\t},\n\t\t\tall: async <T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]) => {\n\t\t\t\tconst result = await statement(sql, params);\n\t\t\t\treturn result.rows.map((row) => normalizeRow(row, result.columns) as T);\n\t\t\t},\n\t\t};\n\t}\n\n\texec(sql: string): Promise<void> {\n\t\treturn this.executor.exec(sql);\n\t}\n\n\trun(sql: string, ...params: readonly SqliteValue[]) {\n\t\treturn this.executor.run(sql, ...params);\n\t}\n\n\tget<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T | undefined> {\n\t\treturn this.executor.get<T>(sql, ...params);\n\t}\n\n\tall<T extends SqliteRow>(sql: string, ...params: readonly SqliteValue[]): Promise<T[]> {\n\t\treturn this.executor.all<T>(sql, ...params);\n\t}\n\n\ttransaction<T>(callback: (transaction: SqliteExecutor) => Promise<T>): Promise<T> {\n\t\tif (this.closePromise) return Promise.reject(new StoreClosedError(this.descriptor));\n\t\treturn this.queue.push(async () => {\n\t\t\tconst connection = await this.call(() => this.driver.beginTransaction());\n\t\t\tconst handleQueue = new CallQueue();\n\t\t\tlet active = true;\n\t\t\tlet result: T;\n\t\t\tconst handle = this.createExecutor(connection, (operation) =>\n\t\t\t\tactive ? handleQueue.push(operation) : Promise.reject(new StorageTransactionClosedError()),\n\t\t\t);\n\t\t\tconst close = () => this.call(() => connection.close?.());\n\t\t\ttry {\n\t\t\t\ttry {\n\t\t\t\t\tresult = await callback(handle);\n\t\t\t\t} finally {\n\t\t\t\t\tactive = false;\n\t\t\t\t\tawait handleQueue.drained();\n\t\t\t\t}\n\t\t\t\tawait this.call(() => connection.commit());\n\t\t\t} catch (cause) {\n\t\t\t\tlet failure = cause as StorageFailureCause;\n\t\t\t\ttry {\n\t\t\t\t\tawait this.call(() => connection.rollback());\n\t\t\t\t} catch (rollbackCause) {\n\t\t\t\t\tfailure = new StorageRollbackError(failure, rollbackCause as StorageFailureCause);\n\t\t\t\t}\n\t\t\t\t// Cleanup must not replace a callback, commit, or rollback failure.\n\t\t\t\tawait close().catch(() => {});\n\t\t\t\tthrow failure;\n\t\t\t}\n\t\t\tawait close();\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.closePromise ??= this.queue.drained().then(() => this.call(() => this.driver.close()));\n\t\treturn this.closePromise;\n\t}\n}\n\n/**\n * Wraps a SQLite-compatible driver as a `SqliteDatabase`. The facade queues operations in call order and keeps them\n * outside active transactions, snapshots binary parameters at call time, rejects NUL text, returns safe-range integers\n * as numbers and blobs as `Uint8Array` copies, expires transaction handles when their callback settles, maps driver\n * failures to `StorageUnavailableError` with credentials redacted, and reports failed rollbacks with\n * `StorageRollbackError`. Closing rejects new calls, drains accepted work, then closes the driver once.\n */\nexport function createSqliteDatabase(driver: SqliteDriver): SqliteDatabase {\n\treturn new DriverDatabase(driver, driver.redact?.bind(driver) ?? ((text) => text));\n}\n"]}
|
package/docs/storage.md
CHANGED
|
@@ -53,6 +53,8 @@ Then select it in `~/.atomic/agent/settings.json`:
|
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
For a self-hosted sqld started with `--enable-namespaces`, add `"namespace": "<name>"` to `options`; the adapter sends it as the `x-namespace` header, so each namespace is its own database with its own token. `namespace` needs a `libsql:`, `https:`, or `http:` URL. SDK callers can also pass extra request `headers` to `openLibsqlDatabase`; their values are redacted from errors.
|
|
57
|
+
|
|
56
58
|
Save the token with `turso db tokens create <db> > turso-token` and keep it readable only by you (`chmod 600`); a trailing newline is ignored. A relative `file` resolves against Atomic home, normally `~/.atomic`. Use `{ "env": "TURSO_TOKEN" }` instead to read it from an environment variable. For a local database file, use a `file:` URL such as `file:/home/me/shared.sqlite` and omit `secrets`. Every machine that uses the same `storage` block shares the same sessions, workflow runs, and Intercom routing; add a `prefix` to keep projects or teams apart. See [Sharing storage across hosts](#sharing-storage-across-hosts).
|
|
57
59
|
|
|
58
60
|
Like any [adapter](#selecting-an-adapter), it runs with Atomic's privileges. To use a different driver, adapt it with [Bring your own driver](#bring-your-own-driver).
|
|
@@ -108,6 +110,7 @@ Atomic does not bundle remote database drivers. Install your chosen SQLite-compa
|
|
|
108
110
|
- `executeMultiple(sql)`: runs zero or more statements that take no parameters.
|
|
109
111
|
- `beginTransaction()`: begins a write transaction and returns its own `execute` and `executeMultiple`, plus `commit()`, `rollback()`, and an optional `close()` that releases it afterward.
|
|
110
112
|
- `close()`: releases the connection.
|
|
113
|
+
- `batch(statements)`, optional: runs `{ sql, params }` statements in order in one write transaction, sent as one request, and returns each statement's result; all of them commit or none do. Provide it only when your driver sends the whole batch at once. The facade then offers `SqliteDatabase.batch`, and workflow journals write a batch of events with one request instead of one per statement.
|
|
111
114
|
- `redact(text)`, optional: removes credentials from diagnostic text. `redactSecrets(secrets)` builds one that also removes each secret's URI-encoded and decoded forms, longest first.
|
|
112
115
|
|
|
113
116
|
Driver calls may return values or promises. The returned facade follows the rules described above: it queues operations in call order and keeps them outside active transactions, snapshots binary parameters when a call is made, rejects NUL text with `StorageInvalidTextError` before SQL runs, returns safe-range integers as numbers and blobs as `Uint8Array` copies, expires transaction handles when their callback settles, and closes the driver once after draining accepted work. A failed driver call rejects with `StorageUnavailableError`, whose `cause` is the driver error with credentials redacted. A failed rollback rejects with `StorageRollbackError`, and callback failures are preserved. Do not fall back to memory after an opening failure.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49-alpha.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bastani/atomic",
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.49-alpha.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@bastani/atomic-natives": "0.9.
|
|
13
|
-
"@bastani/pi-ai": "0.9.
|
|
12
|
+
"@bastani/atomic-natives": "0.9.49-alpha.1",
|
|
13
|
+
"@bastani/pi-ai": "0.9.49-alpha.1",
|
|
14
14
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
15
15
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
16
16
|
"@earendil-works/pi-tui": "1.4.0",
|
|
@@ -427,18 +427,18 @@
|
|
|
427
427
|
}
|
|
428
428
|
},
|
|
429
429
|
"node_modules/@bastani/atomic-natives": {
|
|
430
|
-
"version": "0.9.
|
|
431
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.
|
|
430
|
+
"version": "0.9.49-alpha.1",
|
|
431
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.49-alpha.1.tgz",
|
|
432
432
|
"license": "MIT",
|
|
433
433
|
"optionalDependencies": {
|
|
434
|
-
"@bastani/atomic-natives-darwin-arm64": "0.9.
|
|
435
|
-
"@bastani/atomic-natives-darwin-x64": "0.9.
|
|
436
|
-
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.
|
|
437
|
-
"@bastani/atomic-natives-linux-arm64-musl": "0.9.
|
|
438
|
-
"@bastani/atomic-natives-linux-x64-gnu": "0.9.
|
|
439
|
-
"@bastani/atomic-natives-linux-x64-musl": "0.9.
|
|
440
|
-
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.
|
|
441
|
-
"@bastani/atomic-natives-win32-x64-msvc": "0.9.
|
|
434
|
+
"@bastani/atomic-natives-darwin-arm64": "0.9.49-alpha.1",
|
|
435
|
+
"@bastani/atomic-natives-darwin-x64": "0.9.49-alpha.1",
|
|
436
|
+
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.49-alpha.1",
|
|
437
|
+
"@bastani/atomic-natives-linux-arm64-musl": "0.9.49-alpha.1",
|
|
438
|
+
"@bastani/atomic-natives-linux-x64-gnu": "0.9.49-alpha.1",
|
|
439
|
+
"@bastani/atomic-natives-linux-x64-musl": "0.9.49-alpha.1",
|
|
440
|
+
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.49-alpha.1",
|
|
441
|
+
"@bastani/atomic-natives-win32-x64-msvc": "0.9.49-alpha.1"
|
|
442
442
|
},
|
|
443
443
|
"engines": {
|
|
444
444
|
"bun": ">=1.4.2",
|
|
@@ -446,8 +446,8 @@
|
|
|
446
446
|
}
|
|
447
447
|
},
|
|
448
448
|
"node_modules/@bastani/atomic-natives-darwin-arm64": {
|
|
449
|
-
"version": "0.9.
|
|
450
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.
|
|
449
|
+
"version": "0.9.49-alpha.1",
|
|
450
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.49-alpha.1.tgz",
|
|
451
451
|
"license": "MIT",
|
|
452
452
|
"os": [
|
|
453
453
|
"darwin"
|
|
@@ -458,8 +458,8 @@
|
|
|
458
458
|
"optional": true
|
|
459
459
|
},
|
|
460
460
|
"node_modules/@bastani/atomic-natives-darwin-x64": {
|
|
461
|
-
"version": "0.9.
|
|
462
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.
|
|
461
|
+
"version": "0.9.49-alpha.1",
|
|
462
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.49-alpha.1.tgz",
|
|
463
463
|
"license": "MIT",
|
|
464
464
|
"os": [
|
|
465
465
|
"darwin"
|
|
@@ -470,8 +470,8 @@
|
|
|
470
470
|
"optional": true
|
|
471
471
|
},
|
|
472
472
|
"node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
|
|
473
|
-
"version": "0.9.
|
|
474
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.
|
|
473
|
+
"version": "0.9.49-alpha.1",
|
|
474
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.49-alpha.1.tgz",
|
|
475
475
|
"license": "MIT",
|
|
476
476
|
"os": [
|
|
477
477
|
"linux"
|
|
@@ -485,8 +485,8 @@
|
|
|
485
485
|
"optional": true
|
|
486
486
|
},
|
|
487
487
|
"node_modules/@bastani/atomic-natives-linux-arm64-musl": {
|
|
488
|
-
"version": "0.9.
|
|
489
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.
|
|
488
|
+
"version": "0.9.49-alpha.1",
|
|
489
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.49-alpha.1.tgz",
|
|
490
490
|
"license": "MIT",
|
|
491
491
|
"os": [
|
|
492
492
|
"linux"
|
|
@@ -500,8 +500,8 @@
|
|
|
500
500
|
"optional": true
|
|
501
501
|
},
|
|
502
502
|
"node_modules/@bastani/atomic-natives-linux-x64-gnu": {
|
|
503
|
-
"version": "0.9.
|
|
504
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.
|
|
503
|
+
"version": "0.9.49-alpha.1",
|
|
504
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.49-alpha.1.tgz",
|
|
505
505
|
"license": "MIT",
|
|
506
506
|
"os": [
|
|
507
507
|
"linux"
|
|
@@ -515,8 +515,8 @@
|
|
|
515
515
|
"optional": true
|
|
516
516
|
},
|
|
517
517
|
"node_modules/@bastani/atomic-natives-linux-x64-musl": {
|
|
518
|
-
"version": "0.9.
|
|
519
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.
|
|
518
|
+
"version": "0.9.49-alpha.1",
|
|
519
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.49-alpha.1.tgz",
|
|
520
520
|
"license": "MIT",
|
|
521
521
|
"os": [
|
|
522
522
|
"linux"
|
|
@@ -530,8 +530,8 @@
|
|
|
530
530
|
"optional": true
|
|
531
531
|
},
|
|
532
532
|
"node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
|
|
533
|
-
"version": "0.9.
|
|
534
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.
|
|
533
|
+
"version": "0.9.49-alpha.1",
|
|
534
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.49-alpha.1.tgz",
|
|
535
535
|
"license": "MIT",
|
|
536
536
|
"os": [
|
|
537
537
|
"win32"
|
|
@@ -542,8 +542,8 @@
|
|
|
542
542
|
"optional": true
|
|
543
543
|
},
|
|
544
544
|
"node_modules/@bastani/atomic-natives-win32-x64-msvc": {
|
|
545
|
-
"version": "0.9.
|
|
546
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.
|
|
545
|
+
"version": "0.9.49-alpha.1",
|
|
546
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.49-alpha.1.tgz",
|
|
547
547
|
"license": "MIT",
|
|
548
548
|
"os": [
|
|
549
549
|
"win32"
|
|
@@ -554,8 +554,8 @@
|
|
|
554
554
|
"optional": true
|
|
555
555
|
},
|
|
556
556
|
"node_modules/@bastani/pi-ai": {
|
|
557
|
-
"version": "0.9.
|
|
558
|
-
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.
|
|
557
|
+
"version": "0.9.49-alpha.1",
|
|
558
|
+
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.49-alpha.1.tgz",
|
|
559
559
|
"license": "MIT",
|
|
560
560
|
"dependencies": {
|
|
561
561
|
"@anthropic-ai/sdk": "0.129.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49-alpha.1",
|
|
4
4
|
"description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"atomicConfig": {
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@bastani/atomic-natives": "0.9.
|
|
93
|
-
"@bastani/pi-ai": "0.9.
|
|
92
|
+
"@bastani/atomic-natives": "0.9.49-alpha.1",
|
|
93
|
+
"@bastani/pi-ai": "0.9.49-alpha.1",
|
|
94
94
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
95
95
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
96
96
|
"@earendil-works/pi-tui": "1.4.0",
|