@yieldstar/sqlite-runtime 0.5.0 → 0.6.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/dist/bun.js +15 -17
- package/dist/dao/effect-waiters-dao.d.ts +19 -0
- package/dist/dao/effect-waiters-dao.d.ts.map +1 -0
- package/dist/dao/effects-dao.d.ts +17 -0
- package/dist/dao/effects-dao.d.ts.map +1 -0
- package/dist/dao/executions-dao.d.ts +23 -0
- package/dist/dao/executions-dao.d.ts.map +1 -0
- package/dist/dao/start-requests-dao.d.ts +15 -0
- package/dist/dao/start-requests-dao.d.ts.map +1 -0
- package/dist/dao/step-response-dao.d.ts +1 -0
- package/dist/dao/step-response-dao.d.ts.map +1 -1
- package/dist/dao/store-waiters-dao.d.ts +26 -0
- package/dist/dao/store-waiters-dao.d.ts.map +1 -0
- package/dist/index-083bmj5k.js +800 -0
- package/dist/index-4kybaxga.js +798 -0
- package/dist/index-a8thbaee.js +718 -0
- package/dist/index-ag93sv33.js +664 -0
- package/dist/index-eabcgmaa.js +996 -0
- package/dist/index-gjfs8rn6.js +997 -0
- package/dist/index-h3h7r4b6.js +981 -0
- package/dist/index-ma984fze.js +718 -0
- package/dist/index-ne28djfn.js +718 -0
- package/dist/index-v6rn0pr6.js +664 -0
- package/dist/index-wx6vk994.js +669 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -13
- package/dist/node.js +15 -17
- package/dist/sqlite-effect.d.ts +30 -0
- package/dist/sqlite-effect.d.ts.map +1 -0
- package/dist/sqlite-execution.d.ts +54 -0
- package/dist/sqlite-execution.d.ts.map +1 -0
- package/dist/sqlite-heap.d.ts +12 -4
- package/dist/sqlite-heap.d.ts.map +1 -1
- package/dist/sqlite-runtime.d.ts +22 -0
- package/dist/sqlite-runtime.d.ts.map +1 -0
- package/dist/sqlite-store.d.ts +31 -25
- package/dist/sqlite-store.d.ts.map +1 -1
- package/dist/sqlite-transaction.d.ts +9 -0
- package/dist/sqlite-transaction.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/dao/effect-waiters-dao.ts +63 -0
- package/src/dao/effects-dao.ts +123 -0
- package/src/dao/executions-dao.ts +188 -0
- package/src/dao/start-requests-dao.ts +72 -0
- package/src/dao/step-response-dao.ts +16 -1
- package/src/dao/store-waiters-dao.ts +92 -0
- package/src/index.ts +6 -4
- package/src/sqlite-effect.ts +99 -0
- package/src/sqlite-execution.ts +238 -0
- package/src/sqlite-heap.ts +64 -12
- package/src/sqlite-runtime.ts +36 -0
- package/src/sqlite-store.ts +184 -520
- package/src/sqlite-transaction.ts +19 -0
- package/dist/dao/task-queue-dao.d.ts +0 -21
- package/dist/dao/task-queue-dao.d.ts.map +0 -1
- package/dist/dao/timers-dao.d.ts +0 -22
- package/dist/dao/timers-dao.d.ts.map +0 -1
- package/dist/index-4vq70w0r.js +0 -796
- package/dist/index-s8wqgfwt.js +0 -19
- package/dist/index-x891hxwg.js +0 -796
- package/dist/node-driver.d.ts +0 -10
- package/dist/node-driver.d.ts.map +0 -1
- package/dist/sqlite-event-loop.d.ts +0 -18
- package/dist/sqlite-event-loop.d.ts.map +0 -1
- package/dist/sqlite-scheduler.d.ts +0 -13
- package/dist/sqlite-scheduler.d.ts.map +0 -1
- package/dist/sqlite-store.test.d.ts +0 -2
- package/dist/sqlite-store.test.d.ts.map +0 -1
- package/dist/sqlite-task-queue.d.ts +0 -26
- package/dist/sqlite-task-queue.d.ts.map +0 -1
- package/dist/sqlite-timers.d.ts +0 -18
- package/dist/sqlite-timers.d.ts.map +0 -1
- package/src/dao/task-queue-dao.ts +0 -79
- package/src/dao/timers-dao.ts +0 -81
- package/src/sqlite-event-loop.ts +0 -41
- package/src/sqlite-scheduler.ts +0 -24
- package/src/sqlite-task-queue.ts +0 -64
- package/src/sqlite-timers.ts +0 -40
- package/tsconfig.tsbuildinfo +0 -1
- /package/dist/{index-h7bm9xg4.js → index-dapqh99v.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "./index-4vq70w0r.js";
|
|
2
|
+
SqliteExecutionClient2,
|
|
3
|
+
SqliteEffectClient2,
|
|
4
|
+
SqliteHeapClient2,
|
|
5
|
+
SqliteStoreClient2,
|
|
6
|
+
SqliteRuntime2
|
|
7
|
+
} from "./index-h3h7r4b6.js";
|
|
9
8
|
export {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
SqliteEventLoop
|
|
9
|
+
SqliteEffectClient2 as SqliteEffectClient,
|
|
10
|
+
SqliteExecutionClient2 as SqliteExecutionClient,
|
|
11
|
+
SqliteHeapClient2 as SqliteHeapClient,
|
|
12
|
+
SqliteRuntime2 as SqliteRuntime,
|
|
13
|
+
SqliteStoreClient2 as SqliteStoreClient
|
|
16
14
|
};
|
package/dist/node.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SqliteExecutionClient2,
|
|
3
|
+
SqliteEffectClient2,
|
|
4
|
+
SqliteHeapClient2,
|
|
5
|
+
SqliteStoreClient2,
|
|
6
|
+
SqliteRuntime2
|
|
7
|
+
} from "./index-h3h7r4b6.js";
|
|
1
8
|
import {
|
|
2
9
|
createSqliteDriver,
|
|
3
10
|
wrapSqliteStatement
|
|
4
|
-
} from "./index-
|
|
5
|
-
import {
|
|
6
|
-
SqliteEventLoop,
|
|
7
|
-
SqliteHeapClient,
|
|
8
|
-
SqliteSchedulerClient,
|
|
9
|
-
SqliteStoreClient,
|
|
10
|
-
SqliteTaskQueueClient,
|
|
11
|
-
SqliteTimersClient
|
|
12
|
-
} from "./index-4vq70w0r.js";
|
|
11
|
+
} from "./index-dapqh99v.js";
|
|
13
12
|
|
|
14
13
|
// src/node.ts
|
|
15
14
|
import { DatabaseSync } from "node:sqlite";
|
|
@@ -38,12 +37,11 @@ function createSqliteDb(opts) {
|
|
|
38
37
|
return createSqliteDriver((path) => new NodeSqliteDriver(new DatabaseSync(path)), opts);
|
|
39
38
|
}
|
|
40
39
|
export {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
NodeSqliteDriver
|
|
40
|
+
NodeSqliteDriver,
|
|
41
|
+
SqliteEffectClient2 as SqliteEffectClient,
|
|
42
|
+
SqliteExecutionClient2 as SqliteExecutionClient,
|
|
43
|
+
SqliteHeapClient2 as SqliteHeapClient,
|
|
44
|
+
SqliteRuntime2 as SqliteRuntime,
|
|
45
|
+
SqliteStoreClient2 as SqliteStoreClient,
|
|
46
|
+
createSqliteDb
|
|
49
47
|
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type EffectBeginRequest, type EffectBeginResult, type EffectClient, type EffectRecord, type EffectSettleRequest, type EffectSettleResult, type EffectWatchRequest } from "@yieldstar/core";
|
|
2
|
+
import type { SqliteDriver } from "./sqlite-driver";
|
|
3
|
+
import { SqliteExecutionClient } from "./sqlite-execution";
|
|
4
|
+
/**
|
|
5
|
+
* Effect records and waiters in the same database as the execution records,
|
|
6
|
+
* so a settlement and the wakes of its waiters commit in one IMMEDIATE
|
|
7
|
+
* transaction.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SqliteEffectClient implements EffectClient {
|
|
10
|
+
private db;
|
|
11
|
+
private executions;
|
|
12
|
+
private effectsDao;
|
|
13
|
+
private effectWaitersDao;
|
|
14
|
+
private clock;
|
|
15
|
+
/**
|
|
16
|
+
* @param params.executions The execution client whose records waiters wake.
|
|
17
|
+
* Defaults to one over `db` with the default clock; SqliteRuntime passes
|
|
18
|
+
* its own so both share the runtime clock.
|
|
19
|
+
*/
|
|
20
|
+
constructor(params: {
|
|
21
|
+
db: SqliteDriver;
|
|
22
|
+
executions?: SqliteExecutionClient;
|
|
23
|
+
clock?: () => number;
|
|
24
|
+
});
|
|
25
|
+
begin(request: EffectBeginRequest): Promise<EffectBeginResult>;
|
|
26
|
+
settle(request: EffectSettleRequest): Promise<EffectSettleResult>;
|
|
27
|
+
watch(request: EffectWatchRequest): Promise<void>;
|
|
28
|
+
getEffect(effectId: string): Promise<EffectRecord | undefined>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=sqlite-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-effect.d.ts","sourceRoot":"","sources":["../src/sqlite-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAG3D;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,KAAK,CAAe;IAE5B;;;;OAIG;gBACS,MAAM,EAAE;QAClB,EAAE,EAAE,YAAY,CAAC;QACjB,UAAU,CAAC,EAAE,qBAAqB,CAAC;QACnC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;KACtB;IAUK,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAU9D,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkBjE,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAIrE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ExecutionAcknowledgeResult, type ExecutionAdmissionRequest, type ExecutionAdmissionResult, type ExecutionClient, type ExecutionLease, type ExecutionRecord, type ExecutionStartRequest, type ExecutionStartResult, type ExecutionReleaseResult, type ExecutionRenewResult, type ExecutionWakeResult, type WorkflowRunOutcome } from "@yieldstar/core";
|
|
2
|
+
import type { SqliteDriver } from "./sqlite-driver";
|
|
3
|
+
export type SqliteExecutionClientOptions = {
|
|
4
|
+
/** Reads the current time. Defaults to `Date.now`. */
|
|
5
|
+
clock?: () => number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Execution records in the `executions` table. Every operation loads a row,
|
|
9
|
+
* applies a pure transition from @yieldstar/core and writes it back inside one
|
|
10
|
+
* IMMEDIATE transaction, so processes sharing the database file see the same
|
|
11
|
+
* semantics as the memory runtime.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SqliteExecutionClient implements ExecutionClient {
|
|
14
|
+
private db;
|
|
15
|
+
private executionsDao;
|
|
16
|
+
private startRequestsDao;
|
|
17
|
+
private clock;
|
|
18
|
+
constructor(db: SqliteDriver, options?: SqliteExecutionClientOptions);
|
|
19
|
+
admit(request: ExecutionAdmissionRequest): Promise<ExecutionAdmissionResult>;
|
|
20
|
+
start(request: ExecutionStartRequest): Promise<ExecutionStartResult>;
|
|
21
|
+
get(executionId: string): Promise<ExecutionRecord | undefined>;
|
|
22
|
+
requestWake(request: {
|
|
23
|
+
executionId: string;
|
|
24
|
+
wakeAt: number;
|
|
25
|
+
}): Promise<ExecutionWakeResult>;
|
|
26
|
+
claimDue(request: {
|
|
27
|
+
limit: number;
|
|
28
|
+
duration: number;
|
|
29
|
+
}): Promise<ExecutionLease[]>;
|
|
30
|
+
renew(request: {
|
|
31
|
+
lease: ExecutionLease;
|
|
32
|
+
duration: number;
|
|
33
|
+
}): Promise<ExecutionRenewResult>;
|
|
34
|
+
release(request: {
|
|
35
|
+
lease: ExecutionLease;
|
|
36
|
+
}): Promise<ExecutionReleaseResult>;
|
|
37
|
+
acknowledge(request: {
|
|
38
|
+
lease: ExecutionLease;
|
|
39
|
+
outcome: WorkflowRunOutcome;
|
|
40
|
+
}): Promise<ExecutionAcknowledgeResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Applies a fenced transition in one transaction. The transition checks the
|
|
43
|
+
* lease against the stored token, so the check and the write are atomic.
|
|
44
|
+
*/
|
|
45
|
+
private transition;
|
|
46
|
+
/**
|
|
47
|
+
* @internal Requests a wake from inside a transaction the caller already
|
|
48
|
+
* holds on the same database, so the wake commits with the caller's write
|
|
49
|
+
* (e.g. a store commit). `wakeAt` defaults to the runtime clock's now.
|
|
50
|
+
* Unknown and terminal executions are ignored.
|
|
51
|
+
*/
|
|
52
|
+
wakeInTransaction(executionId: string, wakeAt?: number): void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=sqlite-execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-execution.d.ts","sourceRoot":"","sources":["../src/sqlite-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAeL,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAEzB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,MAAM,MAAM,4BAA4B,GAAG;IACzC,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,KAAK,CAAe;gBAEhB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAE,4BAAiC;IAQlE,KAAK,CACT,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC;IA0B9B,KAAK,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAiCpE,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAK9D,WAAW,CAAC,OAAO,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAa1B,QAAQ,CAAC,OAAO,EAAE;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA2BvB,KAAK,CAAC,OAAO,EAAE;QACnB,KAAK,EAAE,cAAc,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAU3B,OAAO,CAAC,OAAO,EAAE;QACrB,KAAK,EAAE,cAAc,CAAC;KACvB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAM7B,WAAW,CAAC,OAAO,EAAE;QACzB,KAAK,EAAE,cAAc,CAAC;QACtB,OAAO,EAAE,kBAAkB,CAAC;KAC7B,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAUvC;;;OAGG;IACH,OAAO,CAAC,UAAU;IAelB;;;;;OAKG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,GAAE,MAAqB;CAOrE"}
|
package/dist/sqlite-heap.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ExecutionLease, type HeapClient, type HeapRecord, type LeaseLost } from "@yieldstar/core";
|
|
2
2
|
import type { SqliteDriver } from "./sqlite-driver";
|
|
3
3
|
export declare class SqliteHeapClient implements HeapClient {
|
|
4
|
+
private db;
|
|
5
|
+
private executionsDao;
|
|
4
6
|
private stepResponsesDao;
|
|
7
|
+
private storeWaitersDao;
|
|
8
|
+
private effectWaitersDao;
|
|
5
9
|
constructor(db: SqliteDriver);
|
|
6
10
|
getAllSteps(): Promise<unknown[]>;
|
|
7
11
|
deleteAll(): Promise<void>;
|
|
@@ -15,12 +19,16 @@ export declare class SqliteHeapClient implements HeapClient {
|
|
|
15
19
|
done: boolean;
|
|
16
20
|
};
|
|
17
21
|
} | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Checks the lease against the `executions` row and writes the step record
|
|
24
|
+
* in one IMMEDIATE transaction, so no claim can interleave between them.
|
|
25
|
+
*/
|
|
18
26
|
writeStep(params: {
|
|
19
|
-
|
|
27
|
+
lease: ExecutionLease;
|
|
20
28
|
stepKey: string;
|
|
21
29
|
stepAttempt: number;
|
|
22
|
-
|
|
30
|
+
done: boolean;
|
|
23
31
|
stepResponseJson: string;
|
|
24
|
-
}): Promise<
|
|
32
|
+
}): Promise<HeapRecord | LeaseLost>;
|
|
25
33
|
}
|
|
26
34
|
//# sourceMappingURL=sqlite-heap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-heap.d.ts","sourceRoot":"","sources":["../src/sqlite-heap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sqlite-heap.d.ts","sourceRoot":"","sources":["../src/sqlite-heap.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AAKzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,gBAAgB,CAAmB;gBAE/B,EAAE,EAAE,YAAY;IAQtB,WAAW;IAIX,SAAS;IAIT,QAAQ,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;;;;;;;IAmB/D;;;OAGG;IACG,SAAS,CAAC,MAAM,EAAE;QACtB,KAAK,EAAE,cAAc,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,OAAO,CAAC;QACd,gBAAgB,EAAE,MAAM,CAAC;KAC1B,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;CAuCpC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Runtime, type RuntimeOptions } from "@yieldstar/core";
|
|
2
|
+
import { SqliteEffectClient } from "./sqlite-effect";
|
|
3
|
+
import { SqliteExecutionClient } from "./sqlite-execution";
|
|
4
|
+
import { SqliteHeapClient } from "./sqlite-heap";
|
|
5
|
+
import { SqliteStoreClient } from "./sqlite-store";
|
|
6
|
+
import type { SqliteDriver } from "./sqlite-driver";
|
|
7
|
+
export type SqliteRuntimeOptions = RuntimeOptions;
|
|
8
|
+
/**
|
|
9
|
+
* Execution records, step records, stores, effects and waiters in one SQLite
|
|
10
|
+
* database, so every guarantee that spans them (wakes for a store commit or an
|
|
11
|
+
* effect settlement, deleting a waiter with its step's result) holds in a
|
|
12
|
+
* single transaction.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SqliteRuntime extends Runtime {
|
|
15
|
+
readonly clock: () => number;
|
|
16
|
+
readonly executions: SqliteExecutionClient;
|
|
17
|
+
readonly effects: SqliteEffectClient;
|
|
18
|
+
readonly heap: SqliteHeapClient;
|
|
19
|
+
readonly stores: SqliteStoreClient;
|
|
20
|
+
constructor(db: SqliteDriver, options?: SqliteRuntimeOptions);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=sqlite-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-runtime.d.ts","sourceRoot":"","sources":["../src/sqlite-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAElD;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,OAAO;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;gBAEvB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAE,oBAAyB;CAajE"}
|
package/dist/sqlite-store.d.ts
CHANGED
|
@@ -1,24 +1,38 @@
|
|
|
1
|
-
import type { SchedulerClient } from "@yieldstar/core";
|
|
2
1
|
import type { SqliteDriver } from "./sqlite-driver";
|
|
3
|
-
import {
|
|
2
|
+
import { SqliteExecutionClient } from "./sqlite-execution";
|
|
3
|
+
import { CasStoreClient, type StandardSchemaV1, type StoreDefinition, type StoreDeletion, type StoreSnapshot, type StoreStepId, type StoreWaiter, type StoreMutation, type StoreMutationCommitResult } from "@yieldstar/core";
|
|
4
|
+
/**
|
|
5
|
+
* Stores, waiters and the applied-steps ledger, in the same database as the
|
|
6
|
+
* execution records. A commit that satisfies waiters requests their wakes in
|
|
7
|
+
* the same transaction, so a durable commit always has durable wakes.
|
|
8
|
+
*
|
|
9
|
+
* Every write is one synchronous IMMEDIATE transaction: nothing awaits
|
|
10
|
+
* between BEGIN and COMMIT, so operations on a shared connection cannot
|
|
11
|
+
* interleave, and processes sharing the file serialize on SQLite's lock.
|
|
12
|
+
*/
|
|
4
13
|
export declare class SqliteStoreClient extends CasStoreClient {
|
|
5
14
|
private db;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
15
|
+
private executions;
|
|
16
|
+
private storeWaitersDao;
|
|
17
|
+
/**
|
|
18
|
+
* @param params.executions The execution client whose records waiters wake.
|
|
19
|
+
* Defaults to one over `db` with the default clock; SqliteRuntime passes
|
|
20
|
+
* its own so both share the runtime clock.
|
|
21
|
+
*/
|
|
8
22
|
constructor(params: {
|
|
9
23
|
db: SqliteDriver;
|
|
10
|
-
|
|
24
|
+
executions?: SqliteExecutionClient;
|
|
11
25
|
});
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
definition: StoreDefinition
|
|
26
|
+
protected createInstanceId(): string;
|
|
27
|
+
protected readStore(params: {
|
|
28
|
+
definition: StoreDefinition;
|
|
15
29
|
id: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
definition: StoreDefinition<Schema>;
|
|
30
|
+
}): Promise<StoreSnapshot<unknown> | undefined>;
|
|
31
|
+
protected insertStore(params: {
|
|
32
|
+
definition: StoreDefinition;
|
|
20
33
|
id: string;
|
|
21
|
-
|
|
34
|
+
snapshot: StoreSnapshot<unknown>;
|
|
35
|
+
}): Promise<StoreSnapshot<unknown>>;
|
|
22
36
|
protected getAppliedStoreStep(params: {
|
|
23
37
|
definition: StoreDefinition;
|
|
24
38
|
id: string;
|
|
@@ -32,23 +46,15 @@ export declare class SqliteStoreClient extends CasStoreClient {
|
|
|
32
46
|
definition: StoreDefinition<Schema>;
|
|
33
47
|
id: string;
|
|
34
48
|
}): Promise<void>;
|
|
35
|
-
|
|
36
|
-
definition: StoreDefinition;
|
|
37
|
-
id: string;
|
|
38
|
-
snapshot: StoreSnapshot<unknown>;
|
|
39
|
-
stepId?: StoreStepId;
|
|
40
|
-
}): Promise<StoreDeleteFromResult>;
|
|
49
|
+
protected commitStoreDeletion(deletion: StoreDeletion): Promise<StoreMutationCommitResult>;
|
|
41
50
|
registerWaiter(waiter: StoreWaiter): Promise<void>;
|
|
42
51
|
private setupDb;
|
|
43
52
|
private createStoresTable;
|
|
44
53
|
private getAppliedStepRow;
|
|
45
54
|
private insertAppliedStepRow;
|
|
46
55
|
private getStoreRow;
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
private
|
|
50
|
-
private drainWakeOutbox;
|
|
51
|
-
private drainWakeOutboxBestEffort;
|
|
52
|
-
private assertSnapshotHasInstanceId;
|
|
56
|
+
/** Executions with a waiter that the commit at `version` satisfies. */
|
|
57
|
+
private selectMatchingExecutionIds;
|
|
58
|
+
private insertStoreRow;
|
|
53
59
|
}
|
|
54
60
|
//# sourceMappingURL=sqlite-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../src/sqlite-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../src/sqlite-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAEL,cAAc,EAId,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,aAAa,EAElB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC/B,MAAM,iBAAiB,CAAC;AAgBzB;;;;;;;;GAQG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;IACnD,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,eAAe,CAAkB;IAEzC;;;;OAIG;gBACS,MAAM,EAAE;QAAE,EAAE,EAAE,YAAY,CAAC;QAAC,UAAU,CAAC,EAAE,qBAAqB,CAAA;KAAE;IAQ5E,SAAS,CAAC,gBAAgB,IAAI,MAAM;cAIpB,SAAS,CAAC,MAAM,EAAE;QAChC,UAAU,EAAE,eAAe,CAAC;QAC5B,EAAE,EAAE,MAAM,CAAC;KACZ,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;cAK/B,WAAW,CAAC,MAAM,EAAE;QAClC,UAAU,EAAE,eAAe,CAAC;QAC5B,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;KAClC,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;cAenB,mBAAmB,CAAC,MAAM,EAAE;QAC1C,UAAU,EAAE,eAAe,CAAC;QAC5B,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,WAAW,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;cAS5B,mBAAmB,CACjC,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,yBAAyB,CAAC;IAgF/B,UAAU,CAAC,MAAM,SAAS,gBAAgB,EAC9C,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,GAClC,OAAO,CAAC,MAAM,EAAE,CAAC;IAWd,WAAW,CAAC,MAAM,SAAS,gBAAgB,EAAE,MAAM,EAAE;QACzD,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QACpC,EAAE,EAAE,MAAM,CAAC;KACZ,GAAG,OAAO,CAAC,IAAI,CAAC;cAcD,mBAAmB,CACjC,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,yBAAyB,CAAC;IAyC/B,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBxD,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,WAAW;IAYnB,uEAAuE;IACvE,OAAO,CAAC,0BAA0B;IAwBlC,OAAO,CAAC,cAAc;CAoBvB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SqliteDriver } from "./sqlite-driver";
|
|
2
|
+
/**
|
|
3
|
+
* Runs `fn` in one `BEGIN IMMEDIATE … COMMIT` transaction, rolling back if it
|
|
4
|
+
* throws. `fn` is synchronous so no other operation on this connection can
|
|
5
|
+
* interleave, and IMMEDIATE takes the write lock up front so concurrent
|
|
6
|
+
* processes sharing the database file serialize on it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runTransaction<R>(db: SqliteDriver, fn: () => R): R;
|
|
9
|
+
//# sourceMappingURL=sqlite-transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-transaction.d.ts","sourceRoot":"","sources":["../src/sqlite-transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAUlE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yieldstar/sqlite-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Daniel Grant",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"pino": "^9.9.0",
|
|
33
33
|
"uuid": "^11.1.0",
|
|
34
|
-
"@yieldstar/core": "0.
|
|
34
|
+
"@yieldstar/core": "0.6.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/bun": "^1.2.21",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { SqliteDriver } from "../sqlite-driver";
|
|
2
|
+
|
|
3
|
+
class EffectWaiterRow {
|
|
4
|
+
execution_id!: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Effect waiters live in the same database as step records, so the heap can
|
|
9
|
+
* delete a waiter in the same transaction that records its step's result.
|
|
10
|
+
* Callers own the surrounding transaction.
|
|
11
|
+
*/
|
|
12
|
+
export class EffectWaitersDao {
|
|
13
|
+
private db: SqliteDriver;
|
|
14
|
+
|
|
15
|
+
constructor(db: SqliteDriver) {
|
|
16
|
+
this.db = db;
|
|
17
|
+
this.setupDb();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
setupDb() {
|
|
21
|
+
this.db.run(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS effect_waiters (
|
|
23
|
+
effect_id TEXT NOT NULL,
|
|
24
|
+
execution_id TEXT NOT NULL,
|
|
25
|
+
step_key TEXT NOT NULL,
|
|
26
|
+
PRIMARY KEY (effect_id, execution_id, step_key)
|
|
27
|
+
);
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_effect_waiters_step
|
|
29
|
+
ON effect_waiters(execution_id, step_key);
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
upsertWaiter(waiter: { effectId: string; executionId: string; stepKey: string }) {
|
|
34
|
+
this.db
|
|
35
|
+
.query(
|
|
36
|
+
`INSERT INTO effect_waiters (effect_id, execution_id, step_key)
|
|
37
|
+
VALUES ($effectId, $executionId, $stepKey)
|
|
38
|
+
ON CONFLICT(effect_id, execution_id, step_key) DO NOTHING`
|
|
39
|
+
)
|
|
40
|
+
.run({
|
|
41
|
+
$effectId: waiter.effectId,
|
|
42
|
+
$executionId: waiter.executionId,
|
|
43
|
+
$stepKey: waiter.stepKey,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getWaitingExecutionIds(effectId: string): string[] {
|
|
48
|
+
return this.db
|
|
49
|
+
.query<EffectWaiterRow>(
|
|
50
|
+
`SELECT DISTINCT execution_id FROM effect_waiters WHERE effect_id = $effectId`
|
|
51
|
+
)
|
|
52
|
+
.all({ $effectId: effectId })
|
|
53
|
+
.map((row) => row.execution_id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
deleteStepWaiters(executionId: string, stepKey: string) {
|
|
57
|
+
this.db
|
|
58
|
+
.query(
|
|
59
|
+
`DELETE FROM effect_waiters WHERE execution_id = $executionId AND step_key = $stepKey`
|
|
60
|
+
)
|
|
61
|
+
.run({ $executionId: executionId, $stepKey: stepKey });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { EffectConflictState, EffectState } from "@yieldstar/core";
|
|
2
|
+
import type { SqliteDriver } from "../sqlite-driver";
|
|
3
|
+
|
|
4
|
+
class EffectRow {
|
|
5
|
+
effect_id!: string;
|
|
6
|
+
operation!: string;
|
|
7
|
+
input!: string;
|
|
8
|
+
status!: EffectState["status"];
|
|
9
|
+
result!: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class EffectConflictRow {
|
|
13
|
+
result!: string;
|
|
14
|
+
conflicting_result!: string;
|
|
15
|
+
reported_at!: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Effect records and their conflict reports. Neither is deleted with an
|
|
20
|
+
* execution. Callers own the surrounding transaction.
|
|
21
|
+
*/
|
|
22
|
+
export class EffectsDao {
|
|
23
|
+
private db: SqliteDriver;
|
|
24
|
+
|
|
25
|
+
constructor(db: SqliteDriver) {
|
|
26
|
+
this.db = db;
|
|
27
|
+
this.setupDb();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setupDb() {
|
|
31
|
+
this.db.run(`
|
|
32
|
+
CREATE TABLE IF NOT EXISTS effects (
|
|
33
|
+
effect_id TEXT PRIMARY KEY,
|
|
34
|
+
operation TEXT NOT NULL,
|
|
35
|
+
input TEXT NOT NULL,
|
|
36
|
+
status TEXT NOT NULL,
|
|
37
|
+
result TEXT
|
|
38
|
+
);
|
|
39
|
+
CREATE TABLE IF NOT EXISTS effect_conflicts (
|
|
40
|
+
effect_id TEXT NOT NULL,
|
|
41
|
+
result TEXT NOT NULL,
|
|
42
|
+
conflicting_result TEXT NOT NULL,
|
|
43
|
+
reported_at INTEGER NOT NULL,
|
|
44
|
+
PRIMARY KEY (effect_id, conflicting_result)
|
|
45
|
+
);
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getState(effectId: string): EffectState | undefined {
|
|
50
|
+
const row = this.db
|
|
51
|
+
.query<EffectRow>(`SELECT * FROM effects WHERE effect_id = $effectId`)
|
|
52
|
+
.get({ $effectId: effectId });
|
|
53
|
+
if (!row) return undefined;
|
|
54
|
+
const conflicts = this.db
|
|
55
|
+
.query<EffectConflictRow>(
|
|
56
|
+
`SELECT result, conflicting_result, reported_at FROM effect_conflicts
|
|
57
|
+
WHERE effect_id = $effectId
|
|
58
|
+
ORDER BY reported_at, rowid`
|
|
59
|
+
)
|
|
60
|
+
.all({ $effectId: effectId });
|
|
61
|
+
const state: EffectState = {
|
|
62
|
+
effectId: row.effect_id,
|
|
63
|
+
operation: row.operation,
|
|
64
|
+
input: row.input,
|
|
65
|
+
status: row.status,
|
|
66
|
+
conflicts: conflicts.map((conflict) => ({
|
|
67
|
+
result: conflict.result,
|
|
68
|
+
conflictingResult: conflict.conflicting_result,
|
|
69
|
+
reportedAt: conflict.reported_at,
|
|
70
|
+
})),
|
|
71
|
+
};
|
|
72
|
+
if (row.result !== null) state.result = row.result;
|
|
73
|
+
return state;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
insertState(state: EffectState) {
|
|
77
|
+
this.db
|
|
78
|
+
.query(
|
|
79
|
+
`INSERT INTO effects (effect_id, operation, input, status, result)
|
|
80
|
+
VALUES ($effectId, $operation, $input, $status, $result)`
|
|
81
|
+
)
|
|
82
|
+
.run({
|
|
83
|
+
$effectId: state.effectId,
|
|
84
|
+
$operation: state.operation,
|
|
85
|
+
$input: state.input,
|
|
86
|
+
$status: state.status,
|
|
87
|
+
$result: state.result ?? null,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Writes a transition from `before` to `after`: the settlement and any new conflict reports. */
|
|
92
|
+
updateState(before: EffectState, after: EffectState) {
|
|
93
|
+
if (before.status !== after.status || before.result !== after.result) {
|
|
94
|
+
this.db
|
|
95
|
+
.query(
|
|
96
|
+
`UPDATE effects SET status = $status, result = $result
|
|
97
|
+
WHERE effect_id = $effectId`
|
|
98
|
+
)
|
|
99
|
+
.run({
|
|
100
|
+
$effectId: after.effectId,
|
|
101
|
+
$status: after.status,
|
|
102
|
+
$result: after.result ?? null,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
for (const conflict of after.conflicts.slice(before.conflicts.length)) {
|
|
106
|
+
this.insertConflict(after.effectId, conflict);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private insertConflict(effectId: string, conflict: EffectConflictState) {
|
|
111
|
+
this.db
|
|
112
|
+
.query(
|
|
113
|
+
`INSERT INTO effect_conflicts (effect_id, result, conflicting_result, reported_at)
|
|
114
|
+
VALUES ($effectId, $result, $conflictingResult, $reportedAt)`
|
|
115
|
+
)
|
|
116
|
+
.run({
|
|
117
|
+
$effectId: effectId,
|
|
118
|
+
$result: conflict.result,
|
|
119
|
+
$conflictingResult: conflict.conflictingResult,
|
|
120
|
+
$reportedAt: conflict.reportedAt,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|