@torkbot/sledge 0.1.0
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/LICENSE +21 -0
- package/README.md +251 -0
- package/dist/ledger/better-sqlite3-ledger.d.ts +18 -0
- package/dist/ledger/better-sqlite3-ledger.d.ts.map +1 -0
- package/dist/ledger/better-sqlite3-ledger.js +50 -0
- package/dist/ledger/better-sqlite3-ledger.js.map +1 -0
- package/dist/ledger/database-ledger-engine.d.ts +31 -0
- package/dist/ledger/database-ledger-engine.d.ts.map +1 -0
- package/dist/ledger/database-ledger-engine.js +798 -0
- package/dist/ledger/database-ledger-engine.js.map +1 -0
- package/dist/ledger/ledger.d.ts +233 -0
- package/dist/ledger/ledger.d.ts.map +1 -0
- package/dist/ledger/ledger.js +31 -0
- package/dist/ledger/ledger.js.map +1 -0
- package/dist/ledger/turso-ledger.d.ts +18 -0
- package/dist/ledger/turso-ledger.d.ts.map +1 -0
- package/dist/ledger/turso-ledger.js +50 -0
- package/dist/ledger/turso-ledger.js.map +1 -0
- package/dist/runtime/contracts.d.ts +26 -0
- package/dist/runtime/contracts.d.ts.map +1 -0
- package/dist/runtime/contracts.js +2 -0
- package/dist/runtime/contracts.js.map +1 -0
- package/dist/runtime/node-runtime.d.ts +15 -0
- package/dist/runtime/node-runtime.d.ts.map +1 -0
- package/dist/runtime/node-runtime.js +35 -0
- package/dist/runtime/node-runtime.js.map +1 -0
- package/dist/runtime/virtual-runtime.d.ts +28 -0
- package/dist/runtime/virtual-runtime.d.ts.map +1 -0
- package/dist/runtime/virtual-runtime.js +116 -0
- package/dist/runtime/virtual-runtime.js.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geoff Goodman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# @torkbot/sledge
|
|
2
|
+
|
|
3
|
+
A SQLite-backed event and work engine for building durable, restart-safe workflows.
|
|
4
|
+
|
|
5
|
+
If you need to reliably turn events into background work (without losing consistency during crashes/retries), this package gives you the core runtime.
|
|
6
|
+
|
|
7
|
+
## Who this is for
|
|
8
|
+
|
|
9
|
+
Use `@torkbot/sledge` when you want:
|
|
10
|
+
|
|
11
|
+
- durable event append + background work orchestration,
|
|
12
|
+
- retries and restart recovery by default,
|
|
13
|
+
- strong runtime validation at I/O boundaries,
|
|
14
|
+
- a small API surface you can adapt to your own schema and storage layout.
|
|
15
|
+
|
|
16
|
+
## What you get
|
|
17
|
+
|
|
18
|
+
- **Event log** (`events` table)
|
|
19
|
+
- **Durable work queue** (`work` table)
|
|
20
|
+
- **Transactional flow:** append event -> project -> materialize work in one transaction
|
|
21
|
+
- **Lease-based execution** for queue handlers
|
|
22
|
+
- **Idempotent producer retries** via `dedupeKey`
|
|
23
|
+
- **Configurable contention behavior** (`maxBusyRetries`, `maxBusyRetryDelayMs`)
|
|
24
|
+
|
|
25
|
+
## Example use-cases
|
|
26
|
+
|
|
27
|
+
- **Webhook ingestion** with producer idempotency (`dedupeKey`) and reliable downstream processing
|
|
28
|
+
- **Notification pipelines** (email/push/slack) with retries and dead-letter outcomes
|
|
29
|
+
- **Long-running tool/API jobs** that survive worker restarts
|
|
30
|
+
- **Outbox-style orchestration** without split-brain between writes and job enqueue
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick start (copy/paste)
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import Database from "better-sqlite3";
|
|
38
|
+
import { Type } from "@sinclair/typebox";
|
|
39
|
+
|
|
40
|
+
import { defineLedgerModel } from "@torkbot/sledge/ledger";
|
|
41
|
+
import { createBetterSqliteLedger } from "@torkbot/sledge/better-sqlite3-ledger";
|
|
42
|
+
import {
|
|
43
|
+
NodeRuntimeScheduler,
|
|
44
|
+
SystemRuntimeClock,
|
|
45
|
+
} from "@torkbot/sledge/runtime/node-runtime";
|
|
46
|
+
|
|
47
|
+
const model = defineLedgerModel({
|
|
48
|
+
events: {
|
|
49
|
+
"user.created": Type.Object({
|
|
50
|
+
userId: Type.String(),
|
|
51
|
+
email: Type.String(),
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
queues: {
|
|
56
|
+
"welcome-email.send": Type.Object({
|
|
57
|
+
userId: Type.String(),
|
|
58
|
+
email: Type.String(),
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
indexers: {
|
|
63
|
+
upsertUser: Type.Object({
|
|
64
|
+
userId: Type.String(),
|
|
65
|
+
email: Type.String(),
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
queries: {
|
|
70
|
+
userById: {
|
|
71
|
+
params: Type.Object({ userId: Type.String() }),
|
|
72
|
+
result: Type.Union([
|
|
73
|
+
Type.Null(),
|
|
74
|
+
Type.Object({
|
|
75
|
+
userId: Type.String(),
|
|
76
|
+
email: Type.String(),
|
|
77
|
+
}),
|
|
78
|
+
]),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
register(builder) {
|
|
83
|
+
// Event -> projection
|
|
84
|
+
builder.project("user.created", async ({ event, actions }) => {
|
|
85
|
+
await actions.index("upsertUser", {
|
|
86
|
+
userId: event.payload.userId,
|
|
87
|
+
email: event.payload.email,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Event -> queued work
|
|
92
|
+
builder.materialize("user.created", ({ event, actions }) => {
|
|
93
|
+
actions.enqueue("welcome-email.send", {
|
|
94
|
+
userId: event.payload.userId,
|
|
95
|
+
email: event.payload.email,
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Queue handler
|
|
100
|
+
builder.handle("welcome-email.send", async ({ work }) => {
|
|
101
|
+
// call provider here
|
|
102
|
+
console.log("sending welcome email", work.payload.email);
|
|
103
|
+
|
|
104
|
+
return { outcome: "ack" } as const;
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const db = new Database("./app.sqlite");
|
|
110
|
+
const clock = new SystemRuntimeClock();
|
|
111
|
+
const scheduler = new NodeRuntimeScheduler();
|
|
112
|
+
|
|
113
|
+
const ledger = createBetterSqliteLedger({
|
|
114
|
+
database: db,
|
|
115
|
+
boundModel: model.bind({
|
|
116
|
+
indexers: {
|
|
117
|
+
upsertUser: async (input) => {
|
|
118
|
+
// Write to your own projection table(s)
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
queries: {
|
|
122
|
+
userById: async () => {
|
|
123
|
+
// Read from your own projection table(s)
|
|
124
|
+
return null;
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}),
|
|
128
|
+
timing: {
|
|
129
|
+
clock,
|
|
130
|
+
scheduler,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await ledger.emit("user.created", {
|
|
135
|
+
userId: "u_123",
|
|
136
|
+
email: "alice@example.com",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await ledger.close();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## How to think about the API
|
|
145
|
+
|
|
146
|
+
### 1) `defineLedgerModel(...)`
|
|
147
|
+
|
|
148
|
+
You define contracts, not implementation details:
|
|
149
|
+
|
|
150
|
+
- `events`: facts appended to the event stream
|
|
151
|
+
- `queues`: durable work payloads
|
|
152
|
+
- `indexers`: projection write contracts
|
|
153
|
+
- `queries`: projection read contracts
|
|
154
|
+
- `register(builder)`: orchestration glue
|
|
155
|
+
|
|
156
|
+
### 2) `model.bind(...)`
|
|
157
|
+
|
|
158
|
+
You provide concrete implementations for indexers and queries.
|
|
159
|
+
|
|
160
|
+
### 3) `create*Ledger(...)`
|
|
161
|
+
|
|
162
|
+
You choose backend adapter and start the runtime:
|
|
163
|
+
|
|
164
|
+
- `createBetterSqliteLedger(...)`
|
|
165
|
+
- `createTursoLedger(...)`
|
|
166
|
+
|
|
167
|
+
The runtime exposes:
|
|
168
|
+
|
|
169
|
+
- `emit(eventName, payload, options?)`
|
|
170
|
+
- `query(queryName, params)`
|
|
171
|
+
- `close()`
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Handler outcomes
|
|
176
|
+
|
|
177
|
+
Queue handlers must return one of:
|
|
178
|
+
|
|
179
|
+
- `{ outcome: "ack" }`
|
|
180
|
+
- `{ outcome: "retry", error, retryAtMs? }`
|
|
181
|
+
- `{ outcome: "dead_letter", error }`
|
|
182
|
+
|
|
183
|
+
If a handler throws, the runtime treats it as a retry.
|
|
184
|
+
|
|
185
|
+
## Dedupe and idempotency
|
|
186
|
+
|
|
187
|
+
Use `dedupeKey` in `emit(...)` for producer retries.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
await ledger.emit(
|
|
191
|
+
"user.created",
|
|
192
|
+
{ userId: "u_123", email: "alice@example.com" },
|
|
193
|
+
{ dedupeKey: "provider-event:abc-123" },
|
|
194
|
+
);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Same key => same durable event winner, no duplicate downstream materialization.
|
|
198
|
+
|
|
199
|
+
## Long-running handlers
|
|
200
|
+
|
|
201
|
+
For long operations, keep the lease alive while working:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
builder.handle("some.queue", async ({ lease }) => {
|
|
205
|
+
await using hold = lease.hold();
|
|
206
|
+
|
|
207
|
+
// long-running async work
|
|
208
|
+
|
|
209
|
+
return { outcome: "ack" } as const;
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Runtime tuning knobs
|
|
214
|
+
|
|
215
|
+
Available options when creating a ledger:
|
|
216
|
+
|
|
217
|
+
- `leaseMs`
|
|
218
|
+
- `defaultRetryDelayMs`
|
|
219
|
+
- `maxInFlight`
|
|
220
|
+
- `maxBusyRetries`
|
|
221
|
+
- `maxBusyRetryDelayMs`
|
|
222
|
+
|
|
223
|
+
Start simple; tune only when you observe contention/throughput issues.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Package exports
|
|
228
|
+
|
|
229
|
+
- `@torkbot/sledge/ledger`
|
|
230
|
+
- `@torkbot/sledge/database-ledger-engine`
|
|
231
|
+
- `@torkbot/sledge/better-sqlite3-ledger`
|
|
232
|
+
- `@torkbot/sledge/turso-ledger`
|
|
233
|
+
- `@torkbot/sledge/runtime/contracts`
|
|
234
|
+
- `@torkbot/sledge/runtime/node-runtime`
|
|
235
|
+
- `@torkbot/sledge/runtime/virtual-runtime`
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
node --run typecheck
|
|
241
|
+
node --run test
|
|
242
|
+
node --run build
|
|
243
|
+
node --run lint
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Publishing notes
|
|
247
|
+
|
|
248
|
+
- The package is published as compiled JavaScript in `dist/` (with `.d.ts` types).
|
|
249
|
+
- Source remains strict TypeScript in `src/`.
|
|
250
|
+
- `prepublishOnly` runs `node --run build` automatically.
|
|
251
|
+
- Node version is pinned via `engines.node` because runtime code uses explicit resource management (`using` / `await using`).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
3
|
+
import type { Ledger, BoundLedgerModel, LedgerTiming, QuerySchema } from "./ledger.ts";
|
|
4
|
+
type AnyIndexerDef = TSchema;
|
|
5
|
+
type AnyQueryDef = QuerySchema<TSchema, TSchema>;
|
|
6
|
+
type CreateBetterSqliteLedgerInput<TEvents extends Record<string, TSchema>, TQueues extends Record<string, TSchema>, TIndexers extends Record<string, AnyIndexerDef>, TQueries extends Record<string, AnyQueryDef>> = {
|
|
7
|
+
readonly database: Database.Database;
|
|
8
|
+
readonly boundModel: BoundLedgerModel<TEvents, TQueues, TIndexers, TQueries>;
|
|
9
|
+
readonly timing: LedgerTiming;
|
|
10
|
+
readonly leaseMs?: number;
|
|
11
|
+
readonly defaultRetryDelayMs?: number;
|
|
12
|
+
readonly maxInFlight?: number;
|
|
13
|
+
readonly maxBusyRetries?: number;
|
|
14
|
+
readonly maxBusyRetryDelayMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function createBetterSqliteLedger<const TEvents extends Record<string, TSchema>, const TQueues extends Record<string, TSchema>, const TIndexers extends Record<string, AnyIndexerDef>, const TQueries extends Record<string, AnyQueryDef>>(input: CreateBetterSqliteLedgerInput<TEvents, TQueues, TIndexers, TQueries>): Ledger<TEvents, TQueries>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=better-sqlite3-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-sqlite3-ledger.d.ts","sourceRoot":"","sources":["../../src/ledger/better-sqlite3-ledger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EACV,MAAM,EACN,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACZ,MAAM,aAAa,CAAC;AAOrB,KAAK,aAAa,GAAG,OAAO,CAAC;AAC7B,KAAK,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAEjD,KAAK,6BAA6B,CAChC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAC/C,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAC1C;IACF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC7E,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACrD,KAAK,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAElD,KAAK,EAAE,6BAA6B,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,GAC1E,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAkB3B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createDatabaseLedger, } from "./database-ledger-engine.js";
|
|
2
|
+
export function createBetterSqliteLedger(input) {
|
|
3
|
+
const sharedInput = {
|
|
4
|
+
database: wrapBetterSqliteDatabase(input.database),
|
|
5
|
+
boundModel: input.boundModel,
|
|
6
|
+
timing: input.timing,
|
|
7
|
+
leaseMs: input.leaseMs,
|
|
8
|
+
defaultRetryDelayMs: input.defaultRetryDelayMs,
|
|
9
|
+
maxInFlight: input.maxInFlight,
|
|
10
|
+
maxBusyRetries: input.maxBusyRetries,
|
|
11
|
+
maxBusyRetryDelayMs: input.maxBusyRetryDelayMs,
|
|
12
|
+
};
|
|
13
|
+
return createDatabaseLedger(sharedInput);
|
|
14
|
+
}
|
|
15
|
+
function wrapBetterSqliteDatabase(database) {
|
|
16
|
+
return {
|
|
17
|
+
exec: async (sql) => {
|
|
18
|
+
database.exec(sql);
|
|
19
|
+
},
|
|
20
|
+
prepare: (sql) => {
|
|
21
|
+
const statement = database.prepare(sql);
|
|
22
|
+
return {
|
|
23
|
+
run: async (...params) => statement.run(...params),
|
|
24
|
+
get: async (...params) => {
|
|
25
|
+
const row = statement.get(...params);
|
|
26
|
+
if (row === undefined) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
30
|
+
throw new Error("expected row object from better-sqlite statement.get");
|
|
31
|
+
}
|
|
32
|
+
return row;
|
|
33
|
+
},
|
|
34
|
+
all: async (...params) => {
|
|
35
|
+
const rows = statement.all(...params);
|
|
36
|
+
return rows.map((row) => {
|
|
37
|
+
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
38
|
+
throw new Error("expected row object from better-sqlite statement.all");
|
|
39
|
+
}
|
|
40
|
+
return row;
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
close: async () => {
|
|
46
|
+
database.close();
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=better-sqlite3-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-sqlite3-ledger.js","sourceRoot":"","sources":["../../src/ledger/better-sqlite3-ledger.ts"],"names":[],"mappings":"AASA,OAAO,EACL,oBAAoB,GAGrB,MAAM,6BAA6B,CAAC;AAqBrC,MAAM,UAAU,wBAAwB,CAMtC,KAA2E;IAE3E,MAAM,WAAW,GAKb;QACF,QAAQ,EAAE,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAClD,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;KAC/C,CAAC;IAEF,OAAO,oBAAoB,CAAC,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,wBAAwB,CAC/B,QAA2B;IAE3B,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAClB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACf,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAExC,OAAO;gBACL,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;gBAClD,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,EAAE;oBACvB,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;oBAErC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;wBACtB,OAAO,SAAS,CAAC;oBACnB,CAAC;oBAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;wBAClE,MAAM,IAAI,KAAK,CACb,sDAAsD,CACvD,CAAC;oBACJ,CAAC;oBAED,OAAO,GAA8B,CAAC;gBACxC,CAAC;gBACD,GAAG,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,EAAE;oBACvB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;oBAEtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;wBACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;4BAClE,MAAM,IAAI,KAAK,CACb,sDAAsD,CACvD,CAAC;wBACJ,CAAC;wBAED,OAAO,GAA8B,CAAC;oBACxC,CAAC,CAAC,CAAC;gBACL,CAAC;aACF,CAAC;QACJ,CAAC;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
2
|
+
import type { BoundLedgerModel, Ledger, LedgerTiming, QuerySchema } from "./ledger.ts";
|
|
3
|
+
type AnyIndexerDef = TSchema;
|
|
4
|
+
type AnyQueryDef = QuerySchema<TSchema, TSchema>;
|
|
5
|
+
type StorageRow = Record<string, unknown>;
|
|
6
|
+
export interface StorageStatement {
|
|
7
|
+
run(...params: unknown[]): Promise<{
|
|
8
|
+
readonly changes: number;
|
|
9
|
+
readonly lastInsertRowid: number | bigint;
|
|
10
|
+
}>;
|
|
11
|
+
get(...params: unknown[]): Promise<StorageRow | undefined>;
|
|
12
|
+
all(...params: unknown[]): Promise<readonly StorageRow[]>;
|
|
13
|
+
}
|
|
14
|
+
export interface StorageDatabase {
|
|
15
|
+
exec(sql: string): Promise<void>;
|
|
16
|
+
prepare(sql: string): StorageStatement;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export type CreateDatabaseLedgerInput<TEvents extends Record<string, TSchema>, TQueues extends Record<string, TSchema>, TIndexers extends Record<string, AnyIndexerDef>, TQueries extends Record<string, AnyQueryDef>> = {
|
|
20
|
+
readonly database: StorageDatabase;
|
|
21
|
+
readonly boundModel: BoundLedgerModel<TEvents, TQueues, TIndexers, TQueries>;
|
|
22
|
+
readonly timing: LedgerTiming;
|
|
23
|
+
readonly leaseMs?: number;
|
|
24
|
+
readonly defaultRetryDelayMs?: number;
|
|
25
|
+
readonly maxInFlight?: number;
|
|
26
|
+
readonly maxBusyRetries?: number;
|
|
27
|
+
readonly maxBusyRetryDelayMs?: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function createDatabaseLedger<const TEvents extends Record<string, TSchema>, const TQueues extends Record<string, TSchema>, const TIndexers extends Record<string, AnyIndexerDef>, const TQueries extends Record<string, AnyQueryDef>>(input: CreateDatabaseLedgerInput<TEvents, TQueues, TIndexers, TQueries>): Ledger<TEvents, TQueries>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=database-ledger-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-ledger-engine.d.ts","sourceRoot":"","sources":["../../src/ledger/database-ledger-engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,KAAK,EACV,gBAAgB,EAEhB,MAAM,EAEN,YAAY,EAGZ,WAAW,EAOZ,MAAM,aAAa,CAAC;AAErB,KAAK,aAAa,GAAG,OAAO,CAAC;AAC7B,KAAK,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAqBjD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;KAC3C,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAE3D,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAEvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAkBD,MAAM,MAAM,yBAAyB,CACnC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAC/C,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAC1C;IACF,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC7E,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACrD,KAAK,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAElD,KAAK,EAAE,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,GACtE,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAW3B"}
|