@fungi.computer/watchdog 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +334 -2
- package/dist/d1.d.ts +36 -0
- package/dist/d1.js +41 -0
- package/dist/effect.d.ts +336 -0
- package/dist/effect.js +140 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +41 -0
- package/dist/internal/async-runtime.d.ts +17 -0
- package/dist/internal/async-runtime.js +39 -0
- package/dist/internal/async-sql.d.ts +15 -0
- package/dist/internal/async-sql.js +66 -0
- package/dist/internal/async-store.d.ts +58 -0
- package/dist/internal/async-store.js +235 -0
- package/dist/internal/identities.d.ts +3 -0
- package/dist/internal/identities.js +8 -0
- package/dist/internal/lane.d.ts +3 -0
- package/dist/internal/lane.js +6 -0
- package/dist/internal/promise-watchdog-host.d.ts +4 -0
- package/dist/internal/promise-watchdog-host.js +25 -0
- package/dist/internal/runtime.d.ts +3 -0
- package/dist/internal/runtime.js +199 -0
- package/dist/internal/sqlite-store.d.ts +107 -0
- package/dist/internal/sqlite-store.js +478 -0
- package/dist/internal/watchdog-error.d.ts +12 -0
- package/dist/internal/watchdog-error.js +17 -0
- package/dist/node-sqlite.d.ts +17 -0
- package/dist/node-sqlite.js +63 -0
- package/dist/postgres.d.ts +22 -0
- package/dist/postgres.js +31 -0
- package/docs/api/README.md +17 -0
- package/docs/api/d1.md +162 -0
- package/docs/api/effect.md +875 -0
- package/docs/api/index.md +421 -0
- package/docs/api/node-sqlite.md +57 -0
- package/docs/api/postgres.md +102 -0
- package/package.json +78 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
import { watchdogSqliteRowSchema } from "./effect.js";
|
|
3
|
+
const decodeRow = Schema.decodeUnknownSync(watchdogSqliteRowSchema);
|
|
4
|
+
function fromSqlite(value) {
|
|
5
|
+
if (Schema.is(Schema.BigInt)(value))
|
|
6
|
+
return Number(value);
|
|
7
|
+
if (ArrayBuffer.isView(value))
|
|
8
|
+
return new Uint8Array(value).slice().buffer;
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
/** Adapt a caller-owned Node SQLite database; the caller retains its lifetime. */
|
|
12
|
+
export function fromNodeSqlite(database) {
|
|
13
|
+
let transaction = 0;
|
|
14
|
+
return {
|
|
15
|
+
sql: {
|
|
16
|
+
exec: (statement, ...bindings) => {
|
|
17
|
+
const prepared = database.prepare(statement);
|
|
18
|
+
const values = bindings.map((value) => value instanceof ArrayBuffer ? new Uint8Array(value) : value);
|
|
19
|
+
let rows;
|
|
20
|
+
if (prepared.columns().length > 0) {
|
|
21
|
+
rows = prepared
|
|
22
|
+
.all(...values)
|
|
23
|
+
.map((row) => decodeRow(Object.fromEntries(Object.entries(row).map(([key, value]) => [
|
|
24
|
+
key,
|
|
25
|
+
fromSqlite(value),
|
|
26
|
+
]))));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Schema owners supply several unbound DDL statements in one call.
|
|
30
|
+
// DatabaseSync.exec owns that grammar; prepare/run executes only one.
|
|
31
|
+
if (values.length === 0)
|
|
32
|
+
database.exec(statement);
|
|
33
|
+
else
|
|
34
|
+
prepared.run(...values);
|
|
35
|
+
rows = [];
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
toArray: () => rows,
|
|
39
|
+
one: () => {
|
|
40
|
+
const row = rows[0];
|
|
41
|
+
if (rows.length !== 1 || row === undefined)
|
|
42
|
+
throw new Error(`Expected exactly one SQLite row; got ${String(rows.length)}`);
|
|
43
|
+
return row;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
transactionSync: (operation) => {
|
|
49
|
+
const name = `watchdog_owner_${String(transaction++)}`;
|
|
50
|
+
database.exec(`SAVEPOINT ${name}`);
|
|
51
|
+
try {
|
|
52
|
+
const result = operation();
|
|
53
|
+
database.exec(`RELEASE ${name}`);
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
catch (cause) {
|
|
57
|
+
database.exec(`ROLLBACK TO ${name}`);
|
|
58
|
+
database.exec(`RELEASE ${name}`);
|
|
59
|
+
throw cause;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Pool, PoolClient } from "pg";
|
|
2
|
+
import type { WatchdogQueuedJob } from "./effect.js";
|
|
3
|
+
import { type AsyncWatchdogOptions, type AsyncWatchdogRuntime } from "./internal/async-runtime.js";
|
|
4
|
+
export type { AsyncWatchdogOptions, AsyncWatchdogRuntime, } from "./internal/async-runtime.js";
|
|
5
|
+
/** PostgreSQL runtime with admission joined to the caller's checked-out client. */
|
|
6
|
+
export type PostgresWatchdog = AsyncWatchdogRuntime & Readonly<{
|
|
7
|
+
/** Enqueue on the existing transaction; never BEGIN, COMMIT or ROLLBACK here. */
|
|
8
|
+
enqueue: (client: Pick<PoolClient, "query">, job: WatchdogQueuedJob) => Promise<void>;
|
|
9
|
+
}>;
|
|
10
|
+
/** Package-owned schema statements, to run through the deployment migration owner. */
|
|
11
|
+
export declare const watchdogPostgresSchema: readonly string[];
|
|
12
|
+
/** Open the shared Effect engine on a migrated PostgreSQL database. */
|
|
13
|
+
export declare function createPostgresWatchdog(options: AsyncWatchdogOptions & Readonly<{
|
|
14
|
+
database: Pick<Pool, "query">;
|
|
15
|
+
}>): PostgresWatchdog;
|
|
16
|
+
/** Parameterized queue purge joined to a producer's existing PostgreSQL transaction. */
|
|
17
|
+
export type PostgresPurgeStatement = Readonly<{
|
|
18
|
+
text: string;
|
|
19
|
+
values: readonly (string | number | null)[];
|
|
20
|
+
}>;
|
|
21
|
+
/** Purge every attempt in the queues yielded by trusted producer SQL. */
|
|
22
|
+
export declare function purgePostgresQueues(source: PostgresPurgeStatement): readonly PostgresPurgeStatement[];
|
package/dist/postgres.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createAsyncRuntime, } from "./internal/async-runtime.js";
|
|
2
|
+
import { enqueueStatement, schemaStatements, } from "./internal/async-sql.js";
|
|
3
|
+
/** Package-owned schema statements, to run through the deployment migration owner. */
|
|
4
|
+
export const watchdogPostgresSchema = schemaStatements(true);
|
|
5
|
+
/** Open the shared Effect engine on a migrated PostgreSQL database. */
|
|
6
|
+
export function createPostgresWatchdog(options) {
|
|
7
|
+
const runtime = createAsyncRuntime({
|
|
8
|
+
clock: options.now === undefined
|
|
9
|
+
? "EXTRACT(EPOCH FROM clock_timestamp())*1000"
|
|
10
|
+
: undefined,
|
|
11
|
+
query: async (statement) => (await options.database.query(statement.text, [
|
|
12
|
+
...statement.values,
|
|
13
|
+
])).rows,
|
|
14
|
+
}, options);
|
|
15
|
+
return {
|
|
16
|
+
...runtime,
|
|
17
|
+
enqueue: async (client, job) => {
|
|
18
|
+
const statement = enqueueStatement(job);
|
|
19
|
+
await client.query(statement.text, [...statement.values]);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Purge every attempt in the queues yielded by trusted producer SQL. */
|
|
24
|
+
export function purgePostgresQueues(source) {
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
text: `DELETE FROM watchdog_jobs WHERE queue_name IN (SELECT queue_name FROM (${source.text}) AS erasure)`,
|
|
28
|
+
values: source.values,
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
**@fungi.computer/watchdog**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# @fungi.computer/watchdog
|
|
8
|
+
|
|
9
|
+
## Modules
|
|
10
|
+
|
|
11
|
+
| Module | Description |
|
|
12
|
+
| ----------------------------- | ----------- |
|
|
13
|
+
| [d1](d1.md) | - |
|
|
14
|
+
| [effect](effect.md) | - |
|
|
15
|
+
| [index](index.md) | - |
|
|
16
|
+
| [node-sqlite](node-sqlite.md) | - |
|
|
17
|
+
| [postgres](postgres.md) | - |
|
package/docs/api/d1.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
[**@fungi.computer/watchdog**](README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[@fungi.computer/watchdog](README.md) / d1
|
|
8
|
+
|
|
9
|
+
# d1
|
|
10
|
+
|
|
11
|
+
## Type Aliases
|
|
12
|
+
|
|
13
|
+
### D1AdmissionSource
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
type D1AdmissionSource = Readonly<{
|
|
17
|
+
text: string;
|
|
18
|
+
values: readonly (string | number | null)[];
|
|
19
|
+
}>;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Trusted parameter-bound SELECT yielding queued job fields; never lifecycle
|
|
23
|
+
fields.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
### D1Admission
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
type D1Admission = Readonly<{
|
|
31
|
+
enqueue: (job) => D1PreparedStatement;
|
|
32
|
+
enqueueFromSelect: (source) => D1PreparedStatement;
|
|
33
|
+
}>;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
D1 runtime with admission statements that join the producer's native batch.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### D1Watchdog
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
type D1Watchdog = AsyncWatchdogRuntime & D1Admission;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
D1 lifecycle and native transaction admission.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### D1PurgeStatement
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
type D1PurgeStatement = Readonly<{
|
|
54
|
+
text: string;
|
|
55
|
+
values: readonly (string | number | null)[];
|
|
56
|
+
}>;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Parameterized native purge; caller commits it with its own erasure facts.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### AsyncWatchdogOptions
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
type AsyncWatchdogOptions = Readonly<{
|
|
67
|
+
execute: WatchdogExecutor;
|
|
68
|
+
wake: Readonly<{
|
|
69
|
+
recompute: () => Promise<void>;
|
|
70
|
+
}>;
|
|
71
|
+
now?: () => number;
|
|
72
|
+
}>;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Host execution and wake scheduling for a shared-database Watchdog.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### AsyncWatchdogRuntime
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
type AsyncWatchdogRuntime = Omit<WatchdogRuntime, "transactional">;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Shared-database runtime; native admission replaces the SQLite projection.
|
|
86
|
+
|
|
87
|
+
## Variables
|
|
88
|
+
|
|
89
|
+
### watchdogD1Schema
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const watchdogD1Schema: readonly string[];
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Package-owned schema statements, to run through the deployment migration owner.
|
|
96
|
+
|
|
97
|
+
## Functions
|
|
98
|
+
|
|
99
|
+
### createD1Watchdog()
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
function createD1Watchdog(options): D1Watchdog;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Open the shared Effect engine on a migrated D1 database; no implicit schema
|
|
106
|
+
writes.
|
|
107
|
+
|
|
108
|
+
#### Parameters
|
|
109
|
+
|
|
110
|
+
| Parameter | Type |
|
|
111
|
+
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
112
|
+
| `options` | `Readonly`\<\{ `execute`: [`WatchdogExecutor`](index.md#watchdogexecutor); `wake`: `Readonly`\<\{ `recompute`: () => `Promise`\<`void`\>; \}\>; `now?`: () => `number`; \}\> & `Readonly`\<\{ `database`: `D1Database`; \}\> |
|
|
113
|
+
|
|
114
|
+
#### Returns
|
|
115
|
+
|
|
116
|
+
[`D1Watchdog`](#d1watchdog)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### prepareD1Admission()
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
function prepareD1Admission(database): D1Admission;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Prepare native admission without constructing an executor or performing I/O.
|
|
127
|
+
|
|
128
|
+
#### Parameters
|
|
129
|
+
|
|
130
|
+
| Parameter | Type |
|
|
131
|
+
| ---------- | ------------ |
|
|
132
|
+
| `database` | `D1Database` |
|
|
133
|
+
|
|
134
|
+
#### Returns
|
|
135
|
+
|
|
136
|
+
[`D1Admission`](#d1admission)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### purgeD1Queues()
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
function purgeD1Queues(source): readonly Readonly<{
|
|
144
|
+
text: string;
|
|
145
|
+
values: readonly (string | number | null)[];
|
|
146
|
+
}>[];
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Purge every attempt in selected queues, fencing any executor still holding a
|
|
150
|
+
claim. The trusted SELECT yields queue_name. It never supplies lifecycle
|
|
151
|
+
mutations.
|
|
152
|
+
|
|
153
|
+
#### Parameters
|
|
154
|
+
|
|
155
|
+
| Parameter | Type |
|
|
156
|
+
| --------- | --------------------------------------- |
|
|
157
|
+
| `source` | [`D1PurgeStatement`](#d1purgestatement) |
|
|
158
|
+
|
|
159
|
+
#### Returns
|
|
160
|
+
|
|
161
|
+
readonly `Readonly`\<\{ `text`: `string`; `values`: readonly (`string` \|
|
|
162
|
+
`number` \| `null`)[]; \}\>[]
|