@haikit/postgres 0.14.0 → 0.16.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/README.md +23 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +132 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +145 -14
package/README.md
CHANGED
|
@@ -52,11 +52,11 @@ With your own migration tool, apply the new `ALTER TABLE` from `schema` before
|
|
|
52
52
|
deploying. Rows written before the column existed are held to the window your
|
|
53
53
|
code declares.
|
|
54
54
|
|
|
55
|
-
**Upgrading to 0.
|
|
55
|
+
**Upgrading to 0.13:** `migrate()` adds `haikit_notices`, and `notice_seq` and
|
|
56
56
|
`noticed_through` to `haikit_conversations`, for `hai.notify`. As before, if
|
|
57
57
|
you call `migrate()` at startup there is nothing to do.
|
|
58
58
|
|
|
59
|
-
**Upgrading to 0.
|
|
59
|
+
**Upgrading to 0.14:** `migrate()` adds `kind` to `haikit_notices`, and
|
|
60
60
|
`wakes` and `woke_through` to `haikit_conversations`, for wake notices.
|
|
61
61
|
|
|
62
62
|
Handles are numbered per conversation, so every conversation's digests start at
|
|
@@ -92,6 +92,27 @@ const store = pgStore(pool, {
|
|
|
92
92
|
A notice belongs to its conversation and goes when it does: deleting a
|
|
93
93
|
conversation deletes its notices. `sweepOrphans` never touches them.
|
|
94
94
|
|
|
95
|
+
## Wake turns across servers
|
|
96
|
+
|
|
97
|
+
With several app servers, the same `listen` connection carries a wake turn
|
|
98
|
+
from the server running it to the others, so a browser connected to any of
|
|
99
|
+
them sees the reply. `publish` sends each of the turn's frames as `NOTIFY`
|
|
100
|
+
on `haikit_turns`. A frame longer than one `NOTIFY` can hold (just under
|
|
101
|
+
8,000 bytes) goes as several, sent in one statement, and is put back
|
|
102
|
+
together on arrival. Frames are sent one at a time per conversation, each
|
|
103
|
+
committed before the next, so they arrive in order. Every store can publish;
|
|
104
|
+
only one given `listen` hears. A message past `MAX_PUBLISH_BYTES` (about
|
|
105
|
+
52 MB, far beyond any frame) is refused, not sent.
|
|
106
|
+
|
|
107
|
+
**Upgrading:** `migrate()` adds `wake_turns` to `haikit_conversations`, each
|
|
108
|
+
conversation's count of wake turns, which numbers them so a late frame from
|
|
109
|
+
an older turn can't take over from a newer one.
|
|
110
|
+
|
|
111
|
+
It is best effort, as `NOTIFY` is: a server whose listening connection is
|
|
112
|
+
down misses those frames, and a tab there sees the reply when it next
|
|
113
|
+
reconnects to a server that has it, or not at all. The frames themselves
|
|
114
|
+
are never stored, so there is nothing of them to clean up.
|
|
115
|
+
|
|
95
116
|
## Cleaning up
|
|
96
117
|
|
|
97
118
|
A turn that is overtaken mid-flight can leave payload rows that the surviving
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,10 @@ export interface Listener {
|
|
|
49
49
|
}
|
|
50
50
|
/** The channel `putNotice` notifies on, with the conversation id as payload. */
|
|
51
51
|
export declare const NOTICE_CHANNEL = "haikit_notices";
|
|
52
|
+
/** The channel `publish` carries messages on, in pieces small enough for NOTIFY. */
|
|
53
|
+
export declare const TURN_CHANNEL = "haikit_turns";
|
|
54
|
+
/** The longest message `publish` takes, in UTF-8 bytes: what MAX_PIECES pieces of base64 hold. */
|
|
55
|
+
export declare const MAX_PUBLISH_BYTES: number;
|
|
52
56
|
/**
|
|
53
57
|
* The schema, one statement per entry. `migrate()` runs these; export them to
|
|
54
58
|
* your own migration tool instead if you have one.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChF;AAID,gFAAgF;AAChF,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChF;AAID,gFAAgF;AAChF,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,oFAAoF;AACpF,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAc3C,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAE1E;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,MAAM,EAiEnC,CAAC;AAEF,8FAA8F;AAC9F,wBAAsB,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAI1D;AAmED,wBAAgB,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,cAAmB,GAAG,YAAY,CAoWjF;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAYrG"}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,19 @@ import { ConversationBusy, StaleLease, } from "@haikit/core";
|
|
|
14
14
|
const LEASE_MS = 120_000;
|
|
15
15
|
/** The channel `putNotice` notifies on, with the conversation id as payload. */
|
|
16
16
|
export const NOTICE_CHANNEL = "haikit_notices";
|
|
17
|
+
/** The channel `publish` carries messages on, in pieces small enough for NOTIFY. */
|
|
18
|
+
export const TURN_CHANNEL = "haikit_turns";
|
|
19
|
+
/**
|
|
20
|
+
* The most of a message one NOTIFY carries. Postgres refuses payloads of 8000
|
|
21
|
+
* bytes or more; a piece is ASCII, so this leaves room for its header.
|
|
22
|
+
*/
|
|
23
|
+
const PIECE = 7_000;
|
|
24
|
+
/** How long half a message waits for the rest before it is given up on. */
|
|
25
|
+
const PIECE_TIMEOUT_MS = 30_000;
|
|
26
|
+
/** The most pieces one message may claim to have: about 52 MB of message, far past any frame. */
|
|
27
|
+
const MAX_PIECES = 10_000;
|
|
28
|
+
/** The longest message `publish` takes, in UTF-8 bytes: what MAX_PIECES pieces of base64 hold. */
|
|
29
|
+
export const MAX_PUBLISH_BYTES = Math.floor((PIECE * MAX_PIECES * 3) / 4);
|
|
17
30
|
/**
|
|
18
31
|
* The schema, one statement per entry. `migrate()` runs these; export them to
|
|
19
32
|
* your own migration tool instead if you have one.
|
|
@@ -35,6 +48,8 @@ export const schema = [
|
|
|
35
48
|
-- when recent wake turns started, and the last notice that may no longer start one
|
|
36
49
|
wakes jsonb NOT NULL DEFAULT '[]',
|
|
37
50
|
woke_through integer NOT NULL DEFAULT 0,
|
|
51
|
+
-- how many wake turns it has started, to tell an older turn's frames from a newer's
|
|
52
|
+
wake_turns integer NOT NULL DEFAULT 0,
|
|
38
53
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
39
54
|
)`,
|
|
40
55
|
// a table created before notices existed gains the columns
|
|
@@ -42,6 +57,7 @@ export const schema = [
|
|
|
42
57
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS noticed_through integer NOT NULL DEFAULT 0`,
|
|
43
58
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS wakes jsonb NOT NULL DEFAULT '[]'`,
|
|
44
59
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS woke_through integer NOT NULL DEFAULT 0`,
|
|
60
|
+
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS wake_turns integer NOT NULL DEFAULT 0`,
|
|
45
61
|
// Append-only, and never an orphan: a notice belongs to a conversation that
|
|
46
62
|
// exists, and goes when it does.
|
|
47
63
|
`CREATE TABLE IF NOT EXISTS haikit_notices (
|
|
@@ -95,7 +111,7 @@ export async function migrate(db) {
|
|
|
95
111
|
const CONVERSATION_COLUMNS = `
|
|
96
112
|
id, status, messages::text AS messages, handles::text AS handles,
|
|
97
113
|
frozen::text AS frozen, pending::text AS pending, lease_token, noticed_through,
|
|
98
|
-
wakes::text AS wakes, woke_through,
|
|
114
|
+
wakes::text AS wakes, woke_through, wake_turns,
|
|
99
115
|
(extract(epoch FROM lease_until) * 1000)::float8 AS lease_until_ms`;
|
|
100
116
|
const NOTICE_COLUMNS = `
|
|
101
117
|
conversation_id, seq, name, version, payload::text AS payload, model, handle, kind,
|
|
@@ -119,6 +135,7 @@ const toConversation = (row) => ({
|
|
|
119
135
|
noticedThrough: Number(row.noticed_through ?? 0),
|
|
120
136
|
wakes: row.wakes == null ? [] : json(row.wakes),
|
|
121
137
|
wokeThrough: Number(row.woke_through ?? 0),
|
|
138
|
+
wakeTurns: Number(row.wake_turns ?? 0),
|
|
122
139
|
});
|
|
123
140
|
const toNotice = (row) => ({
|
|
124
141
|
conversationId: row.conversation_id,
|
|
@@ -152,20 +169,118 @@ export function pgStore(db, options = {}) {
|
|
|
152
169
|
if (!Number.isFinite(leaseMs) || leaseMs <= 0) {
|
|
153
170
|
throw new RangeError(`leaseMs must be a positive, finite number of milliseconds (got ${leaseMs})`);
|
|
154
171
|
}
|
|
155
|
-
// One LISTEN for the whole store, taken when something first
|
|
156
|
-
// each notification handed to whoever
|
|
172
|
+
// One LISTEN per channel for the whole store, taken when something first
|
|
173
|
+
// needs it, and each notification handed to whoever wants that conversation.
|
|
157
174
|
const waiting = new Map();
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
.
|
|
175
|
+
const listening = new Map();
|
|
176
|
+
const listenOn = (listener, channel, onNotify) => {
|
|
177
|
+
let started = listening.get(channel);
|
|
178
|
+
if (!started) {
|
|
179
|
+
started = listener.listen(channel, onNotify).catch((err) => {
|
|
180
|
+
// try again next time, rather than never
|
|
181
|
+
listening.delete(channel);
|
|
182
|
+
throw err;
|
|
183
|
+
});
|
|
184
|
+
listening.set(channel, started);
|
|
185
|
+
}
|
|
186
|
+
return started;
|
|
187
|
+
};
|
|
188
|
+
const listen = (listener) => listenOn(listener, NOTICE_CHANNEL, (id) => {
|
|
161
189
|
for (const wake of waiting.get(id) ?? [])
|
|
162
190
|
wake();
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
191
|
+
});
|
|
192
|
+
// ── publish / subscribe, over NOTIFY ───────────────────────────────────
|
|
193
|
+
// A message goes out as pieces of at most PIECE base64 characters, each
|
|
194
|
+
// `<conversation> <message id> <index> <count> <piece>`, all in one
|
|
195
|
+
// statement, and is put back together on the way in. Messages from this
|
|
196
|
+
// store are sent one at a time per conversation, each committed before the
|
|
197
|
+
// next starts, so they arrive in the order they were published.
|
|
198
|
+
const hearing = new Map();
|
|
199
|
+
const partial = new Map();
|
|
200
|
+
const sending = new Map();
|
|
201
|
+
const onTurn = (payload) => {
|
|
202
|
+
const [conversationId, id, index, count, piece] = String(payload).split(" ");
|
|
203
|
+
if (!hearing.has(conversationId))
|
|
204
|
+
return;
|
|
205
|
+
// The channel is shared, and anything may NOTIFY on it: a piece that
|
|
206
|
+
// doesn't hold together is dropped, never let throw out of the listener.
|
|
207
|
+
const n = Number(count);
|
|
208
|
+
const i = Number(index);
|
|
209
|
+
if (!id || !Number.isSafeInteger(n) || n < 1 || n > MAX_PIECES || !Number.isSafeInteger(i) || i < 0 || i >= n)
|
|
210
|
+
return;
|
|
211
|
+
const known = partial.get(id);
|
|
212
|
+
if (known && known.pieces.length !== n)
|
|
213
|
+
return;
|
|
214
|
+
let entry = known;
|
|
215
|
+
if (!entry) {
|
|
216
|
+
// A message whose other pieces never come (a listening connection that
|
|
217
|
+
// dropped part way) is given up on after a while, whatever else arrives.
|
|
218
|
+
const expire = setTimeout(() => partial.delete(id), PIECE_TIMEOUT_MS);
|
|
219
|
+
// and is no reason to keep the process alive
|
|
220
|
+
expire.unref?.();
|
|
221
|
+
entry = { pieces: new Array(n), got: 0, expire };
|
|
222
|
+
}
|
|
223
|
+
if (entry.pieces[i] === undefined)
|
|
224
|
+
entry.got++;
|
|
225
|
+
entry.pieces[i] = piece ?? "";
|
|
226
|
+
if (entry.got < n)
|
|
227
|
+
return void partial.set(id, entry);
|
|
228
|
+
clearTimeout(entry.expire);
|
|
229
|
+
partial.delete(id);
|
|
230
|
+
let message;
|
|
231
|
+
try {
|
|
232
|
+
message = new TextDecoder("utf-8", { fatal: true }).decode(Uint8Array.from(atob(entry.pieces.join("")), (c) => c.charCodeAt(0)));
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return; // not base64, or not UTF-8 once decoded: not one of ours
|
|
236
|
+
}
|
|
237
|
+
for (const hear of [...(hearing.get(conversationId) ?? [])])
|
|
238
|
+
hear(message);
|
|
239
|
+
};
|
|
240
|
+
async function publish(conversationId, message) {
|
|
241
|
+
const bytes = new TextEncoder().encode(String(message));
|
|
242
|
+
// Refused here rather than sent and dropped by every listener, and before
|
|
243
|
+
// any of the work of encoding it.
|
|
244
|
+
if (bytes.length > MAX_PUBLISH_BYTES) {
|
|
245
|
+
throw new RangeError(`message too long to publish: ${bytes.length} bytes, over the ${MAX_PUBLISH_BYTES}-byte maximum`);
|
|
246
|
+
}
|
|
247
|
+
let binary = "";
|
|
248
|
+
for (const b of bytes)
|
|
249
|
+
binary += String.fromCharCode(b);
|
|
250
|
+
const encoded = btoa(binary);
|
|
251
|
+
const id = newToken().replaceAll("-", "");
|
|
252
|
+
const count = Math.max(1, Math.ceil(encoded.length / PIECE));
|
|
253
|
+
const pieces = Array.from({ length: count }, (_, i) => `${conversationId} ${id} ${i} ${count} ${encoded.slice(i * PIECE, (i + 1) * PIECE)}`);
|
|
254
|
+
const before = sending.get(conversationId) ?? Promise.resolve();
|
|
255
|
+
const sent = before.then(() => db.query(`SELECT pg_notify('${TURN_CHANNEL}', piece) FROM jsonb_array_elements_text($1::jsonb) AS piece`, [
|
|
256
|
+
JSON.stringify(pieces),
|
|
257
|
+
]));
|
|
258
|
+
const settled = sent.then(() => { }, () => { });
|
|
259
|
+
sending.set(conversationId, settled);
|
|
260
|
+
try {
|
|
261
|
+
await sent;
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
if (sending.get(conversationId) === settled)
|
|
265
|
+
sending.delete(conversationId);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async function subscribe(conversationId, onMessage, signal) {
|
|
269
|
+
if (signal.aborted)
|
|
270
|
+
return;
|
|
271
|
+
const set = hearing.get(conversationId) ?? new Set();
|
|
272
|
+
set.add(onMessage);
|
|
273
|
+
hearing.set(conversationId, set);
|
|
274
|
+
signal.addEventListener("abort", () => {
|
|
275
|
+
set.delete(onMessage);
|
|
276
|
+
if (!set.size && hearing.get(conversationId) === set)
|
|
277
|
+
hearing.delete(conversationId);
|
|
278
|
+
}, { once: true });
|
|
279
|
+
// Resolves once LISTEN has taken hold, so nothing published after this
|
|
280
|
+
// resolves is missed. Best effort, as the contract says: a failed LISTEN
|
|
281
|
+
// is tried again next time, and this resolves all the same.
|
|
282
|
+
await listenOn(options.listen, TURN_CHANNEL, onTurn).catch(() => { });
|
|
283
|
+
}
|
|
169
284
|
async function* watch(conversationId, signal) {
|
|
170
285
|
// One wake-up stands for any number of notices: a step resolves once
|
|
171
286
|
// something has landed since the last, and the caller reads them all.
|
|
@@ -250,6 +365,7 @@ export function pgStore(db, options = {}) {
|
|
|
250
365
|
noticed_through = $9::integer,
|
|
251
366
|
wakes = $10::jsonb,
|
|
252
367
|
woke_through = $11::integer,
|
|
368
|
+
wake_turns = $12::integer,
|
|
253
369
|
updated_at = now()
|
|
254
370
|
WHERE id = $1 AND lease_token = $2
|
|
255
371
|
RETURNING id`, [
|
|
@@ -265,6 +381,7 @@ export function pgStore(db, options = {}) {
|
|
|
265
381
|
conversation.noticedThrough ?? 0,
|
|
266
382
|
JSON.stringify(conversation.wakes ?? []),
|
|
267
383
|
conversation.wokeThrough ?? 0,
|
|
384
|
+
conversation.wakeTurns ?? 0,
|
|
268
385
|
]);
|
|
269
386
|
if (!rows.length)
|
|
270
387
|
await stale(conversation.id);
|
|
@@ -362,7 +479,9 @@ export function pgStore(db, options = {}) {
|
|
|
362
479
|
const exists = await db.query(`SELECT 1 FROM haikit_conversations WHERE id = $1`, [conversationId]);
|
|
363
480
|
return exists.rows.length ? [] : null;
|
|
364
481
|
},
|
|
365
|
-
|
|
482
|
+
// Anyone can publish; hearing it takes a LISTEN connection.
|
|
483
|
+
publish,
|
|
484
|
+
...(options.listen ? { watch, subscribe } : {}),
|
|
366
485
|
};
|
|
367
486
|
}
|
|
368
487
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haikit/postgres",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Postgres store adapter for haikit: durable conversations, fenced turn leases, write-once payloads. Bring your own driver.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"haikit",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"prepack": "npm --prefix ../.. run build"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@haikit/core": "0.
|
|
37
|
+
"@haikit/core": "0.16.0"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -62,6 +62,24 @@ const LEASE_MS = 120_000;
|
|
|
62
62
|
/** The channel `putNotice` notifies on, with the conversation id as payload. */
|
|
63
63
|
export const NOTICE_CHANNEL = "haikit_notices";
|
|
64
64
|
|
|
65
|
+
/** The channel `publish` carries messages on, in pieces small enough for NOTIFY. */
|
|
66
|
+
export const TURN_CHANNEL = "haikit_turns";
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The most of a message one NOTIFY carries. Postgres refuses payloads of 8000
|
|
70
|
+
* bytes or more; a piece is ASCII, so this leaves room for its header.
|
|
71
|
+
*/
|
|
72
|
+
const PIECE = 7_000;
|
|
73
|
+
|
|
74
|
+
/** How long half a message waits for the rest before it is given up on. */
|
|
75
|
+
const PIECE_TIMEOUT_MS = 30_000;
|
|
76
|
+
|
|
77
|
+
/** The most pieces one message may claim to have: about 52 MB of message, far past any frame. */
|
|
78
|
+
const MAX_PIECES = 10_000;
|
|
79
|
+
|
|
80
|
+
/** The longest message `publish` takes, in UTF-8 bytes: what MAX_PIECES pieces of base64 hold. */
|
|
81
|
+
export const MAX_PUBLISH_BYTES = Math.floor((PIECE * MAX_PIECES * 3) / 4);
|
|
82
|
+
|
|
65
83
|
/**
|
|
66
84
|
* The schema, one statement per entry. `migrate()` runs these; export them to
|
|
67
85
|
* your own migration tool instead if you have one.
|
|
@@ -83,6 +101,8 @@ export const schema: readonly string[] = [
|
|
|
83
101
|
-- when recent wake turns started, and the last notice that may no longer start one
|
|
84
102
|
wakes jsonb NOT NULL DEFAULT '[]',
|
|
85
103
|
woke_through integer NOT NULL DEFAULT 0,
|
|
104
|
+
-- how many wake turns it has started, to tell an older turn's frames from a newer's
|
|
105
|
+
wake_turns integer NOT NULL DEFAULT 0,
|
|
86
106
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
87
107
|
)`,
|
|
88
108
|
// a table created before notices existed gains the columns
|
|
@@ -90,6 +110,7 @@ export const schema: readonly string[] = [
|
|
|
90
110
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS noticed_through integer NOT NULL DEFAULT 0`,
|
|
91
111
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS wakes jsonb NOT NULL DEFAULT '[]'`,
|
|
92
112
|
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS woke_through integer NOT NULL DEFAULT 0`,
|
|
113
|
+
`ALTER TABLE haikit_conversations ADD COLUMN IF NOT EXISTS wake_turns integer NOT NULL DEFAULT 0`,
|
|
93
114
|
// Append-only, and never an orphan: a notice belongs to a conversation that
|
|
94
115
|
// exists, and goes when it does.
|
|
95
116
|
`CREATE TABLE IF NOT EXISTS haikit_notices (
|
|
@@ -144,7 +165,7 @@ export async function migrate(db: Queryable): Promise<void> {
|
|
|
144
165
|
const CONVERSATION_COLUMNS = `
|
|
145
166
|
id, status, messages::text AS messages, handles::text AS handles,
|
|
146
167
|
frozen::text AS frozen, pending::text AS pending, lease_token, noticed_through,
|
|
147
|
-
wakes::text AS wakes, woke_through,
|
|
168
|
+
wakes::text AS wakes, woke_through, wake_turns,
|
|
148
169
|
(extract(epoch FROM lease_until) * 1000)::float8 AS lease_until_ms`;
|
|
149
170
|
|
|
150
171
|
const NOTICE_COLUMNS = `
|
|
@@ -172,6 +193,7 @@ const toConversation = (row: any): Conversation => ({
|
|
|
172
193
|
noticedThrough: Number(row.noticed_through ?? 0),
|
|
173
194
|
wakes: row.wakes == null ? [] : json(row.wakes),
|
|
174
195
|
wokeThrough: Number(row.woke_through ?? 0),
|
|
196
|
+
wakeTurns: Number(row.wake_turns ?? 0),
|
|
175
197
|
});
|
|
176
198
|
|
|
177
199
|
const toNotice = (row: any): NoticeRecord => ({
|
|
@@ -211,20 +233,125 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
211
233
|
throw new RangeError(`leaseMs must be a positive, finite number of milliseconds (got ${leaseMs})`);
|
|
212
234
|
}
|
|
213
235
|
|
|
214
|
-
// One LISTEN for the whole store, taken when something first
|
|
215
|
-
// each notification handed to whoever
|
|
236
|
+
// One LISTEN per channel for the whole store, taken when something first
|
|
237
|
+
// needs it, and each notification handed to whoever wants that conversation.
|
|
216
238
|
const waiting = new Map<string, Set<() => void>>();
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
// try again on the next watch, rather than never
|
|
225
|
-
listening = null;
|
|
239
|
+
const listening = new Map<string, Promise<unknown>>();
|
|
240
|
+
const listenOn = (listener: Listener, channel: string, onNotify: (payload: string) => void) => {
|
|
241
|
+
let started = listening.get(channel);
|
|
242
|
+
if (!started) {
|
|
243
|
+
started = listener.listen(channel, onNotify).catch((err) => {
|
|
244
|
+
// try again next time, rather than never
|
|
245
|
+
listening.delete(channel);
|
|
226
246
|
throw err;
|
|
227
|
-
})
|
|
247
|
+
});
|
|
248
|
+
listening.set(channel, started);
|
|
249
|
+
}
|
|
250
|
+
return started;
|
|
251
|
+
};
|
|
252
|
+
const listen = (listener: Listener) =>
|
|
253
|
+
listenOn(listener, NOTICE_CHANNEL, (id) => {
|
|
254
|
+
for (const wake of waiting.get(id) ?? []) wake();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ── publish / subscribe, over NOTIFY ───────────────────────────────────
|
|
258
|
+
// A message goes out as pieces of at most PIECE base64 characters, each
|
|
259
|
+
// `<conversation> <message id> <index> <count> <piece>`, all in one
|
|
260
|
+
// statement, and is put back together on the way in. Messages from this
|
|
261
|
+
// store are sent one at a time per conversation, each committed before the
|
|
262
|
+
// next starts, so they arrive in the order they were published.
|
|
263
|
+
const hearing = new Map<string, Set<(message: string) => void>>();
|
|
264
|
+
const partial = new Map<string, { pieces: string[]; got: number; expire: ReturnType<typeof setTimeout> }>();
|
|
265
|
+
const sending = new Map<string, Promise<void>>();
|
|
266
|
+
|
|
267
|
+
const onTurn = (payload: string) => {
|
|
268
|
+
const [conversationId, id, index, count, piece] = String(payload).split(" ");
|
|
269
|
+
if (!hearing.has(conversationId)) return;
|
|
270
|
+
// The channel is shared, and anything may NOTIFY on it: a piece that
|
|
271
|
+
// doesn't hold together is dropped, never let throw out of the listener.
|
|
272
|
+
const n = Number(count);
|
|
273
|
+
const i = Number(index);
|
|
274
|
+
if (!id || !Number.isSafeInteger(n) || n < 1 || n > MAX_PIECES || !Number.isSafeInteger(i) || i < 0 || i >= n) return;
|
|
275
|
+
const known = partial.get(id);
|
|
276
|
+
if (known && known.pieces.length !== n) return;
|
|
277
|
+
let entry = known;
|
|
278
|
+
if (!entry) {
|
|
279
|
+
// A message whose other pieces never come (a listening connection that
|
|
280
|
+
// dropped part way) is given up on after a while, whatever else arrives.
|
|
281
|
+
const expire = setTimeout(() => partial.delete(id), PIECE_TIMEOUT_MS);
|
|
282
|
+
// and is no reason to keep the process alive
|
|
283
|
+
(expire as { unref?: () => void }).unref?.();
|
|
284
|
+
entry = { pieces: new Array<string>(n), got: 0, expire };
|
|
285
|
+
}
|
|
286
|
+
if (entry.pieces[i] === undefined) entry.got++;
|
|
287
|
+
entry.pieces[i] = piece ?? "";
|
|
288
|
+
if (entry.got < n) return void partial.set(id, entry);
|
|
289
|
+
clearTimeout(entry.expire);
|
|
290
|
+
partial.delete(id);
|
|
291
|
+
let message: string;
|
|
292
|
+
try {
|
|
293
|
+
message = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
294
|
+
Uint8Array.from(atob(entry.pieces.join("")), (c) => c.charCodeAt(0)),
|
|
295
|
+
);
|
|
296
|
+
} catch {
|
|
297
|
+
return; // not base64, or not UTF-8 once decoded: not one of ours
|
|
298
|
+
}
|
|
299
|
+
for (const hear of [...(hearing.get(conversationId) ?? [])]) hear(message);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
async function publish(conversationId: string, message: string) {
|
|
303
|
+
const bytes = new TextEncoder().encode(String(message));
|
|
304
|
+
// Refused here rather than sent and dropped by every listener, and before
|
|
305
|
+
// any of the work of encoding it.
|
|
306
|
+
if (bytes.length > MAX_PUBLISH_BYTES) {
|
|
307
|
+
throw new RangeError(
|
|
308
|
+
`message too long to publish: ${bytes.length} bytes, over the ${MAX_PUBLISH_BYTES}-byte maximum`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
let binary = "";
|
|
312
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
313
|
+
const encoded = btoa(binary);
|
|
314
|
+
const id = newToken().replaceAll("-", "");
|
|
315
|
+
const count = Math.max(1, Math.ceil(encoded.length / PIECE));
|
|
316
|
+
const pieces = Array.from({ length: count }, (_, i) =>
|
|
317
|
+
`${conversationId} ${id} ${i} ${count} ${encoded.slice(i * PIECE, (i + 1) * PIECE)}`,
|
|
318
|
+
);
|
|
319
|
+
const before = sending.get(conversationId) ?? Promise.resolve();
|
|
320
|
+
const sent = before.then(() =>
|
|
321
|
+
db.query(`SELECT pg_notify('${TURN_CHANNEL}', piece) FROM jsonb_array_elements_text($1::jsonb) AS piece`, [
|
|
322
|
+
JSON.stringify(pieces),
|
|
323
|
+
]),
|
|
324
|
+
);
|
|
325
|
+
const settled = sent.then(
|
|
326
|
+
() => {},
|
|
327
|
+
() => {},
|
|
328
|
+
);
|
|
329
|
+
sending.set(conversationId, settled);
|
|
330
|
+
try {
|
|
331
|
+
await sent;
|
|
332
|
+
} finally {
|
|
333
|
+
if (sending.get(conversationId) === settled) sending.delete(conversationId);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async function subscribe(conversationId: string, onMessage: (message: string) => void, signal: AbortSignal) {
|
|
338
|
+
if (signal.aborted) return;
|
|
339
|
+
const set = hearing.get(conversationId) ?? new Set();
|
|
340
|
+
set.add(onMessage);
|
|
341
|
+
hearing.set(conversationId, set);
|
|
342
|
+
signal.addEventListener(
|
|
343
|
+
"abort",
|
|
344
|
+
() => {
|
|
345
|
+
set.delete(onMessage);
|
|
346
|
+
if (!set.size && hearing.get(conversationId) === set) hearing.delete(conversationId);
|
|
347
|
+
},
|
|
348
|
+
{ once: true },
|
|
349
|
+
);
|
|
350
|
+
// Resolves once LISTEN has taken hold, so nothing published after this
|
|
351
|
+
// resolves is missed. Best effort, as the contract says: a failed LISTEN
|
|
352
|
+
// is tried again next time, and this resolves all the same.
|
|
353
|
+
await listenOn(options.listen!, TURN_CHANNEL, onTurn).catch(() => {});
|
|
354
|
+
}
|
|
228
355
|
|
|
229
356
|
async function* watch(conversationId: string, signal: AbortSignal): AsyncIterable<void> {
|
|
230
357
|
// One wake-up stands for any number of notices: a step resolves once
|
|
@@ -316,6 +443,7 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
316
443
|
noticed_through = $9::integer,
|
|
317
444
|
wakes = $10::jsonb,
|
|
318
445
|
woke_through = $11::integer,
|
|
446
|
+
wake_turns = $12::integer,
|
|
319
447
|
updated_at = now()
|
|
320
448
|
WHERE id = $1 AND lease_token = $2
|
|
321
449
|
RETURNING id`,
|
|
@@ -332,6 +460,7 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
332
460
|
conversation.noticedThrough ?? 0,
|
|
333
461
|
JSON.stringify(conversation.wakes ?? []),
|
|
334
462
|
conversation.wokeThrough ?? 0,
|
|
463
|
+
conversation.wakeTurns ?? 0,
|
|
335
464
|
],
|
|
336
465
|
);
|
|
337
466
|
if (!rows.length) await stale(conversation.id);
|
|
@@ -446,7 +575,9 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
446
575
|
return exists.rows.length ? [] : null;
|
|
447
576
|
},
|
|
448
577
|
|
|
449
|
-
|
|
578
|
+
// Anyone can publish; hearing it takes a LISTEN connection.
|
|
579
|
+
publish,
|
|
580
|
+
...(options.listen ? { watch, subscribe } : {}),
|
|
450
581
|
};
|
|
451
582
|
}
|
|
452
583
|
|