station-adapter-sqlite 1.0.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 +86 -0
- package/dist/broadcast.d.ts +29 -0
- package/dist/broadcast.d.ts.map +1 -0
- package/dist/broadcast.js +239 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +303 -0
- package/dist/index.js.map +1 -0
- package/dist/shared.d.ts +14 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +44 -0
- package/dist/shared.js.map +1 -0
- package/package.json +40 -0
- package/src/broadcast.ts +279 -0
- package/src/index.ts +354 -0
- package/src/shared.ts +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 porkytheblack
|
|
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,86 @@
|
|
|
1
|
+
# station-adapter-sqlite
|
|
2
|
+
|
|
3
|
+
SQLite storage adapter for station-signal using better-sqlite3.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add station-adapter-sqlite
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires `station-signal` as a peer dependency.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Configure globally:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { configure } from "station-signal";
|
|
19
|
+
import { SqliteAdapter } from "station-adapter-sqlite";
|
|
20
|
+
|
|
21
|
+
configure({ adapter: new SqliteAdapter() });
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Options
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
interface SqliteAdapterOptions {
|
|
28
|
+
/** Path to the SQLite database file. Defaults to "station-signal.db". */
|
|
29
|
+
dbPath?: string;
|
|
30
|
+
/** Table name. Defaults to "entries". */
|
|
31
|
+
tableName?: string;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Example with options:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const adapter = new SqliteAdapter({
|
|
39
|
+
dbPath: "./data/jobs.db",
|
|
40
|
+
tableName: "signal_entries",
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## With SignalRunner
|
|
45
|
+
|
|
46
|
+
The `configModule` pattern lets you share a single adapter instance across the runner and all spawned child processes.
|
|
47
|
+
|
|
48
|
+
1. Create a config module (e.g. `src/adapter.config.ts`):
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { configure } from "station-signal";
|
|
52
|
+
import { SqliteAdapter } from "station-adapter-sqlite";
|
|
53
|
+
|
|
54
|
+
configure({ adapter: new SqliteAdapter({ dbPath: "./jobs.db" }) });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. Pass it to the runner:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { SignalRunner } from "station-signal";
|
|
61
|
+
import { fileURLToPath } from "node:url";
|
|
62
|
+
|
|
63
|
+
const runner = new SignalRunner({
|
|
64
|
+
signalsDir: "./src/signals",
|
|
65
|
+
configModule: fileURLToPath(new URL("./adapter.config.ts", import.meta.url)),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await runner.start();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The runner imports the config module on startup and passes its path to every spawned child process via an environment variable, so they all connect to the same SQLite database.
|
|
72
|
+
|
|
73
|
+
## Graceful shutdown
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const adapter = new SqliteAdapter();
|
|
77
|
+
// ... use adapter ...
|
|
78
|
+
adapter.close();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Details
|
|
82
|
+
|
|
83
|
+
- WAL mode is enabled by default for better concurrent read/write performance.
|
|
84
|
+
- Table and indexes are created automatically on first use (`CREATE TABLE IF NOT EXISTS`).
|
|
85
|
+
- Date fields are stored as ISO-8601 text strings.
|
|
86
|
+
- All methods are async (to satisfy the `SignalQueueAdapter` interface) but use synchronous better-sqlite3 under the hood.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BroadcastQueueAdapter, BroadcastRun, BroadcastRunPatch, BroadcastRunStatus, BroadcastNodeRun, BroadcastNodeRunPatch } from "station-broadcast";
|
|
2
|
+
export interface BroadcastSqliteAdapterOptions {
|
|
3
|
+
dbPath?: string;
|
|
4
|
+
tableName?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class BroadcastSqliteAdapter implements BroadcastQueueAdapter {
|
|
7
|
+
private db;
|
|
8
|
+
private runsTable;
|
|
9
|
+
private nodesTable;
|
|
10
|
+
constructor(options?: BroadcastSqliteAdapterOptions);
|
|
11
|
+
addBroadcastRun(run: BroadcastRun): Promise<void>;
|
|
12
|
+
getBroadcastRun(id: string): Promise<BroadcastRun | null>;
|
|
13
|
+
private static readonly BROADCAST_RUN_PATCH_KEYS;
|
|
14
|
+
updateBroadcastRun(id: string, patch: BroadcastRunPatch): Promise<void>;
|
|
15
|
+
getBroadcastRunsDue(): Promise<BroadcastRun[]>;
|
|
16
|
+
getBroadcastRunsRunning(): Promise<BroadcastRun[]>;
|
|
17
|
+
listBroadcastRuns(broadcastName: string): Promise<BroadcastRun[]>;
|
|
18
|
+
hasBroadcastRunWithStatus(broadcastName: string, statuses: BroadcastRunStatus[]): Promise<boolean>;
|
|
19
|
+
purgeBroadcastRuns(olderThan: Date, statuses: BroadcastRunStatus[]): Promise<number>;
|
|
20
|
+
addNodeRun(nodeRun: BroadcastNodeRun): Promise<void>;
|
|
21
|
+
getNodeRun(id: string): Promise<BroadcastNodeRun | null>;
|
|
22
|
+
private static readonly NODE_RUN_PATCH_KEYS;
|
|
23
|
+
updateNodeRun(id: string, patch: BroadcastNodeRunPatch): Promise<void>;
|
|
24
|
+
getNodeRuns(broadcastRunId: string): Promise<BroadcastNodeRun[]>;
|
|
25
|
+
generateId(): string;
|
|
26
|
+
ping(): Promise<boolean>;
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=broadcast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAgC3B,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,sBAAuB,YAAW,qBAAqB;IAClE,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,GAAE,6BAAkC;IA2DjD,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBjD,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAK/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAG7C;IAEG,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvE,mBAAmB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAW9C,uBAAuB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAKlD,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAKjE,yBAAyB,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IASlG,kBAAkB,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAUpF,UAAU,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAK9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAExC;IAEG,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBtE,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAKtE,UAAU,IAAI,MAAM;IAId,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IASxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
|
+
import { validateTableName, dateToStr, createColumnMapper, rowToObject } from "./shared.js";
|
|
4
|
+
const { toColumn: toBroadcastRunCol, toField: toBroadcastRunField } = createColumnMapper({
|
|
5
|
+
broadcastName: "broadcast_name",
|
|
6
|
+
failurePolicy: "failure_policy",
|
|
7
|
+
nextRunAt: "next_run_at",
|
|
8
|
+
startedAt: "started_at",
|
|
9
|
+
completedAt: "completed_at",
|
|
10
|
+
createdAt: "created_at",
|
|
11
|
+
});
|
|
12
|
+
const BROADCAST_RUN_DATE_FIELDS = new Set(["nextRunAt", "startedAt", "completedAt", "createdAt"]);
|
|
13
|
+
const { toColumn: toNodeRunCol, toField: toNodeRunField } = createColumnMapper({
|
|
14
|
+
broadcastRunId: "broadcast_run_id",
|
|
15
|
+
nodeName: "node_name",
|
|
16
|
+
signalName: "signal_name",
|
|
17
|
+
signalRunId: "signal_run_id",
|
|
18
|
+
skipReason: "skip_reason",
|
|
19
|
+
startedAt: "started_at",
|
|
20
|
+
completedAt: "completed_at",
|
|
21
|
+
});
|
|
22
|
+
const NODE_RUN_DATE_FIELDS = new Set(["startedAt", "completedAt"]);
|
|
23
|
+
function rowToBroadcastRun(row) {
|
|
24
|
+
return rowToObject(row, toBroadcastRunField, BROADCAST_RUN_DATE_FIELDS);
|
|
25
|
+
}
|
|
26
|
+
function rowToNodeRun(row) {
|
|
27
|
+
return rowToObject(row, toNodeRunField, NODE_RUN_DATE_FIELDS);
|
|
28
|
+
}
|
|
29
|
+
export class BroadcastSqliteAdapter {
|
|
30
|
+
db;
|
|
31
|
+
runsTable;
|
|
32
|
+
nodesTable;
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
const dbPath = options.dbPath ?? "station.db";
|
|
35
|
+
this.runsTable = validateTableName(options.tableName ?? "broadcast_runs");
|
|
36
|
+
this.nodesTable = validateTableName(`${this.runsTable}_nodes`);
|
|
37
|
+
this.db = new Database(dbPath);
|
|
38
|
+
this.db.pragma("journal_mode = WAL");
|
|
39
|
+
this.db.pragma("foreign_keys = ON");
|
|
40
|
+
this.db.exec(`
|
|
41
|
+
CREATE TABLE IF NOT EXISTS ${this.runsTable} (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
broadcast_name TEXT NOT NULL,
|
|
44
|
+
input TEXT NOT NULL,
|
|
45
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
46
|
+
failure_policy TEXT NOT NULL DEFAULT 'fail-fast',
|
|
47
|
+
timeout INTEGER,
|
|
48
|
+
interval TEXT,
|
|
49
|
+
next_run_at TEXT,
|
|
50
|
+
started_at TEXT,
|
|
51
|
+
completed_at TEXT,
|
|
52
|
+
created_at TEXT NOT NULL,
|
|
53
|
+
error TEXT
|
|
54
|
+
)
|
|
55
|
+
`);
|
|
56
|
+
this.db.exec(`
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_${this.runsTable}_status
|
|
58
|
+
ON ${this.runsTable} (status, next_run_at)
|
|
59
|
+
`);
|
|
60
|
+
this.db.exec(`
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_${this.runsTable}_name
|
|
62
|
+
ON ${this.runsTable} (broadcast_name)
|
|
63
|
+
`);
|
|
64
|
+
this.db.exec(`
|
|
65
|
+
CREATE TABLE IF NOT EXISTS ${this.nodesTable} (
|
|
66
|
+
id TEXT PRIMARY KEY,
|
|
67
|
+
broadcast_run_id TEXT NOT NULL REFERENCES ${this.runsTable}(id) ON DELETE CASCADE,
|
|
68
|
+
node_name TEXT NOT NULL,
|
|
69
|
+
signal_name TEXT NOT NULL,
|
|
70
|
+
signal_run_id TEXT,
|
|
71
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
72
|
+
skip_reason TEXT,
|
|
73
|
+
input TEXT,
|
|
74
|
+
output TEXT,
|
|
75
|
+
error TEXT,
|
|
76
|
+
started_at TEXT,
|
|
77
|
+
completed_at TEXT
|
|
78
|
+
)
|
|
79
|
+
`);
|
|
80
|
+
this.db.exec(`
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_${this.nodesTable}_run_id
|
|
82
|
+
ON ${this.nodesTable} (broadcast_run_id)
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
async addBroadcastRun(run) {
|
|
86
|
+
this.db.prepare(`
|
|
87
|
+
INSERT INTO ${this.runsTable}
|
|
88
|
+
(id, broadcast_name, input, status, failure_policy, timeout, interval,
|
|
89
|
+
next_run_at, started_at, completed_at, created_at, error)
|
|
90
|
+
VALUES
|
|
91
|
+
(@id, @broadcast_name, @input, @status, @failure_policy, @timeout, @interval,
|
|
92
|
+
@next_run_at, @started_at, @completed_at, @created_at, @error)
|
|
93
|
+
`).run({
|
|
94
|
+
id: run.id,
|
|
95
|
+
broadcast_name: run.broadcastName,
|
|
96
|
+
input: run.input,
|
|
97
|
+
status: run.status,
|
|
98
|
+
failure_policy: run.failurePolicy,
|
|
99
|
+
timeout: run.timeout ?? null,
|
|
100
|
+
interval: run.interval ?? null,
|
|
101
|
+
next_run_at: dateToStr(run.nextRunAt),
|
|
102
|
+
started_at: dateToStr(run.startedAt),
|
|
103
|
+
completed_at: dateToStr(run.completedAt),
|
|
104
|
+
created_at: dateToStr(run.createdAt),
|
|
105
|
+
error: run.error ?? null,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async getBroadcastRun(id) {
|
|
109
|
+
const row = this.db.prepare(`SELECT * FROM ${this.runsTable} WHERE id = ?`).get(id);
|
|
110
|
+
return row ? rowToBroadcastRun(row) : null;
|
|
111
|
+
}
|
|
112
|
+
static BROADCAST_RUN_PATCH_KEYS = new Set([
|
|
113
|
+
"input", "status", "failurePolicy", "timeout", "interval", "nextRunAt",
|
|
114
|
+
"startedAt", "completedAt", "error",
|
|
115
|
+
]);
|
|
116
|
+
async updateBroadcastRun(id, patch) {
|
|
117
|
+
const setClauses = [];
|
|
118
|
+
const values = { id };
|
|
119
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
120
|
+
if (!BroadcastSqliteAdapter.BROADCAST_RUN_PATCH_KEYS.has(key))
|
|
121
|
+
continue;
|
|
122
|
+
const col = toBroadcastRunCol(key);
|
|
123
|
+
const param = `p_${col}`;
|
|
124
|
+
setClauses.push(`${col} = @${param}`);
|
|
125
|
+
if (value === undefined) {
|
|
126
|
+
values[param] = null;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
values[param] = BROADCAST_RUN_DATE_FIELDS.has(key) ? dateToStr(value) : value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (setClauses.length === 0)
|
|
133
|
+
return;
|
|
134
|
+
this.db.prepare(`UPDATE ${this.runsTable} SET ${setClauses.join(", ")} WHERE id = @id`).run(values);
|
|
135
|
+
}
|
|
136
|
+
async getBroadcastRunsDue() {
|
|
137
|
+
const now = new Date().toISOString();
|
|
138
|
+
const rows = this.db.prepare(`
|
|
139
|
+
SELECT * FROM ${this.runsTable}
|
|
140
|
+
WHERE status = 'pending'
|
|
141
|
+
AND (next_run_at IS NULL OR next_run_at <= ?)
|
|
142
|
+
ORDER BY created_at ASC
|
|
143
|
+
`).all(now);
|
|
144
|
+
return rows.map(rowToBroadcastRun);
|
|
145
|
+
}
|
|
146
|
+
async getBroadcastRunsRunning() {
|
|
147
|
+
const rows = this.db.prepare(`SELECT * FROM ${this.runsTable} WHERE status = 'running'`).all();
|
|
148
|
+
return rows.map(rowToBroadcastRun);
|
|
149
|
+
}
|
|
150
|
+
async listBroadcastRuns(broadcastName) {
|
|
151
|
+
const rows = this.db.prepare(`SELECT * FROM ${this.runsTable} WHERE broadcast_name = ? ORDER BY created_at DESC`).all(broadcastName);
|
|
152
|
+
return rows.map(rowToBroadcastRun);
|
|
153
|
+
}
|
|
154
|
+
async hasBroadcastRunWithStatus(broadcastName, statuses) {
|
|
155
|
+
if (statuses.length === 0)
|
|
156
|
+
return false;
|
|
157
|
+
const placeholders = statuses.map(() => "?").join(", ");
|
|
158
|
+
const row = this.db.prepare(`SELECT 1 FROM ${this.runsTable} WHERE broadcast_name = ? AND status IN (${placeholders}) LIMIT 1`).get(broadcastName, ...statuses);
|
|
159
|
+
return row !== undefined;
|
|
160
|
+
}
|
|
161
|
+
async purgeBroadcastRuns(olderThan, statuses) {
|
|
162
|
+
if (statuses.length === 0)
|
|
163
|
+
return 0;
|
|
164
|
+
const placeholders = statuses.map(() => "?").join(", ");
|
|
165
|
+
const cutoff = olderThan.toISOString();
|
|
166
|
+
const result = this.db.prepare(`DELETE FROM ${this.runsTable} WHERE status IN (${placeholders}) AND completed_at IS NOT NULL AND completed_at < ?`).run(...statuses, cutoff);
|
|
167
|
+
return result.changes;
|
|
168
|
+
}
|
|
169
|
+
async addNodeRun(nodeRun) {
|
|
170
|
+
this.db.prepare(`
|
|
171
|
+
INSERT INTO ${this.nodesTable}
|
|
172
|
+
(id, broadcast_run_id, node_name, signal_name, signal_run_id,
|
|
173
|
+
status, skip_reason, input, output, error, started_at, completed_at)
|
|
174
|
+
VALUES
|
|
175
|
+
(@id, @broadcast_run_id, @node_name, @signal_name, @signal_run_id,
|
|
176
|
+
@status, @skip_reason, @input, @output, @error, @started_at, @completed_at)
|
|
177
|
+
`).run({
|
|
178
|
+
id: nodeRun.id,
|
|
179
|
+
broadcast_run_id: nodeRun.broadcastRunId,
|
|
180
|
+
node_name: nodeRun.nodeName,
|
|
181
|
+
signal_name: nodeRun.signalName,
|
|
182
|
+
signal_run_id: nodeRun.signalRunId ?? null,
|
|
183
|
+
status: nodeRun.status,
|
|
184
|
+
skip_reason: nodeRun.skipReason ?? null,
|
|
185
|
+
input: nodeRun.input ?? null,
|
|
186
|
+
output: nodeRun.output ?? null,
|
|
187
|
+
error: nodeRun.error ?? null,
|
|
188
|
+
started_at: dateToStr(nodeRun.startedAt),
|
|
189
|
+
completed_at: dateToStr(nodeRun.completedAt),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async getNodeRun(id) {
|
|
193
|
+
const row = this.db.prepare(`SELECT * FROM ${this.nodesTable} WHERE id = ?`).get(id);
|
|
194
|
+
return row ? rowToNodeRun(row) : null;
|
|
195
|
+
}
|
|
196
|
+
static NODE_RUN_PATCH_KEYS = new Set([
|
|
197
|
+
"signalRunId", "status", "skipReason", "input", "output", "error", "startedAt", "completedAt",
|
|
198
|
+
]);
|
|
199
|
+
async updateNodeRun(id, patch) {
|
|
200
|
+
const setClauses = [];
|
|
201
|
+
const values = { id };
|
|
202
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
203
|
+
if (!BroadcastSqliteAdapter.NODE_RUN_PATCH_KEYS.has(key))
|
|
204
|
+
continue;
|
|
205
|
+
const col = toNodeRunCol(key);
|
|
206
|
+
const param = `p_${col}`;
|
|
207
|
+
setClauses.push(`${col} = @${param}`);
|
|
208
|
+
if (value === undefined) {
|
|
209
|
+
values[param] = null;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
values[param] = NODE_RUN_DATE_FIELDS.has(key) ? dateToStr(value) : value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (setClauses.length === 0)
|
|
216
|
+
return;
|
|
217
|
+
this.db.prepare(`UPDATE ${this.nodesTable} SET ${setClauses.join(", ")} WHERE id = @id`).run(values);
|
|
218
|
+
}
|
|
219
|
+
async getNodeRuns(broadcastRunId) {
|
|
220
|
+
const rows = this.db.prepare(`SELECT * FROM ${this.nodesTable} WHERE broadcast_run_id = ?`).all(broadcastRunId);
|
|
221
|
+
return rows.map(rowToNodeRun);
|
|
222
|
+
}
|
|
223
|
+
generateId() {
|
|
224
|
+
return randomUUID();
|
|
225
|
+
}
|
|
226
|
+
async ping() {
|
|
227
|
+
try {
|
|
228
|
+
this.db.prepare("SELECT 1").get();
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async close() {
|
|
236
|
+
this.db.close();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=broadcast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SerializableAdapter, AdapterManifest, Run, RunPatch, RunStatus, Step, StepPatch } from "station-signal";
|
|
2
|
+
export interface SqliteAdapterOptions {
|
|
3
|
+
/** Path to the SQLite database file. Defaults to `"station.db"`. */
|
|
4
|
+
dbPath?: string;
|
|
5
|
+
/** Table name (alphanumeric and underscores only). Defaults to `"runs"`. */
|
|
6
|
+
tableName?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class SqliteAdapter implements SerializableAdapter {
|
|
9
|
+
private db;
|
|
10
|
+
private tableName;
|
|
11
|
+
private options;
|
|
12
|
+
constructor(options?: SqliteAdapterOptions);
|
|
13
|
+
toManifest(): AdapterManifest;
|
|
14
|
+
addRun(run: Run): Promise<void>;
|
|
15
|
+
removeRun(id: string): Promise<void>;
|
|
16
|
+
getRunsDue(): Promise<Run[]>;
|
|
17
|
+
getRunsRunning(): Promise<Run[]>;
|
|
18
|
+
getRun(id: string): Promise<Run | null>;
|
|
19
|
+
/** Allowed RunPatch keys (L13: whitelist to prevent injection via unexpected keys). */
|
|
20
|
+
private static readonly RUN_PATCH_KEYS;
|
|
21
|
+
updateRun(id: string, patch: RunPatch): Promise<void>;
|
|
22
|
+
listRuns(signalName: string): Promise<Run[]>;
|
|
23
|
+
hasRunWithStatus(signalName: string, statuses: RunStatus[]): Promise<boolean>;
|
|
24
|
+
purgeRuns(olderThan: Date, statuses: RunStatus[]): Promise<number>;
|
|
25
|
+
addStep(step: Step): Promise<void>;
|
|
26
|
+
/** Allowed StepPatch keys. */
|
|
27
|
+
private static readonly STEP_PATCH_KEYS;
|
|
28
|
+
updateStep(id: string, patch: StepPatch): Promise<void>;
|
|
29
|
+
getSteps(runId: string): Promise<Step[]>;
|
|
30
|
+
removeSteps(runId: string): Promise<void>;
|
|
31
|
+
ping(): Promise<boolean>;
|
|
32
|
+
generateId(): string;
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAgCtH,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,aAAc,YAAW,mBAAmB;IACvD,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAuB;gBAE1B,OAAO,GAAE,oBAAyB;IA2E9C,UAAU,IAAI,eAAe;IAQvB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC/B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAc5B,cAAc,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAQhC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAQ7C,uFAAuF;IACvF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAGnC;IAEG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BrD,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAU5C,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAW7E,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAalE,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxC,8BAA8B;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAEpC;IAEG,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BvD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAQxC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAS9B,UAAU,IAAI,MAAM;IAId,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|