@haikit/postgres 0.3.1 → 0.5.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 +10 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +17 -4
package/README.md
CHANGED
|
@@ -41,8 +41,16 @@ exactly one to win.
|
|
|
41
41
|
## Schema
|
|
42
42
|
|
|
43
43
|
Two tables, `haikit_conversations` and `haikit_payloads`. `migrate()` creates
|
|
44
|
-
them if they do not exist; if you use your
|
|
45
|
-
are exported as `schema`.
|
|
44
|
+
them if they do not exist and brings existing ones up to date; if you use your
|
|
45
|
+
own migration tool, the statements are exported as `schema`.
|
|
46
|
+
|
|
47
|
+
**Upgrading to 0.4:** `migrate()` adds `stale_after_ms` to `haikit_payloads`:
|
|
48
|
+
the freshness window each payload was rendered under, so a later deploy that
|
|
49
|
+
renames a surface or relaxes its window cannot make data already shown last
|
|
50
|
+
longer. If you call `migrate()` at startup as above, there is nothing to do.
|
|
51
|
+
With your own migration tool, apply the new `ALTER TABLE` from `schema` before
|
|
52
|
+
deploying. Rows written before the column existed are held to the window your
|
|
53
|
+
code declares.
|
|
46
54
|
|
|
47
55
|
Handles are numbered per conversation, so every conversation's digests start at
|
|
48
56
|
`ui_01`.
|
package/dist/index.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export interface PgStoreOptions {
|
|
|
38
38
|
* your own migration tool instead if you have one.
|
|
39
39
|
*/
|
|
40
40
|
export declare const schema: readonly string[];
|
|
41
|
-
/** Create the tables if they do not exist. Idempotent. */
|
|
41
|
+
/** Create the tables if they do not exist, and bring existing ones up to date. Idempotent. */
|
|
42
42
|
export declare function migrate(db: Queryable): Promise<void>;
|
|
43
43
|
export declare function pgStore(db: Queryable, options?: PgStoreOptions): StoreAdapter;
|
|
44
44
|
export interface SweepOptions {
|
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,EAKL,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;CAClB;AAID;;;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,EAKL,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;CAClB;AAID;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,MAAM,EAmCnC,CAAC;AAEF,8FAA8F;AAC9F,wBAAsB,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAI1D;AA8CD,wBAAgB,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,cAAmB,GAAG,YAAY,CAkJjF;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
|
@@ -42,11 +42,17 @@ export const schema = [
|
|
|
42
42
|
-- never save again, which is what makes an unreferenced row an orphan.
|
|
43
43
|
lease_token text NOT NULL,
|
|
44
44
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
45
|
+
-- the surface's freshness window when this rendered, in ms; 'Infinity' is
|
|
46
|
+
-- "never", NULL a payload written before windows existed
|
|
47
|
+
stale_after_ms double precision,
|
|
45
48
|
PRIMARY KEY (conversation_id, handle)
|
|
46
49
|
)`,
|
|
50
|
+
// a table created before freshness windows existed gains the column; its
|
|
51
|
+
// rows read as unknown and are held to whatever the code declares
|
|
52
|
+
`ALTER TABLE haikit_payloads ADD COLUMN IF NOT EXISTS stale_after_ms double precision`,
|
|
47
53
|
`CREATE INDEX IF NOT EXISTS haikit_payloads_created_at ON haikit_payloads (created_at)`,
|
|
48
54
|
];
|
|
49
|
-
/** Create the tables if they do not exist. Idempotent. */
|
|
55
|
+
/** Create the tables if they do not exist, and bring existing ones up to date. Idempotent. */
|
|
50
56
|
export async function migrate(db) {
|
|
51
57
|
// One statement per call: some drivers (PGlite among them) reject several
|
|
52
58
|
// statements in a single parameterised query.
|
|
@@ -61,9 +67,12 @@ const CONVERSATION_COLUMNS = `
|
|
|
61
67
|
id, status, messages::text AS messages, handles::text AS handles,
|
|
62
68
|
frozen::text AS frozen, pending::text AS pending, lease_token,
|
|
63
69
|
(extract(epoch FROM lease_until) * 1000)::float8 AS lease_until_ms`;
|
|
70
|
+
// The window is read as text too: 'Infinity' is how "never" is stored, and
|
|
71
|
+
// drivers need not agree on turning it into a number.
|
|
64
72
|
const PAYLOAD_COLUMNS = `
|
|
65
73
|
handle, conversation_id, component, version, props::text AS props, mode,
|
|
66
|
-
(extract(epoch FROM created_at) * 1000)::float8 AS created_at_ms
|
|
74
|
+
(extract(epoch FROM created_at) * 1000)::float8 AS created_at_ms,
|
|
75
|
+
stale_after_ms::text AS stale_after_ms`;
|
|
67
76
|
const json = (text) => JSON.parse(text);
|
|
68
77
|
const toConversation = (row) => ({
|
|
69
78
|
id: row.id,
|
|
@@ -83,6 +92,7 @@ const toPayload = (row) => ({
|
|
|
83
92
|
props: json(row.props),
|
|
84
93
|
mode: row.mode,
|
|
85
94
|
createdAt: Number(row.created_at_ms),
|
|
95
|
+
staleAfterMs: row.stale_after_ms == null ? null : row.stale_after_ms === "Infinity" ? "never" : Number(row.stale_after_ms),
|
|
86
96
|
});
|
|
87
97
|
const newToken = () => globalThis.crypto.randomUUID();
|
|
88
98
|
const newId = () => `conv_${globalThis.crypto.randomUUID().replaceAll("-", "")}`;
|
|
@@ -167,11 +177,12 @@ export function pgStore(db, options = {}) {
|
|
|
167
177
|
WHERE id = $1::text AND lease_token = $2::text
|
|
168
178
|
RETURNING handle_seq
|
|
169
179
|
)
|
|
170
|
-
INSERT INTO haikit_payloads
|
|
180
|
+
INSERT INTO haikit_payloads
|
|
181
|
+
(conversation_id, handle, component, version, props, mode, lease_token, stale_after_ms)
|
|
171
182
|
SELECT $1::text,
|
|
172
183
|
-- ui_01 … ui_09, ui_10 … ui_99, ui_100: pad, never truncate
|
|
173
184
|
'ui_' || CASE WHEN handle_seq < 10 THEN '0' ELSE '' END || handle_seq,
|
|
174
|
-
$3::text, $4::integer, $5::jsonb, $6::text, $2::text
|
|
185
|
+
$3::text, $4::integer, $5::jsonb, $6::text, $2::text, $7::float8
|
|
175
186
|
FROM owner
|
|
176
187
|
RETURNING handle`, [
|
|
177
188
|
record.conversationId,
|
|
@@ -180,6 +191,7 @@ export function pgStore(db, options = {}) {
|
|
|
180
191
|
record.version,
|
|
181
192
|
JSON.stringify(record.props),
|
|
182
193
|
record.mode,
|
|
194
|
+
record.staleAfterMs === "never" ? "Infinity" : (record.staleAfterMs ?? null),
|
|
183
195
|
]);
|
|
184
196
|
if (!rows.length)
|
|
185
197
|
await stale(record.conversationId);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,gBAAgB,EAChB,UAAU,GAIX,MAAM,cAAc,CAAC;AAwBtB,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEzB;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAsB;IACvC;;;;;;;;;;;KAWG;IACH,6EAA6E;IAC7E,uEAAuE;IACvE
|
|
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.5.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.5.0"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -73,12 +73,18 @@ export const schema: readonly string[] = [
|
|
|
73
73
|
-- never save again, which is what makes an unreferenced row an orphan.
|
|
74
74
|
lease_token text NOT NULL,
|
|
75
75
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
76
|
+
-- the surface's freshness window when this rendered, in ms; 'Infinity' is
|
|
77
|
+
-- "never", NULL a payload written before windows existed
|
|
78
|
+
stale_after_ms double precision,
|
|
76
79
|
PRIMARY KEY (conversation_id, handle)
|
|
77
80
|
)`,
|
|
81
|
+
// a table created before freshness windows existed gains the column; its
|
|
82
|
+
// rows read as unknown and are held to whatever the code declares
|
|
83
|
+
`ALTER TABLE haikit_payloads ADD COLUMN IF NOT EXISTS stale_after_ms double precision`,
|
|
78
84
|
`CREATE INDEX IF NOT EXISTS haikit_payloads_created_at ON haikit_payloads (created_at)`,
|
|
79
85
|
];
|
|
80
86
|
|
|
81
|
-
/** Create the tables if they do not exist. Idempotent. */
|
|
87
|
+
/** Create the tables if they do not exist, and bring existing ones up to date. Idempotent. */
|
|
82
88
|
export async function migrate(db: Queryable): Promise<void> {
|
|
83
89
|
// One statement per call: some drivers (PGlite among them) reject several
|
|
84
90
|
// statements in a single parameterised query.
|
|
@@ -94,9 +100,12 @@ const CONVERSATION_COLUMNS = `
|
|
|
94
100
|
frozen::text AS frozen, pending::text AS pending, lease_token,
|
|
95
101
|
(extract(epoch FROM lease_until) * 1000)::float8 AS lease_until_ms`;
|
|
96
102
|
|
|
103
|
+
// The window is read as text too: 'Infinity' is how "never" is stored, and
|
|
104
|
+
// drivers need not agree on turning it into a number.
|
|
97
105
|
const PAYLOAD_COLUMNS = `
|
|
98
106
|
handle, conversation_id, component, version, props::text AS props, mode,
|
|
99
|
-
(extract(epoch FROM created_at) * 1000)::float8 AS created_at_ms
|
|
107
|
+
(extract(epoch FROM created_at) * 1000)::float8 AS created_at_ms,
|
|
108
|
+
stale_after_ms::text AS stale_after_ms`;
|
|
100
109
|
|
|
101
110
|
const json = (text: string) => JSON.parse(text);
|
|
102
111
|
|
|
@@ -119,6 +128,8 @@ const toPayload = (row: any): PayloadRecord => ({
|
|
|
119
128
|
props: json(row.props),
|
|
120
129
|
mode: row.mode,
|
|
121
130
|
createdAt: Number(row.created_at_ms),
|
|
131
|
+
staleAfterMs:
|
|
132
|
+
row.stale_after_ms == null ? null : row.stale_after_ms === "Infinity" ? "never" : Number(row.stale_after_ms),
|
|
122
133
|
});
|
|
123
134
|
|
|
124
135
|
const newToken = () => globalThis.crypto.randomUUID();
|
|
@@ -218,11 +229,12 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
218
229
|
WHERE id = $1::text AND lease_token = $2::text
|
|
219
230
|
RETURNING handle_seq
|
|
220
231
|
)
|
|
221
|
-
INSERT INTO haikit_payloads
|
|
232
|
+
INSERT INTO haikit_payloads
|
|
233
|
+
(conversation_id, handle, component, version, props, mode, lease_token, stale_after_ms)
|
|
222
234
|
SELECT $1::text,
|
|
223
235
|
-- ui_01 … ui_09, ui_10 … ui_99, ui_100: pad, never truncate
|
|
224
236
|
'ui_' || CASE WHEN handle_seq < 10 THEN '0' ELSE '' END || handle_seq,
|
|
225
|
-
$3::text, $4::integer, $5::jsonb, $6::text, $2::text
|
|
237
|
+
$3::text, $4::integer, $5::jsonb, $6::text, $2::text, $7::float8
|
|
226
238
|
FROM owner
|
|
227
239
|
RETURNING handle`,
|
|
228
240
|
[
|
|
@@ -232,6 +244,7 @@ export function pgStore(db: Queryable, options: PgStoreOptions = {}): StoreAdapt
|
|
|
232
244
|
record.version,
|
|
233
245
|
JSON.stringify(record.props),
|
|
234
246
|
record.mode,
|
|
247
|
+
record.staleAfterMs === "never" ? "Infinity" : (record.staleAfterMs ?? null),
|
|
235
248
|
],
|
|
236
249
|
);
|
|
237
250
|
if (!rows.length) await stale(record.conversationId);
|