@kairos-es/store-postgres 1.0.0-alpha.3 → 1.0.0-alpha.4

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.
Files changed (35) hide show
  1. package/README.md +11 -4
  2. package/dist/cjs/ensureSchema.js +6 -1
  3. package/dist/cjs/ensureSchema.js.map +1 -1
  4. package/dist/cjs/internal/ddl.js +29 -12
  5. package/dist/cjs/internal/ddl.js.map +1 -1
  6. package/dist/cjs/internal/matchSql.js +46 -4
  7. package/dist/cjs/internal/matchSql.js.map +1 -1
  8. package/dist/cjs/internal/readPlan.js +8 -4
  9. package/dist/cjs/internal/readPlan.js.map +1 -1
  10. package/dist/cjs/internal/transport.js +27 -4
  11. package/dist/cjs/internal/transport.js.map +1 -1
  12. package/dist/dts/ensureSchema.d.ts +6 -1
  13. package/dist/dts/ensureSchema.d.ts.map +1 -1
  14. package/dist/dts/internal/ddl.d.ts.map +1 -1
  15. package/dist/dts/internal/matchSql.d.ts +26 -2
  16. package/dist/dts/internal/matchSql.d.ts.map +1 -1
  17. package/dist/dts/internal/readPlan.d.ts.map +1 -1
  18. package/dist/dts/internal/transport.d.ts +17 -7
  19. package/dist/dts/internal/transport.d.ts.map +1 -1
  20. package/dist/esm/ensureSchema.js +6 -1
  21. package/dist/esm/ensureSchema.js.map +1 -1
  22. package/dist/esm/internal/ddl.js +30 -13
  23. package/dist/esm/internal/ddl.js.map +1 -1
  24. package/dist/esm/internal/matchSql.js +44 -2
  25. package/dist/esm/internal/matchSql.js.map +1 -1
  26. package/dist/esm/internal/readPlan.js +8 -4
  27. package/dist/esm/internal/readPlan.js.map +1 -1
  28. package/dist/esm/internal/transport.js +26 -3
  29. package/dist/esm/internal/transport.js.map +1 -1
  30. package/package.json +2 -2
  31. package/src/ensureSchema.ts +6 -1
  32. package/src/internal/ddl.ts +32 -12
  33. package/src/internal/matchSql.ts +52 -1
  34. package/src/internal/readPlan.ts +8 -4
  35. package/src/internal/transport.ts +46 -7
package/README.md CHANGED
@@ -31,10 +31,17 @@ consumers.
31
31
  ## Schema: `ensureSchema` as a migration
32
32
 
33
33
  The package ships **no migrator**. `ensureSchema(config)` is a single idempotent
34
- `Effect<void, SqlError, SqlClient>` that creates (or refreshes) every object the
35
- store owns. Every statement is `CREATE … IF NOT EXISTS` or `CREATE OR REPLACE
36
- FUNCTION`, so re-running it is a no-op. Migration **orchestration** is yours; the
37
- package only provides the idempotent **payload**.
34
+ `Effect<void, SqlError, SqlClient>` that creates every object the store owns and
35
+ replaces its append functions. Every statement is `CREATE … IF NOT EXISTS` or
36
+ `CREATE OR REPLACE FUNCTION`, so re-running it is safe. Migration
37
+ **orchestration** is yours; the package only provides the idempotent **payload**.
38
+
39
+ **Upgrading.** A re-run replaces the append functions but never alters an existing
40
+ table. So when a release adds a column, its release notes give the `ALTER TABLE`
41
+ statement, and an upgrade is that statement followed by this version's
42
+ `ensureSchema` again, registered as a NEW migration: a migrator never re-runs one
43
+ it has already applied, and an append function left behind silently ignores the
44
+ new column.
38
45
 
39
46
  Drop it straight into an `@effect/sql` migrator as a one-liner:
40
47
 
@@ -28,7 +28,12 @@ var _ddl = require("./internal/ddl.js");
28
28
  * consumer, this package only provides the idempotent PAYLOAD.
29
29
  *
30
30
  * Idempotence: every statement is `CREATE … IF NOT EXISTS` or `CREATE OR REPLACE
31
- * FUNCTION`, so re-running against an existing store is a no-op. Names come from
31
+ * FUNCTION`, so re-running it is safe. It is NOT a no-op across versions: a
32
+ * re-run replaces the append functions with this version's, and does NOT alter
33
+ * an existing table, so a column a newer version adds must be added by hand
34
+ * before the re-run (the release notes give the statement). A store whose
35
+ * table gained a column but whose functions were never replaced keeps writing
36
+ * through the old ones, which do not know the column. Names come from
32
37
  * `sql(identifier)` (via the pre-quoted builder in `internal/ddl.ts`); the DDL
33
38
  * bodies carry no bound values (pure schema), and the append functions keep
34
39
  * their runtime VALUES as bound parameters, never interpolated.
@@ -1 +1 @@
1
- {"version":3,"file":"ensureSchema.js","names":["_sql","require","_effect","_config","_ddl","ensureSchema","config","Effect","gen","sql","SqlClient","names","resolveNames","decodePostgresStoreConfig","all","runDdl","discard","exports"],"sources":["../../src/ensureSchema.ts"],"sourcesContent":[null],"mappings":";;;;;;AAyBA,IAAAA,IAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,IAAA,GAAAH,OAAA;AA5BA;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA;;;;;AAKO,MAAMI,YAAY,GACvBC,MAA2B,IAE3BC,cAAM,CAACC,GAAG,CAAC,aAAS;EAClB,MAAMC,GAAG,GAAG,OAAOC,cAAS,CAACA,SAAS;EACtC;EACA;EACA,MAAMC,KAAK,GAAG,IAAAC,iBAAY,EAAC,IAAAC,iCAAyB,EAACP,MAAM,CAAC,CAAC;EAC7D;EACA,OAAOC,cAAM,CAACO,GAAG,CAAC,IAAAC,WAAM,EAACN,GAAG,EAAEE,KAAK,CAAC,EAAE;IAAEK,OAAO,EAAE;EAAI,CAAE,CAAC;AAC1D,CAAC,CAAC;AAAAC,OAAA,CAAAZ,YAAA,GAAAA,YAAA","ignoreList":[]}
1
+ {"version":3,"file":"ensureSchema.js","names":["_sql","require","_effect","_config","_ddl","ensureSchema","config","Effect","gen","sql","SqlClient","names","resolveNames","decodePostgresStoreConfig","all","runDdl","discard","exports"],"sources":["../../src/ensureSchema.ts"],"sourcesContent":[null],"mappings":";;;;;;AA8BA,IAAAA,IAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,IAAA,GAAAH,OAAA;AAjCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA;;;;;AAKO,MAAMI,YAAY,GACvBC,MAA2B,IAE3BC,cAAM,CAACC,GAAG,CAAC,aAAS;EAClB,MAAMC,GAAG,GAAG,OAAOC,cAAS,CAACA,SAAS;EACtC;EACA;EACA,MAAMC,KAAK,GAAG,IAAAC,iBAAY,EAAC,IAAAC,iCAAyB,EAACP,MAAM,CAAC,CAAC;EAC7D;EACA,OAAOC,cAAM,CAACO,GAAG,CAAC,IAAAC,WAAM,EAACN,GAAG,EAAEE,KAAK,CAAC,EAAE;IAAEK,OAAO,EAAE;EAAI,CAAE,CAAC;AAC1D,CAAC,CAAC;AAAAC,OAAA,CAAAZ,YAAA,GAAAA,YAAA","ignoreList":[]}
@@ -129,6 +129,16 @@ const lockClause = names => `LOCK TABLE ${quoteQualified(names.mainTable)} IN EX
129
129
  * preserves batch order, and `RETURNING id, tags` is captured into a temp
130
130
  * result set so the tag fan-out and the head can both read it. `data` arrives as
131
131
  * a base64 text field and is `decode(…, 'base64')`-restored to `bytea`.
132
+ *
133
+ * The recordset definition, its projection, the `INSERT INTO (…)` target list and
134
+ * the `SELECT` list are all derived from the one `EVENT_COLUMNS` descriptor in
135
+ * `matchSql.ts`, never written out here. The last two must agree POSITIONALLY and a
136
+ * mismatch is not an error, so deriving both from one walk is what keeps them from
137
+ * falling out of step; a column added without a source is a compile error there.
138
+ * What the compiler does NOT reach is whether the source READS the right field, or
139
+ * whether the column comes back out on the read; the round-trip contract group run
140
+ * against this engine is what proves a new column, and only with a value distinct
141
+ * per column, which is what makes a swap visible.
132
142
  */
133
143
  const insertFanoutNotify = (names, options = {}) => {
134
144
  const main = quoteQualified(names.mainTable);
@@ -146,18 +156,18 @@ const insertFanoutNotify = (names, options = {}) => {
146
156
  IF new_head IS NOT NULL THEN
147
157
  PERFORM pg_notify(${channel}, '1');
148
158
  END IF;` : '';
149
- return ` WITH ne AS (
150
- SELECT type, data, tags, uuid, occurred_at, ordinality
159
+ const ne = _matchSql.RECORDSET_ALIAS;
160
+ return ` WITH ${ne} AS (
161
+ SELECT ${_matchSql.eventColumnList}, ordinality
151
162
  FROM ROWS FROM(
152
163
  jsonb_to_recordset(new_events) AS (${_matchSql.eventRecordsetColumns})
153
164
  ) WITH ORDINALITY
154
165
  ),
155
166
  inserted AS (
156
- INSERT INTO ${main} (type, data, tags, uuid, occurred_at)
157
- SELECT ne.type, decode(ne.data, 'base64'), ne.tags, ne.uuid,
158
- ne.occurred_at
159
- FROM ne
160
- ORDER BY ne.ordinality
167
+ INSERT INTO ${main} (${_matchSql.eventColumnList})
168
+ SELECT ${_matchSql.eventInsertSelectList}
169
+ FROM ${ne}
170
+ ORDER BY ${ne}.ordinality
161
171
  RETURNING id, tags
162
172
  ),
163
173
  fanned AS (
@@ -206,9 +216,12 @@ const conditionalAppendBody = (names, options = {}) => {
206
216
  // its ITEMS — none at all, an item carrying no tags, an item carrying tags —
207
217
  // which between them cover every `Query` value the grammar can express, so a new
208
218
  // SHAPE changes which SQL the read compiles without changing what this body has
209
- // to match. The exposure is the GRAMMAR itself: a new `QueryItem` field, or a new
210
- // meaning for an existing one, is something this body ignores rather than fails
211
- // on, and no `switch` over the shape union would have caught that either.
219
+ // to match. The exposure is the GRAMMAR itself: a field ADDED to `QueryItem`, or a
220
+ // new meaning for an existing one, is something this body ignores rather than
221
+ // fails on, and no `switch` over the shape union would have caught that either. A
222
+ // key the grammar does NOT define never reaches this body: core's
223
+ // `servableQueryFault` refuses it at the contract boundary, which is what keeps a
224
+ // smuggled predicate from being dropped here in silence.
212
225
  const after = 'COALESCE(after_id, 0)';
213
226
  return `
214
227
  DECLARE
@@ -378,14 +391,18 @@ const ddlStatements = names => {
378
391
  // positions — a rolled-back insert permanently consumes its id, which is
379
392
  // fine: ordering is by id alone and the store is never made gapless.
380
393
  // `data` is NULLABLE (a payload-less event is valid); `occurred_at` is
381
- // informational domain time, never an ordering key.
394
+ // informational domain time, never an ordering key. `metadata` is the
395
+ // event's cleartext context bag (ADR-0017): `jsonb` only so a containment
396
+ // index stays possible without a rewrite, though nothing queries it and no
397
+ // index is built; `NOT NULL DEFAULT '{}'` gives an empty bag one shape.
382
398
  `CREATE TABLE IF NOT EXISTS ${main} (
383
399
  id bigserial,
384
400
  type text NOT NULL,
385
401
  data bytea,
386
402
  tags text[] NOT NULL,
387
403
  uuid text NOT NULL,
388
- occurred_at timestamptz NOT NULL
404
+ occurred_at timestamptz NOT NULL,
405
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb
389
406
  ) WITH (${AUTOVACUUM_WITH});`,
390
407
  // Covering unique index: uniqueness on id plus INCLUDE(type) so the read
391
408
  // path's id→type lookups are index-only.
@@ -1 +1 @@
1
- {"version":3,"file":"ddl.js","names":["_matchSql","require","DEFAULT_SCHEMA","exports","DEFAULT_TABLE_PREFIX","MAX_IDENTIFIER_BYTES","utf8ByteLength","value","TextEncoder","encode","length","derivedAtoms","config","schema","tablePrefix","replace","oversizedIdentifier","label","atom","bytes","undefined","resolveNames","problem","Error","mainTable","tagTable","mainIndex","tagIndex","appendFn","appendUnconditionalFn","channel","quoteQualified","name","split","map","join","quoteAtom","quoteLiteral","AUTOVACUUM_WITH","lockClause","names","insertFanoutNotify","options","main","tag","notify","eventRecordsetColumns","conditionalAppendBody","lock","after","taggedMatchChain","queryItemsExpr","afterExpr","allowedTypesPredicate","qualifiedRows","unconditionalAppendBody","appendFunctionStatement","qualifiedName","argList","body","kind","ddlStatements","runDdl","sql","statement","unsafe"],"sources":["../../../src/internal/ddl.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"ddl.js","names":["_matchSql","require","DEFAULT_SCHEMA","exports","DEFAULT_TABLE_PREFIX","MAX_IDENTIFIER_BYTES","utf8ByteLength","value","TextEncoder","encode","length","derivedAtoms","config","schema","tablePrefix","replace","oversizedIdentifier","label","atom","bytes","undefined","resolveNames","problem","Error","mainTable","tagTable","mainIndex","tagIndex","appendFn","appendUnconditionalFn","channel","quoteQualified","name","split","map","join","quoteAtom","quoteLiteral","AUTOVACUUM_WITH","lockClause","names","insertFanoutNotify","options","main","tag","notify","ne","RECORDSET_ALIAS","eventColumnList","eventRecordsetColumns","eventInsertSelectList","conditionalAppendBody","lock","after","taggedMatchChain","queryItemsExpr","afterExpr","allowedTypesPredicate","qualifiedRows","unconditionalAppendBody","appendFunctionStatement","qualifiedName","argList","body","kind","ddlStatements","runDdl","sql","statement","unsafe"],"sources":["../../../src/internal/ddl.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.wildcardReadSql = exports.typeOnlyReadSql = exports.taggedReadSql = exports.taggedMatchChain = exports.readColumns = exports.qualifiedRows = exports.eventRecordsetColumns = exports.allowedTypesPredicate = void 0;
6
+ exports.wildcardReadSql = exports.typeOnlyReadSql = exports.taggedReadSql = exports.taggedMatchChain = exports.readColumns = exports.qualifiedRows = exports.eventRecordsetColumns = exports.eventInsertSelectList = exports.eventColumnList = exports.allowedTypesPredicate = exports.RECORDSET_ALIAS = void 0;
7
7
  /**
8
8
  * Single source of truth for the tag-first match SQL.
9
9
  *
@@ -38,10 +38,11 @@ exports.wildcardReadSql = exports.typeOnlyReadSql = exports.taggedReadSql = expo
38
38
  * that union, so a column rename here is a COMPILE error there, not a silent drift
39
39
  * the lax read boundary (ADR-0006) would only surface as corrupt data under test.
40
40
  */
41
- const EVENT_COLUMNS = [['type', 'text'], ['data', 'text'], ['tags', 'text[]'], ['uuid', 'text'], ['occurred_at', 'timestamptz']];
41
+ const EVENT_COLUMNS = [['type', 'text'], ['data', 'text'], ['tags', 'text[]'], ['uuid', 'text'], ['occurred_at', 'timestamptz'], ['metadata', 'jsonb']];
42
42
  /**
43
43
  * The `jsonb_to_recordset(new_events) AS (…)` column definitions —
44
- * `type text, data text, tags text[], uuid text, occurred_at timestamptz`. The
44
+ * `type text, data text, tags text[], uuid text, occurred_at timestamptz,
45
+ * metadata jsonb`. The
45
46
  * transport `data` is base64 TEXT (restored to `bytea` by `decode(…, 'base64')`
46
47
  * at insert), which is why it is `text` here, not `bytea`.
47
48
  */
@@ -52,13 +53,54 @@ const eventRecordsetColumns = exports.eventRecordsetColumns = /*#__PURE__*/EVENT
52
53
  * cannot drift from the recordset.
53
54
  */
54
55
  const readColumns = (prefix = '') => [`${prefix}id`, ...EVENT_COLUMNS.map(([name]) => `${prefix}${name}`)].join(', ');
56
+ /**
57
+ * The alias the append body gives the expanded `new_events` recordset — the `ne`
58
+ * CTE in `ddl.ts` — which every expression in `EVENT_COLUMN_SOURCE` reads from.
59
+ * Exported so the CTE is declared under the one name its readers assume.
60
+ */
61
+ exports.readColumns = readColumns;
62
+ const RECORDSET_ALIAS = exports.RECORDSET_ALIAS = 'ne';
63
+ /**
64
+ * What the append body inserts into each event column, read from the recordset row.
65
+ *
66
+ * Typed as a `Record` over `EventColumnName` so that adding a column to
67
+ * `EVENT_COLUMNS` without saying where its value comes from is a COMPILE error,
68
+ * rather than a column the insert silently leaves at its default. Every column but
69
+ * `data` passes through as the recordset already types it — `text[]` tags,
70
+ * `timestamptz`, `jsonb` metadata — because `jsonb_to_recordset` did the casting;
71
+ * `data` crosses as base64 TEXT and is restored to `bytea` here, its one decode.
72
+ */
73
+ const EVENT_COLUMN_SOURCE = {
74
+ type: `${RECORDSET_ALIAS}.type`,
75
+ data: `decode(${RECORDSET_ALIAS}.data, 'base64')`,
76
+ tags: `${RECORDSET_ALIAS}.tags`,
77
+ uuid: `${RECORDSET_ALIAS}.uuid`,
78
+ occurred_at: `${RECORDSET_ALIAS}.occurred_at`,
79
+ metadata: `${RECORDSET_ALIAS}.metadata`
80
+ };
81
+ /**
82
+ * The bare event column names — `type, data, tags, uuid, occurred_at, metadata` —
83
+ * which the append body uses twice: as the recordset CTE's projection and as the
84
+ * `INSERT INTO t (…)` target list.
85
+ */
86
+ const eventColumnList = exports.eventColumnList = /*#__PURE__*/EVENT_COLUMNS.map(([name]) => name).join(', ');
87
+ /**
88
+ * The append insert's SELECT list: one source expression per column, in the SAME
89
+ * ORDER as `eventColumnList`.
90
+ *
91
+ * The two halves of `INSERT INTO t (a, b) SELECT x, y` agree POSITION BY POSITION
92
+ * and nothing checks that they do: two columns of compatible type swap without an
93
+ * error at any layer and the data lands in the wrong one. Both halves are therefore
94
+ * one walk of the one descriptor, so the append body has no second ordering to keep
95
+ * in step and no hand-written list for a new column to be missing from.
96
+ */
97
+ const eventInsertSelectList = exports.eventInsertSelectList = /*#__PURE__*/EVENT_COLUMNS.map(([name]) => EVENT_COLUMN_SOURCE[name]).join(', ');
55
98
  /**
56
99
  * The allowed-types filter for a candidate row aliased `m`: an item with no
57
100
  * types matches ANY type; otherwise the event's type must be one of them.
58
101
  * `typesCol` is the `text[]` column holding the item's types — `q.allowed_types`
59
102
  * for a tagged match, `qi.types` for a tagless one.
60
103
  */
61
- exports.readColumns = readColumns;
62
104
  const allowedTypesPredicate = typesCol => `(array_length(${typesCol}, 1) IS NULL OR array_length(${typesCol}, 1) = 0 OR m.type = ANY(${typesCol}))`;
63
105
  /**
64
106
  * The tag-first match CTE chain shared by the read and conflict paths: expand
@@ -1 +1 @@
1
- {"version":3,"file":"matchSql.js","names":["EVENT_COLUMNS","eventRecordsetColumns","exports","map","name","type","join","readColumns","prefix","allowedTypesPredicate","typesCol","taggedMatchChain","tokens","queryItemsExpr","tag","afterExpr","qualifiedRows","main","wildcardReadSql","typeOnlyReadSql","taggedReadSql"],"sources":["../../../src/internal/matchSql.ts"],"sourcesContent":[null],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;AAwBA;;;;;;;;;;;AAWA,MAAMA,aAAa,GAAG,CACpB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAClB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,aAAa,EAAE,aAAa,CAAC,CAG/B;AAYD;;;;;;AAMO,MAAMC,qBAAqB,GAAAC,OAAA,CAAAD,qBAAA,gBAAWD,aAAa,CAACG,GAAG,CAC5D,CAAC,CAACC,IAAI,EAAEC,IAAI,CAAC,KAAK,GAAGD,IAAI,IAAIC,IAAI,EAAE,CACpC,CAACC,IAAI,CAAC,IAAI,CAAC;AAEZ;;;;;AAKO,MAAMC,WAAW,GAAGA,CAACC,MAAM,GAAG,EAAE,KACrC,CAAC,GAAGA,MAAM,IAAI,EAAE,GAAGR,aAAa,CAACG,GAAG,CAAC,CAAC,CAACC,IAAI,CAAC,KAAK,GAAGI,MAAM,GAAGJ,IAAI,EAAE,CAAC,CAAC,CAACE,IAAI,CACxE,IAAI,CACL;AAEH;;;;;;AAAAJ,OAAA,CAAAK,WAAA,GAAAA,WAAA;AAMO,MAAME,qBAAqB,GAAIC,QAAgB,IACpD,iBAAiBA,QAAQ,gCAAgCA,QAAQ,4BAA4BA,QAAQ,IAAI;AAc3G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAAR,OAAA,CAAAO,qBAAA,GAAAA,qBAAA;AA4CO,MAAME,gBAAgB,GAAIC,MAAmB,IAClD;;;;;;;2BAOyBA,MAAM,CAACC,cAAc;;;;;;;WAOrCD,MAAM,CAACE,GAAG;wBACGF,MAAM,CAACG,SAAS;;;;;;;;;;;;;IAapC;AAEJ;;;;;;AAAAb,OAAA,CAAAS,gBAAA,GAAAA,gBAAA;AAMO,MAAMK,aAAa,GACxBJ,MAA+C,IAE/C;WACSA,MAAM,CAACK,IAAI;mBACHL,MAAM,CAACG,SAAS;YACvBN,qBAAqB,CAAC,iBAAiB,CAAC,EAAE;AAEtD;AAAAP,OAAA,CAAAc,aAAA,GAAAA,aAAA;AACO,MAAME,eAAe,GAAID,IAAY,IAC1C,UAAUV,WAAW,EAAE;UACfU,IAAI;;;YAGF;AAEZ;AAAAf,OAAA,CAAAgB,eAAA,GAAAA,eAAA;AACO,MAAMC,eAAe,GAAIF,IAAY,IAC1C,UAAUV,WAAW,EAAE;UACfU,IAAI;;;YAGF;AAEZ;;;;;;AAAAf,OAAA,CAAAiB,eAAA,GAAAA,eAAA;AAMO,MAAMC,aAAa,GAAGA,CAACH,IAAY,EAAEH,GAAW,KACrD,QAAQH,gBAAgB,CAAC;EAAEE,cAAc,EAAE,WAAW;EAAEE,SAAS,EAAE,IAAI;EAAEE,IAAI;EAAEH;AAAG,CAAE,CAAC;;;MAGjFE,aAAa,CAAC;EAAEC,IAAI;EAAEF,SAAS,EAAE;AAAI,CAAE,CAAC;;;;WAInCR,WAAW,CAAC,IAAI,CAAC;SACnBU,IAAI;;oBAEO;AAAAf,OAAA,CAAAkB,aAAA,GAAAA,aAAA","ignoreList":[]}
1
+ {"version":3,"file":"matchSql.js","names":["EVENT_COLUMNS","eventRecordsetColumns","exports","map","name","type","join","readColumns","prefix","RECORDSET_ALIAS","EVENT_COLUMN_SOURCE","data","tags","uuid","occurred_at","metadata","eventColumnList","eventInsertSelectList","allowedTypesPredicate","typesCol","taggedMatchChain","tokens","queryItemsExpr","tag","afterExpr","qualifiedRows","main","wildcardReadSql","typeOnlyReadSql","taggedReadSql"],"sources":["../../../src/internal/matchSql.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -36,10 +36,14 @@ const compileFetchPlan = (tables, query) => {
36
36
  case 'typeOnly':
37
37
  {
38
38
  // node-postgres binds a JS array param as a Postgres array literal, so
39
- // `type = ANY($2)` matches any of the item's types. The item's own list is
40
- // bound as it stands: a branded `EventType` IS its string to the driver, so
41
- // nothing here has to unwrap or copy it.
42
- const types = shape.types;
39
+ // `type = ANY($2)` matches any of the item's types. A branded `EventType` IS
40
+ // its string to the driver, so nothing has to be unwrapped — but the list is
41
+ // COPIED here, at compile time. The driver serialises the array afresh on
42
+ // every `bind`, and a subscription re-binds on every poll, so binding the
43
+ // caller's own array would let an edit the caller makes after subscribing
44
+ // reach the next fetch. The tagged arm is immune by construction, since it
45
+ // serialises once below; this copy is what makes the two arms agree.
46
+ const types = [...shape.types];
43
47
  return {
44
48
  text: (0, _matchSql.typeOnlyReadSql)(tables.main),
45
49
  bind: (after, limit) => [after, types, limit]
@@ -1 +1 @@
1
- {"version":3,"file":"readPlan.js","names":["_core","require","_matchSql","_transport","compileFetchPlan","tables","query","shape","classifyServableQuery","kind","text","wildcardReadSql","main","bind","after","limit","types","typeOnlyReadSql","itemsJson","jsonbText","toQueryItemsJson","taggedReadSql","tag","exports","runFetch","sql","plan","unsafe","ORIGIN"],"sources":["../../../src/internal/readPlan.ts"],"sourcesContent":[null],"mappings":";;;;;;AAyBA,IAAAA,KAAA,GAAAC,OAAA;AAEA,IAAAC,SAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AA0BA;;;;;;;;;;;;;;;;;;AAkBO,MAAMG,gBAAgB,GAAGA,CAC9BC,MAAkB,EAClBC,KAAY,KACC;EACb,MAAMC,KAAK,GAAG,IAAAC,2BAAqB,EAACF,KAAK,CAAC;EAC1C,QAAQC,KAAK,CAACE,IAAI;IAChB,KAAK,UAAU;MACb,OAAO;QACLC,IAAI,EAAE,IAAAC,yBAAe,EAACN,MAAM,CAACO,IAAI,CAAC;QAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEC,KAAK;OACtC;IACH,KAAK,UAAU;MAAE;QACf;QACA;QACA;QACA;QACA,MAAMC,KAAK,GAAGT,KAAK,CAACS,KAAK;QACzB,OAAO;UACLN,IAAI,EAAE,IAAAO,yBAAe,EAACZ,MAAM,CAACO,IAAI,CAAC;UAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEE,KAAK,EAAED,KAAK;SAC7C;MACH;IACA,KAAK,QAAQ;MAAE;QACb;QACA;QACA,MAAMG,SAAS,GAAG,IAAAC,oBAAS,EAAC,IAAAC,2BAAgB,EAACd,KAAK,CAAC,CAAC;QACpD,OAAO;UACLI,IAAI,EAAE,IAAAW,uBAAa,EAAChB,MAAM,CAACO,IAAI,EAAEP,MAAM,CAACiB,GAAG,CAAC;UAC5CT,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACG,SAAS,EAAEJ,KAAK,EAAEC,KAAK;SACjD;MACH;EACF;AACF,CAAC;AAED;;;;AAAAQ,OAAA,CAAAnB,gBAAA,GAAAA,gBAAA;AAIO,MAAMoB,QAAQ,GAAGA,CACtBC,GAAwB,EACxBC,IAAe,EACfZ,KAA2B,EAC3BC,KAA4B,KAE5BU,GAAG,CAACE,MAAM,CAAWD,IAAI,CAAChB,IAAI,EAAEgB,IAAI,CAACb,IAAI,CAACC,KAAK,IAAIc,YAAM,EAAEb,KAAK,IAAI,IAAI,CAAC,CAAC;AAAAQ,OAAA,CAAAC,QAAA,GAAAA,QAAA","ignoreList":[]}
1
+ {"version":3,"file":"readPlan.js","names":["_core","require","_matchSql","_transport","compileFetchPlan","tables","query","shape","classifyServableQuery","kind","text","wildcardReadSql","main","bind","after","limit","types","typeOnlyReadSql","itemsJson","jsonbText","toQueryItemsJson","taggedReadSql","tag","exports","runFetch","sql","plan","unsafe","ORIGIN"],"sources":["../../../src/internal/readPlan.ts"],"sourcesContent":[null],"mappings":";;;;;;AAyBA,IAAAA,KAAA,GAAAC,OAAA;AAEA,IAAAC,SAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AA0BA;;;;;;;;;;;;;;;;;;AAkBO,MAAMG,gBAAgB,GAAGA,CAC9BC,MAAkB,EAClBC,KAAY,KACC;EACb,MAAMC,KAAK,GAAG,IAAAC,2BAAqB,EAACF,KAAK,CAAC;EAC1C,QAAQC,KAAK,CAACE,IAAI;IAChB,KAAK,UAAU;MACb,OAAO;QACLC,IAAI,EAAE,IAAAC,yBAAe,EAACN,MAAM,CAACO,IAAI,CAAC;QAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEC,KAAK;OACtC;IACH,KAAK,UAAU;MAAE;QACf;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,MAAMC,KAAK,GAAG,CAAC,GAAGT,KAAK,CAACS,KAAK,CAAC;QAC9B,OAAO;UACLN,IAAI,EAAE,IAAAO,yBAAe,EAACZ,MAAM,CAACO,IAAI,CAAC;UAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEE,KAAK,EAAED,KAAK;SAC7C;MACH;IACA,KAAK,QAAQ;MAAE;QACb;QACA;QACA,MAAMG,SAAS,GAAG,IAAAC,oBAAS,EAAC,IAAAC,2BAAgB,EAACd,KAAK,CAAC,CAAC;QACpD,OAAO;UACLI,IAAI,EAAE,IAAAW,uBAAa,EAAChB,MAAM,CAACO,IAAI,EAAEP,MAAM,CAACiB,GAAG,CAAC;UAC5CT,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACG,SAAS,EAAEJ,KAAK,EAAEC,KAAK;SACjD;MACH;EACF;AACF,CAAC;AAED;;;;AAAAQ,OAAA,CAAAnB,gBAAA,GAAAA,gBAAA;AAIO,MAAMoB,QAAQ,GAAGA,CACtBC,GAAwB,EACxBC,IAAe,EACfZ,KAA2B,EAC3BC,KAA4B,KAE5BU,GAAG,CAACE,MAAM,CAAWD,IAAI,CAAChB,IAAI,EAAEgB,IAAI,CAACb,IAAI,CAACC,KAAK,IAAIc,YAAM,EAAEb,KAAK,IAAI,IAAI,CAAC,CAAC;AAAAQ,OAAA,CAAAC,QAAA,GAAAA,QAAA","ignoreList":[]}
@@ -34,12 +34,35 @@ const toEventJson = event => ({
34
34
  data: _effect.Encoding.encodeBase64(event.data),
35
35
  tags: [...event.tags],
36
36
  uuid: event.uuid,
37
- occurred_at: _effect.DateTime.formatIso(event.occurredAt)
37
+ occurred_at: _effect.DateTime.formatIso(event.occurredAt),
38
+ metadata: event.metadata
38
39
  });
40
+ /**
41
+ * The `metadata` column as the event's bag, checked to be a JSON OBJECT.
42
+ *
43
+ * The store only ever writes an object, but `jsonb` admits any JSON value — an
44
+ * array, a string, a number, a boolean, JSON `null` (which `NOT NULL` does not
45
+ * exclude) — so a hand-written row can hold one. Such a row is corrupt, and
46
+ * handing an event whose `metadata` is not a bag to every projection
47
+ * downstream is worse than stopping at the read. This is the CONTAINER check
48
+ * only; the shape rule itself has one home, core's `Metadata` doc. The VALUES
49
+ * are deliberately not re-checked as strings, because a value check on read
50
+ * alone would make an event the store accepted unreadable for ever.
51
+ */
52
+ exports.toEventJson = toEventJson;
53
+ const metadataFrom = value => {
54
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
55
+ throw new Error(`@kairos-es/store-postgres: the \`metadata\` column did not hold a JSON object (got ${JSON.stringify(value)}).`);
56
+ }
57
+ return value;
58
+ };
39
59
  /**
40
60
  * Map a raw main-table row to a core `SequencedEvent`. `data` NULL → empty bytes
41
61
  * (a payload-less event round-trips to a zero-length `Uint8Array`); `occurred_at`
42
- * Date → `DateTime.Utc`; `id` string → branded `Position`.
62
+ * Date → `DateTime.Utc`; `id` string → branded `Position`; `metadata` through
63
+ * `metadataFrom`. The column is `NOT NULL DEFAULT '{}'`, so there is no absent
64
+ * case to reconcile: an event appended with an empty bag reads back as `{}` on
65
+ * this engine exactly as on the in-memory oracle.
43
66
  *
44
67
  * The branded scalars (`type`, `tags`, `uuid`, `position`) are minted by trusted
45
68
  * `as`-cast, NOT by re-running `EventType.make` / `Tag.make` etc. This is
@@ -51,14 +74,14 @@ const toEventJson = event => ({
51
74
  * (`inMemory.ts`). The read boundary is the analogous trusted deserialisation
52
75
  * point.
53
76
  */
54
- exports.toEventJson = toEventJson;
55
77
  const rowToSequenced = row => ({
56
78
  event: {
57
79
  type: row.type,
58
80
  data: row.data ?? new Uint8Array(0),
59
81
  tags: row.tags,
60
82
  uuid: row.uuid,
61
- occurredAt: _effect.DateTime.unsafeFromDate(row.occurred_at)
83
+ occurredAt: _effect.DateTime.unsafeFromDate(row.occurred_at),
84
+ metadata: metadataFrom(row.metadata)
62
85
  },
63
86
  position: BigInt(row.id)
64
87
  });
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","names":["_effect","require","jsonbText","value","JSON","stringify","exports","toQueryItemsJson","query","items","map","item","types","tags","toEventJson","event","type","data","Encoding","encodeBase64","uuid","occurred_at","DateTime","formatIso","occurredAt","rowToSequenced","row","Uint8Array","unsafeFromDate","position","BigInt","id"],"sources":["../../../src/internal/transport.ts"],"sourcesContent":[null],"mappings":";;;;;;AAsBA,IAAAA,OAAA,GAAAC,OAAA;AAGA;;;;;;;;;;;;;AAaO,MAAMC,SAAS,GAAIC,KAAc,IAAaC,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC;AAQ1E;AAAAG,OAAA,CAAAJ,SAAA,GAAAA,SAAA;AACO,MAAMK,gBAAgB,GAAIC,KAAY,IAC3CA,KAAK,CAACC,KAAK,CAACC,GAAG,CAAEC,IAAI,KAAM;EACzBC,KAAK,EAAE,CAAC,GAAGD,IAAI,CAACC,KAAK,CAAC;EACtBC,IAAI,EAAE,CAAC,GAAGF,IAAI,CAACE,IAAI;CACpB,CAAC,CAAC;AA4BL;AAAAP,OAAA,CAAAC,gBAAA,GAAAA,gBAAA;AACO,MAAMO,WAAW,GAAIC,KAAe,KAAiB;EAC1DC,IAAI,EAAED,KAAK,CAACC,IAAI;EAChB;EACA;EACAC,IAAI,EAAEC,gBAAQ,CAACC,YAAY,CAACJ,KAAK,CAACE,IAAI,CAAC;EACvCJ,IAAI,EAAE,CAAC,GAAGE,KAAK,CAACF,IAAI,CAAC;EACrBO,IAAI,EAAEL,KAAK,CAACK,IAAI;EAChBC,WAAW,EAAEC,gBAAQ,CAACC,SAAS,CAACR,KAAK,CAACS,UAAU;CACjD,CAAC;AA4BF;;;;;;;;;;;;;;;AAAAlB,OAAA,CAAAQ,WAAA,GAAAA,WAAA;AAeO,MAAMW,cAAc,GAAIC,GAAa,KAAsB;EAChEX,KAAK,EAAE;IACLC,IAAI,EAAEU,GAAG,CAACV,IAAwB;IAClCC,IAAI,EAAES,GAAG,CAACT,IAAI,IAAI,IAAIU,UAAU,CAAC,CAAC,CAAC;IACnCd,IAAI,EAAEa,GAAG,CAACb,IAAmC;IAC7CO,IAAI,EAAEM,GAAG,CAACN,IAAwB;IAClCI,UAAU,EAAEF,gBAAQ,CAACM,cAAc,CAACF,GAAG,CAACL,WAAW;GACpD;EACDQ,QAAQ,EAAEC,MAAM,CAACJ,GAAG,CAACK,EAAE;CACxB,CAAC;AAAAzB,OAAA,CAAAmB,cAAA,GAAAA,cAAA","ignoreList":[]}
1
+ {"version":3,"file":"transport.js","names":["_effect","require","jsonbText","value","JSON","stringify","exports","toQueryItemsJson","query","items","map","item","types","tags","toEventJson","event","type","data","Encoding","encodeBase64","uuid","occurred_at","DateTime","formatIso","occurredAt","metadata","metadataFrom","Array","isArray","Error","rowToSequenced","row","Uint8Array","unsafeFromDate","position","BigInt","id"],"sources":["../../../src/internal/transport.ts"],"sourcesContent":[null],"mappings":";;;;;;AA4BA,IAAAA,OAAA,GAAAC,OAAA;AAGA;;;;;;;;;;;;;AAaO,MAAMC,SAAS,GAAIC,KAAc,IAAaC,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC;AAQ1E;AAAAG,OAAA,CAAAJ,SAAA,GAAAA,SAAA;AACO,MAAMK,gBAAgB,GAAIC,KAAY,IAC3CA,KAAK,CAACC,KAAK,CAACC,GAAG,CAAEC,IAAI,KAAM;EACzBC,KAAK,EAAE,CAAC,GAAGD,IAAI,CAACC,KAAK,CAAC;EACtBC,IAAI,EAAE,CAAC,GAAGF,IAAI,CAACE,IAAI;CACpB,CAAC,CAAC;AA+BL;AAAAP,OAAA,CAAAC,gBAAA,GAAAA,gBAAA;AACO,MAAMO,WAAW,GAAIC,KAAe,KAAiB;EAC1DC,IAAI,EAAED,KAAK,CAACC,IAAI;EAChB;EACA;EACAC,IAAI,EAAEC,gBAAQ,CAACC,YAAY,CAACJ,KAAK,CAACE,IAAI,CAAC;EACvCJ,IAAI,EAAE,CAAC,GAAGE,KAAK,CAACF,IAAI,CAAC;EACrBO,IAAI,EAAEL,KAAK,CAACK,IAAI;EAChBC,WAAW,EAAEC,gBAAQ,CAACC,SAAS,CAACR,KAAK,CAACS,UAAU,CAAC;EACjDC,QAAQ,EAAEV,KAAK,CAACU;CACjB,CAAC;AAgCF;;;;;;;;;;;;AAAAnB,OAAA,CAAAQ,WAAA,GAAAA,WAAA;AAYA,MAAMY,YAAY,GAAIvB,KAAc,IAAc;EAChD,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAIwB,KAAK,CAACC,OAAO,CAACzB,KAAK,CAAC,EAAE;IACvE,MAAM,IAAI0B,KAAK,CACb,sFAAsFzB,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC,IAAI,CAChH;EACH;EACA,OAAOA,KAAiB;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;AAkBO,MAAM2B,cAAc,GAAIC,GAAa,KAAsB;EAChEhB,KAAK,EAAE;IACLC,IAAI,EAAEe,GAAG,CAACf,IAAwB;IAClCC,IAAI,EAAEc,GAAG,CAACd,IAAI,IAAI,IAAIe,UAAU,CAAC,CAAC,CAAC;IACnCnB,IAAI,EAAEkB,GAAG,CAAClB,IAAmC;IAC7CO,IAAI,EAAEW,GAAG,CAACX,IAAwB;IAClCI,UAAU,EAAEF,gBAAQ,CAACW,cAAc,CAACF,GAAG,CAACV,WAAW,CAAC;IACpDI,QAAQ,EAAEC,YAAY,CAACK,GAAG,CAACN,QAAQ;GACpC;EACDS,QAAQ,EAAEC,MAAM,CAACJ,GAAG,CAACK,EAAE;CACxB,CAAC;AAAA9B,OAAA,CAAAwB,cAAA,GAAAA,cAAA","ignoreList":[]}
@@ -18,7 +18,12 @@
18
18
  * consumer, this package only provides the idempotent PAYLOAD.
19
19
  *
20
20
  * Idempotence: every statement is `CREATE … IF NOT EXISTS` or `CREATE OR REPLACE
21
- * FUNCTION`, so re-running against an existing store is a no-op. Names come from
21
+ * FUNCTION`, so re-running it is safe. It is NOT a no-op across versions: a
22
+ * re-run replaces the append functions with this version's, and does NOT alter
23
+ * an existing table, so a column a newer version adds must be added by hand
24
+ * before the re-run (the release notes give the statement). A store whose
25
+ * table gained a column but whose functions were never replaced keeps writing
26
+ * through the old ones, which do not know the column. Names come from
22
27
  * `sql(identifier)` (via the pre-quoted builder in `internal/ddl.ts`); the DDL
23
28
  * bodies carry no bound values (pure schema), and the append functions keep
24
29
  * their runtime VALUES as bound parameters, never interpolated.
@@ -1 +1 @@
1
- {"version":3,"file":"ensureSchema.d.ts","sourceRoot":"","sources":["../../src/ensureSchema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9E;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,mBAAmB,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,SAAS,CAQzD,CAAA"}
1
+ {"version":3,"file":"ensureSchema.d.ts","sourceRoot":"","sources":["../../src/ensureSchema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9E;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,mBAAmB,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,SAAS,CAQzD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../../src/internal/ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAQvD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAA;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,gDAAgD;AAChD,eAAO,MAAM,cAAc,WAAW,CAAA;AACtC,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,eAAe,CAAA;AAuChD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,KAAG,MAAM,GAAG,SAQZ,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,KAAG,aAkBH,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,MAIhC,CAAA;AA2Cd;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAuND;;;;;;;;;;GAUG;AACH,MAAM,MAAM,qBAAqB,GAC7B,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,GACpE,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAAG,iBAAiB,CAAC,CAAA;AAE5D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,aAAa,EACpB,SAAS,qBAAqB,KAC7B,MAqBF,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,aAAa,KAAG,aAAa,CAAC,MAAM,CA+DxE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GACjB,KAAK,SAAS,CAAC,SAAS,EACxB,OAAO,aAAa,KACnB,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CACmB,CAAA"}
1
+ {"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../../src/internal/ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAWvD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAA;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,gDAAgD;AAChD,eAAO,MAAM,cAAc,WAAW,CAAA;AACtC,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,eAAe,CAAA;AAuChD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,KAAG,MAAM,GAAG,SAQZ,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,KAAG,aAkBH,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,MAIhC,CAAA;AA2Cd;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAoOD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,qBAAqB,GAC7B,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,GACpE,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAAG,iBAAiB,CAAC,CAAA;AAE5D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,aAAa,EACpB,SAAS,qBAAqB,KAC7B,MAqBF,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,aAAa,KAAG,aAAa,CAAC,MAAM,CAmExE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GACjB,KAAK,SAAS,CAAC,SAAS,EACxB,OAAO,aAAa,KACnB,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CACmB,CAAA"}
@@ -32,7 +32,7 @@
32
32
  * that union, so a column rename here is a COMPILE error there, not a silent drift
33
33
  * the lax read boundary (ADR-0006) would only surface as corrupt data under test.
34
34
  */
35
- declare const EVENT_COLUMNS: readonly [readonly ["type", "text"], readonly ["data", "text"], readonly ["tags", "text[]"], readonly ["uuid", "text"], readonly ["occurred_at", "timestamptz"]];
35
+ declare const EVENT_COLUMNS: readonly [readonly ["type", "text"], readonly ["data", "text"], readonly ["tags", "text[]"], readonly ["uuid", "text"], readonly ["occurred_at", "timestamptz"], readonly ["metadata", "jsonb"]];
36
36
  /**
37
37
  * The event payload column NAMES as a string-literal union, derived from the ONE
38
38
  * `EVENT_COLUMNS` descriptor. `internal/transport.ts` builds its transport shapes
@@ -44,7 +44,8 @@ declare const EVENT_COLUMNS: readonly [readonly ["type", "text"], readonly ["dat
44
44
  export type EventColumnName = (typeof EVENT_COLUMNS)[number][0];
45
45
  /**
46
46
  * The `jsonb_to_recordset(new_events) AS (…)` column definitions —
47
- * `type text, data text, tags text[], uuid text, occurred_at timestamptz`. The
47
+ * `type text, data text, tags text[], uuid text, occurred_at timestamptz,
48
+ * metadata jsonb`. The
48
49
  * transport `data` is base64 TEXT (restored to `bytea` by `decode(…, 'base64')`
49
50
  * at insert), which is why it is `text` here, not `bytea`.
50
51
  */
@@ -55,6 +56,29 @@ export declare const eventRecordsetColumns: string;
55
56
  * cannot drift from the recordset.
56
57
  */
57
58
  export declare const readColumns: (prefix?: string) => string;
59
+ /**
60
+ * The alias the append body gives the expanded `new_events` recordset — the `ne`
61
+ * CTE in `ddl.ts` — which every expression in `EVENT_COLUMN_SOURCE` reads from.
62
+ * Exported so the CTE is declared under the one name its readers assume.
63
+ */
64
+ export declare const RECORDSET_ALIAS = "ne";
65
+ /**
66
+ * The bare event column names — `type, data, tags, uuid, occurred_at, metadata` —
67
+ * which the append body uses twice: as the recordset CTE's projection and as the
68
+ * `INSERT INTO t (…)` target list.
69
+ */
70
+ export declare const eventColumnList: string;
71
+ /**
72
+ * The append insert's SELECT list: one source expression per column, in the SAME
73
+ * ORDER as `eventColumnList`.
74
+ *
75
+ * The two halves of `INSERT INTO t (a, b) SELECT x, y` agree POSITION BY POSITION
76
+ * and nothing checks that they do: two columns of compatible type swap without an
77
+ * error at any layer and the data lands in the wrong one. Both halves are therefore
78
+ * one walk of the one descriptor, so the append body has no second ordering to keep
79
+ * in step and no hand-written list for a new column to be missing from.
80
+ */
81
+ export declare const eventInsertSelectList: string;
58
82
  /**
59
83
  * The allowed-types filter for a candidate row aliased `m`: an item with no
60
84
  * types matches ANY type; otherwise the event's type must be one of them.
@@ -1 +1 @@
1
- {"version":3,"file":"matchSql.d.ts","sourceRoot":"","sources":["../../../src/internal/matchSql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;;;GAUG;AACH,QAAA,MAAM,aAAa,kKAQlB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAExB,CAAA;AAEZ;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,eAAW,KAAG,MAGvC,CAAA;AAEH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MACkD,CAAA;AAE3G,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,WAAW,KAAG,MA6BnD,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAAC,KAC9C,MAImD,CAAA;AAEtD,kFAAkF;AAClF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAKnC,CAAA;AAEZ,4EAA4E;AAC5E,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAKnC,CAAA;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAG,MAWtC,CAAA"}
1
+ {"version":3,"file":"matchSql.d.ts","sourceRoot":"","sources":["../../../src/internal/matchSql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;;;GAUG;AACH,QAAA,MAAM,aAAa,kMASlB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAExB,CAAA;AAEZ;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,eAAW,KAAG,MAGvC,CAAA;AAEH;;;;GAIG;AACH,eAAO,MAAM,eAAe,OAAO,CAAA;AAqBnC;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAE7B,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAExB,CAAA;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MACkD,CAAA;AAE3G,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,WAAW,KAAG,MA6BnD,CAAA;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAAC,KAC9C,MAImD,CAAA;AAEtD,kFAAkF;AAClF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAKnC,CAAA;AAEZ,4EAA4E;AAC5E,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAKnC,CAAA;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,KAAK,MAAM,KAAG,MAWtC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"readPlan.d.ts","sourceRoot":"","sources":["../../../src/internal/readPlan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAiC,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC,OAAO,EAAE,KAAK,QAAQ,EAA+B,MAAM,aAAa,CAAA;AAExE,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,CACb,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,SAAS,GAAG,IAAI,KACpB,aAAa,CAAC,OAAO,CAAC,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,UAAU,EAClB,OAAO,KAAK,KACX,SA6BF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,SAAS,CAAC,SAAS,EACxB,MAAM,SAAS,EACf,OAAO,QAAQ,GAAG,SAAS,EAC3B,OAAO,SAAS,GAAG,SAAS,KAC3B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CACiB,CAAA"}
1
+ {"version":3,"file":"readPlan.d.ts","sourceRoot":"","sources":["../../../src/internal/readPlan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAiC,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEpC,OAAO,EAAE,KAAK,QAAQ,EAA+B,MAAM,aAAa,CAAA;AAExE,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,CACb,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,SAAS,GAAG,IAAI,KACpB,aAAa,CAAC,OAAO,CAAC,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,UAAU,EAClB,OAAO,KAAK,KACX,SAiCF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,SAAS,CAAC,SAAS,EACxB,MAAM,SAAS,EACf,OAAO,QAAQ,GAAG,SAAS,EAC3B,OAAO,SAAS,GAAG,SAAS,KAC3B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CACiB,CAAA"}
@@ -8,7 +8,7 @@
8
8
  * where transport code lives, and the two per-column type maps (`EventJson`,
9
9
  * `EventRow`) sit next to each other rather than in two files.
10
10
  *
11
- * The 5-column event contract stays single-sourced on `EventColumnName`
11
+ * The event column contract stays single-sourced on `EventColumnName`
12
12
  * (`internal/matchSql.ts`), the one column-NAME descriptor: both type maps here
13
13
  * are mapped types over it, so a column rename in `EVENT_COLUMNS` is a COMPILE
14
14
  * error in this module, never a silent transport drift the lax read boundary
@@ -19,7 +19,7 @@
19
19
  * (`toEventJson`) serialises `data` as base64 text and domain time as an ISO
20
20
  * string, both restored in SQL.
21
21
  */
22
- import type { DcbEvent, Query, SequencedEvent } from '@kairos-es/core';
22
+ import type { DcbEvent, Metadata, Query, SequencedEvent } from '@kairos-es/core';
23
23
  import type { EventColumnName } from './matchSql.js';
24
24
  /**
25
25
  * Serialise a value to a JSON STRING for transport as a `::jsonb`-cast bound
@@ -45,9 +45,11 @@ export declare const toQueryItemsJson: (query: Query) => ReadonlyArray<QueryItem
45
45
  /**
46
46
  * The per-column TS types of the transport JSON shape — one entry per
47
47
  * `EVENT_COLUMNS` name. `data` is base64 TEXT and `occurred_at` an ISO string
48
- * (both restored in SQL: `decode(…, 'base64')` / `timestamptz`); the rest map
49
- * straight across. Kept as a plain map so `EventJson` below is a mapped type over
50
- * the ONE column descriptor rather than a hand-restated column list.
48
+ * (both restored in SQL: `decode(…, 'base64')` / `timestamptz`); `metadata`
49
+ * travels as a nested JSON object, which `jsonb_to_recordset` hands to the
50
+ * insert as `jsonb` untouched; the rest map straight across. Kept as a plain
51
+ * map so `EventJson` below is a mapped type over the ONE column descriptor
52
+ * rather than a hand-restated column list.
51
53
  */
52
54
  interface EventJsonColumns {
53
55
  readonly type: string;
@@ -55,6 +57,7 @@ interface EventJsonColumns {
55
57
  readonly tags: ReadonlyArray<string>;
56
58
  readonly uuid: string;
57
59
  readonly occurred_at: string;
60
+ readonly metadata: Metadata;
58
61
  }
59
62
  /**
60
63
  * The JSON shape of one event as sent to the append functions, as a mapped type
@@ -73,7 +76,10 @@ export declare const toEventJson: (event: DcbEvent) => EventJson;
73
76
  /**
74
77
  * The per-column TS types of a raw driver row — one entry per `EVENT_COLUMNS`
75
78
  * name. These are node-postgres's decoded JS types: `data` a `Buffer` (or null
76
- * for a payload-less event), `occurred_at` a JS `Date`, `tags` a `string[]`. `id`
79
+ * for a payload-less event), `occurred_at` a JS `Date`, `tags` a `string[]`,
80
+ * `metadata` whatever node-postgres parses a `jsonb` value into — declared
81
+ * `unknown`, because `jsonb` is the one column here whose SQL type does not
82
+ * fix its JS shape, and `metadataFrom` below is where it is checked. `id`
77
83
  * (the `bigserial` position) is NOT here — it is prepended by the read projection
78
84
  * and absent from the events recordset, so it sits outside the shared descriptor.
79
85
  */
@@ -83,6 +89,7 @@ interface EventRowColumns {
83
89
  readonly tags: ReadonlyArray<string>;
84
90
  readonly uuid: string;
85
91
  readonly occurred_at: Date;
92
+ readonly metadata: unknown;
86
93
  }
87
94
  /**
88
95
  * A raw row from the main table as node-postgres returns it, as `id` plus a
@@ -99,7 +106,10 @@ export type EventRow = {
99
106
  /**
100
107
  * Map a raw main-table row to a core `SequencedEvent`. `data` NULL → empty bytes
101
108
  * (a payload-less event round-trips to a zero-length `Uint8Array`); `occurred_at`
102
- * Date → `DateTime.Utc`; `id` string → branded `Position`.
109
+ * Date → `DateTime.Utc`; `id` string → branded `Position`; `metadata` through
110
+ * `metadataFrom`. The column is `NOT NULL DEFAULT '{}'`, so there is no absent
111
+ * case to reconcile: an event appended with an empty bag reads back as `{}` on
112
+ * this engine exactly as on the in-memory oracle.
103
113
  *
104
114
  * The branded scalars (`type`, `tags`, `uuid`, `position`) are minted by trusted
105
115
  * `as`-cast, NOT by re-running `EventType.make` / `Tag.make` etc. This is
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAY,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,OAAO,KAAG,MAA+B,CAAA;AAE1E,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACrC;AAED,mEAAmE;AACnE,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,KAAG,aAAa,CAAC,aAAa,CAItE,CAAA;AAEL;;;;;;GAMG;AACH,UAAU,gBAAgB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,eAAe,GAAG,gBAAgB,CAAC,CAAC,CAAC;CAAE,CAAA;AAEhF,mEAAmE;AACnE,eAAO,MAAM,WAAW,GAAI,OAAO,QAAQ,KAAG,SAQ5C,CAAA;AAEF;;;;;;GAMG;AACH,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAC/C,QAAQ,EAAE,CAAC,IAAI,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;CACpD,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,QAAQ,KAAG,cAS7C,CAAA"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/internal/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EAER,KAAK,EACL,cAAc,EACf,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,OAAO,KAAG,MAA+B,CAAA;AAE1E,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACrC;AAED,mEAAmE;AACnE,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,KAAG,aAAa,CAAC,aAAa,CAItE,CAAA;AAEL;;;;;;;;GAQG;AACH,UAAU,gBAAgB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAC5B;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,eAAe,GAAG,gBAAgB,CAAC,CAAC,CAAC;CAAE,CAAA;AAEhF,mEAAmE;AACnE,eAAO,MAAM,WAAW,GAAI,OAAO,QAAQ,KAAG,SAS5C,CAAA;AAEF;;;;;;;;;GASG;AACH,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAC/C,QAAQ,EAAE,CAAC,IAAI,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;CACpD,CAAA;AAuBD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,QAAQ,KAAG,cAU7C,CAAA"}
@@ -18,7 +18,12 @@
18
18
  * consumer, this package only provides the idempotent PAYLOAD.
19
19
  *
20
20
  * Idempotence: every statement is `CREATE … IF NOT EXISTS` or `CREATE OR REPLACE
21
- * FUNCTION`, so re-running against an existing store is a no-op. Names come from
21
+ * FUNCTION`, so re-running it is safe. It is NOT a no-op across versions: a
22
+ * re-run replaces the append functions with this version's, and does NOT alter
23
+ * an existing table, so a column a newer version adds must be added by hand
24
+ * before the re-run (the release notes give the statement). A store whose
25
+ * table gained a column but whose functions were never replaced keeps writing
26
+ * through the old ones, which do not know the column. Names come from
22
27
  * `sql(identifier)` (via the pre-quoted builder in `internal/ddl.ts`); the DDL
23
28
  * bodies carry no bound values (pure schema), and the append functions keep
24
29
  * their runtime VALUES as bound parameters, never interpolated.
@@ -1 +1 @@
1
- {"version":3,"file":"ensureSchema.js","names":["SqlClient","Effect","decodePostgresStoreConfig","resolveNames","runDdl","ensureSchema","config","gen","sql","names","all","discard"],"sources":["../../src/ensureSchema.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAASA,SAAS,QAAuB,aAAa;AACtD,SAASC,MAAM,QAAQ,QAAQ;AAC/B,SAASC,yBAAyB,QAAkC,aAAU;AAC9E,SAASC,YAAY,EAAEC,MAAM,QAAQ,mBAAgB;AAErD;;;;;AAKA,OAAO,MAAMC,YAAY,GACvBC,MAA2B,IAE3BL,MAAM,CAACM,GAAG,CAAC,aAAS;EAClB,MAAMC,GAAG,GAAG,OAAOR,SAAS,CAACA,SAAS;EACtC;EACA;EACA,MAAMS,KAAK,GAAGN,YAAY,CAACD,yBAAyB,CAACI,MAAM,CAAC,CAAC;EAC7D;EACA,OAAOL,MAAM,CAACS,GAAG,CAACN,MAAM,CAACI,GAAG,EAAEC,KAAK,CAAC,EAAE;IAAEE,OAAO,EAAE;EAAI,CAAE,CAAC;AAC1D,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"ensureSchema.js","names":["SqlClient","Effect","decodePostgresStoreConfig","resolveNames","runDdl","ensureSchema","config","gen","sql","names","all","discard"],"sources":["../../src/ensureSchema.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAASA,SAAS,QAAuB,aAAa;AACtD,SAASC,MAAM,QAAQ,QAAQ;AAC/B,SAASC,yBAAyB,QAAkC,aAAU;AAC9E,SAASC,YAAY,EAAEC,MAAM,QAAQ,mBAAgB;AAErD;;;;;AAKA,OAAO,MAAMC,YAAY,GACvBC,MAA2B,IAE3BL,MAAM,CAACM,GAAG,CAAC,aAAS;EAClB,MAAMC,GAAG,GAAG,OAAOR,SAAS,CAACA,SAAS;EACtC;EACA;EACA,MAAMS,KAAK,GAAGN,YAAY,CAACD,yBAAyB,CAACI,MAAM,CAAC,CAAC;EAC7D;EACA,OAAOL,MAAM,CAACS,GAAG,CAACN,MAAM,CAACI,GAAG,EAAEC,KAAK,CAAC,EAAE;IAAEE,OAAO,EAAE;EAAI,CAAE,CAAC;AAC1D,CAAC,CAAC","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import { allowedTypesPredicate, eventRecordsetColumns, qualifiedRows, taggedMatchChain } from "./matchSql.js";
1
+ import { allowedTypesPredicate, eventColumnList, eventInsertSelectList, eventRecordsetColumns, qualifiedRows, RECORDSET_ALIAS, taggedMatchChain } from "./matchSql.js";
2
2
  /** Default schema when the config omits one. */
3
3
  export const DEFAULT_SCHEMA = 'public';
4
4
  /** Default table prefix when the config omits one. */
@@ -120,6 +120,16 @@ const lockClause = names => `LOCK TABLE ${quoteQualified(names.mainTable)} IN EX
120
120
  * preserves batch order, and `RETURNING id, tags` is captured into a temp
121
121
  * result set so the tag fan-out and the head can both read it. `data` arrives as
122
122
  * a base64 text field and is `decode(…, 'base64')`-restored to `bytea`.
123
+ *
124
+ * The recordset definition, its projection, the `INSERT INTO (…)` target list and
125
+ * the `SELECT` list are all derived from the one `EVENT_COLUMNS` descriptor in
126
+ * `matchSql.ts`, never written out here. The last two must agree POSITIONALLY and a
127
+ * mismatch is not an error, so deriving both from one walk is what keeps them from
128
+ * falling out of step; a column added without a source is a compile error there.
129
+ * What the compiler does NOT reach is whether the source READS the right field, or
130
+ * whether the column comes back out on the read; the round-trip contract group run
131
+ * against this engine is what proves a new column, and only with a value distinct
132
+ * per column, which is what makes a swap visible.
123
133
  */
124
134
  const insertFanoutNotify = (names, options = {}) => {
125
135
  const main = quoteQualified(names.mainTable);
@@ -137,18 +147,18 @@ const insertFanoutNotify = (names, options = {}) => {
137
147
  IF new_head IS NOT NULL THEN
138
148
  PERFORM pg_notify(${channel}, '1');
139
149
  END IF;` : '';
140
- return ` WITH ne AS (
141
- SELECT type, data, tags, uuid, occurred_at, ordinality
150
+ const ne = RECORDSET_ALIAS;
151
+ return ` WITH ${ne} AS (
152
+ SELECT ${eventColumnList}, ordinality
142
153
  FROM ROWS FROM(
143
154
  jsonb_to_recordset(new_events) AS (${eventRecordsetColumns})
144
155
  ) WITH ORDINALITY
145
156
  ),
146
157
  inserted AS (
147
- INSERT INTO ${main} (type, data, tags, uuid, occurred_at)
148
- SELECT ne.type, decode(ne.data, 'base64'), ne.tags, ne.uuid,
149
- ne.occurred_at
150
- FROM ne
151
- ORDER BY ne.ordinality
158
+ INSERT INTO ${main} (${eventColumnList})
159
+ SELECT ${eventInsertSelectList}
160
+ FROM ${ne}
161
+ ORDER BY ${ne}.ordinality
152
162
  RETURNING id, tags
153
163
  ),
154
164
  fanned AS (
@@ -197,9 +207,12 @@ const conditionalAppendBody = (names, options = {}) => {
197
207
  // its ITEMS — none at all, an item carrying no tags, an item carrying tags —
198
208
  // which between them cover every `Query` value the grammar can express, so a new
199
209
  // SHAPE changes which SQL the read compiles without changing what this body has
200
- // to match. The exposure is the GRAMMAR itself: a new `QueryItem` field, or a new
201
- // meaning for an existing one, is something this body ignores rather than fails
202
- // on, and no `switch` over the shape union would have caught that either.
210
+ // to match. The exposure is the GRAMMAR itself: a field ADDED to `QueryItem`, or a
211
+ // new meaning for an existing one, is something this body ignores rather than
212
+ // fails on, and no `switch` over the shape union would have caught that either. A
213
+ // key the grammar does NOT define never reaches this body: core's
214
+ // `servableQueryFault` refuses it at the contract boundary, which is what keeps a
215
+ // smuggled predicate from being dropped here in silence.
203
216
  const after = 'COALESCE(after_id, 0)';
204
217
  return `
205
218
  DECLARE
@@ -368,14 +381,18 @@ export const ddlStatements = names => {
368
381
  // positions — a rolled-back insert permanently consumes its id, which is
369
382
  // fine: ordering is by id alone and the store is never made gapless.
370
383
  // `data` is NULLABLE (a payload-less event is valid); `occurred_at` is
371
- // informational domain time, never an ordering key.
384
+ // informational domain time, never an ordering key. `metadata` is the
385
+ // event's cleartext context bag (ADR-0017): `jsonb` only so a containment
386
+ // index stays possible without a rewrite, though nothing queries it and no
387
+ // index is built; `NOT NULL DEFAULT '{}'` gives an empty bag one shape.
372
388
  `CREATE TABLE IF NOT EXISTS ${main} (
373
389
  id bigserial,
374
390
  type text NOT NULL,
375
391
  data bytea,
376
392
  tags text[] NOT NULL,
377
393
  uuid text NOT NULL,
378
- occurred_at timestamptz NOT NULL
394
+ occurred_at timestamptz NOT NULL,
395
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb
379
396
  ) WITH (${AUTOVACUUM_WITH});`,
380
397
  // Covering unique index: uniqueness on id plus INCLUDE(type) so the read
381
398
  // path's id→type lookups are index-only.
@@ -1 +1 @@
1
- {"version":3,"file":"ddl.js","names":["allowedTypesPredicate","eventRecordsetColumns","qualifiedRows","taggedMatchChain","DEFAULT_SCHEMA","DEFAULT_TABLE_PREFIX","MAX_IDENTIFIER_BYTES","utf8ByteLength","value","TextEncoder","encode","length","derivedAtoms","config","schema","tablePrefix","replace","oversizedIdentifier","label","atom","bytes","undefined","resolveNames","problem","Error","mainTable","tagTable","mainIndex","tagIndex","appendFn","appendUnconditionalFn","channel","quoteQualified","name","split","map","join","quoteAtom","quoteLiteral","AUTOVACUUM_WITH","lockClause","names","insertFanoutNotify","options","main","tag","notify","conditionalAppendBody","lock","after","queryItemsExpr","afterExpr","unconditionalAppendBody","appendFunctionStatement","qualifiedName","argList","body","kind","ddlStatements","runDdl","sql","statement","unsafe"],"sources":["../../../src/internal/ddl.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"ddl.js","names":["allowedTypesPredicate","eventColumnList","eventInsertSelectList","eventRecordsetColumns","qualifiedRows","RECORDSET_ALIAS","taggedMatchChain","DEFAULT_SCHEMA","DEFAULT_TABLE_PREFIX","MAX_IDENTIFIER_BYTES","utf8ByteLength","value","TextEncoder","encode","length","derivedAtoms","config","schema","tablePrefix","replace","oversizedIdentifier","label","atom","bytes","undefined","resolveNames","problem","Error","mainTable","tagTable","mainIndex","tagIndex","appendFn","appendUnconditionalFn","channel","quoteQualified","name","split","map","join","quoteAtom","quoteLiteral","AUTOVACUUM_WITH","lockClause","names","insertFanoutNotify","options","main","tag","notify","ne","conditionalAppendBody","lock","after","queryItemsExpr","afterExpr","unconditionalAppendBody","appendFunctionStatement","qualifiedName","argList","body","kind","ddlStatements","runDdl","sql","statement","unsafe"],"sources":["../../../src/internal/ddl.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -32,10 +32,11 @@
32
32
  * that union, so a column rename here is a COMPILE error there, not a silent drift
33
33
  * the lax read boundary (ADR-0006) would only surface as corrupt data under test.
34
34
  */
35
- const EVENT_COLUMNS = [['type', 'text'], ['data', 'text'], ['tags', 'text[]'], ['uuid', 'text'], ['occurred_at', 'timestamptz']];
35
+ const EVENT_COLUMNS = [['type', 'text'], ['data', 'text'], ['tags', 'text[]'], ['uuid', 'text'], ['occurred_at', 'timestamptz'], ['metadata', 'jsonb']];
36
36
  /**
37
37
  * The `jsonb_to_recordset(new_events) AS (…)` column definitions —
38
- * `type text, data text, tags text[], uuid text, occurred_at timestamptz`. The
38
+ * `type text, data text, tags text[], uuid text, occurred_at timestamptz,
39
+ * metadata jsonb`. The
39
40
  * transport `data` is base64 TEXT (restored to `bytea` by `decode(…, 'base64')`
40
41
  * at insert), which is why it is `text` here, not `bytea`.
41
42
  */
@@ -46,6 +47,47 @@ export const eventRecordsetColumns = /*#__PURE__*/EVENT_COLUMNS.map(([name, type
46
47
  * cannot drift from the recordset.
47
48
  */
48
49
  export const readColumns = (prefix = '') => [`${prefix}id`, ...EVENT_COLUMNS.map(([name]) => `${prefix}${name}`)].join(', ');
50
+ /**
51
+ * The alias the append body gives the expanded `new_events` recordset — the `ne`
52
+ * CTE in `ddl.ts` — which every expression in `EVENT_COLUMN_SOURCE` reads from.
53
+ * Exported so the CTE is declared under the one name its readers assume.
54
+ */
55
+ export const RECORDSET_ALIAS = 'ne';
56
+ /**
57
+ * What the append body inserts into each event column, read from the recordset row.
58
+ *
59
+ * Typed as a `Record` over `EventColumnName` so that adding a column to
60
+ * `EVENT_COLUMNS` without saying where its value comes from is a COMPILE error,
61
+ * rather than a column the insert silently leaves at its default. Every column but
62
+ * `data` passes through as the recordset already types it — `text[]` tags,
63
+ * `timestamptz`, `jsonb` metadata — because `jsonb_to_recordset` did the casting;
64
+ * `data` crosses as base64 TEXT and is restored to `bytea` here, its one decode.
65
+ */
66
+ const EVENT_COLUMN_SOURCE = {
67
+ type: `${RECORDSET_ALIAS}.type`,
68
+ data: `decode(${RECORDSET_ALIAS}.data, 'base64')`,
69
+ tags: `${RECORDSET_ALIAS}.tags`,
70
+ uuid: `${RECORDSET_ALIAS}.uuid`,
71
+ occurred_at: `${RECORDSET_ALIAS}.occurred_at`,
72
+ metadata: `${RECORDSET_ALIAS}.metadata`
73
+ };
74
+ /**
75
+ * The bare event column names — `type, data, tags, uuid, occurred_at, metadata` —
76
+ * which the append body uses twice: as the recordset CTE's projection and as the
77
+ * `INSERT INTO t (…)` target list.
78
+ */
79
+ export const eventColumnList = /*#__PURE__*/EVENT_COLUMNS.map(([name]) => name).join(', ');
80
+ /**
81
+ * The append insert's SELECT list: one source expression per column, in the SAME
82
+ * ORDER as `eventColumnList`.
83
+ *
84
+ * The two halves of `INSERT INTO t (a, b) SELECT x, y` agree POSITION BY POSITION
85
+ * and nothing checks that they do: two columns of compatible type swap without an
86
+ * error at any layer and the data lands in the wrong one. Both halves are therefore
87
+ * one walk of the one descriptor, so the append body has no second ordering to keep
88
+ * in step and no hand-written list for a new column to be missing from.
89
+ */
90
+ export const eventInsertSelectList = /*#__PURE__*/EVENT_COLUMNS.map(([name]) => EVENT_COLUMN_SOURCE[name]).join(', ');
49
91
  /**
50
92
  * The allowed-types filter for a candidate row aliased `m`: an item with no
51
93
  * types matches ANY type; otherwise the event's type must be one of them.
@@ -1 +1 @@
1
- {"version":3,"file":"matchSql.js","names":["EVENT_COLUMNS","eventRecordsetColumns","map","name","type","join","readColumns","prefix","allowedTypesPredicate","typesCol","taggedMatchChain","tokens","queryItemsExpr","tag","afterExpr","qualifiedRows","main","wildcardReadSql","typeOnlyReadSql","taggedReadSql"],"sources":["../../../src/internal/matchSql.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;AAwBA;;;;;;;;;;;AAWA,MAAMA,aAAa,GAAG,CACpB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAClB,CAAC,MAAM,EAAE,MAAM,CAAC,EAChB,CAAC,aAAa,EAAE,aAAa,CAAC,CAG/B;AAYD;;;;;;AAMA,OAAO,MAAMC,qBAAqB,gBAAWD,aAAa,CAACE,GAAG,CAC5D,CAAC,CAACC,IAAI,EAAEC,IAAI,CAAC,KAAK,GAAGD,IAAI,IAAIC,IAAI,EAAE,CACpC,CAACC,IAAI,CAAC,IAAI,CAAC;AAEZ;;;;;AAKA,OAAO,MAAMC,WAAW,GAAGA,CAACC,MAAM,GAAG,EAAE,KACrC,CAAC,GAAGA,MAAM,IAAI,EAAE,GAAGP,aAAa,CAACE,GAAG,CAAC,CAAC,CAACC,IAAI,CAAC,KAAK,GAAGI,MAAM,GAAGJ,IAAI,EAAE,CAAC,CAAC,CAACE,IAAI,CACxE,IAAI,CACL;AAEH;;;;;;AAMA,OAAO,MAAMG,qBAAqB,GAAIC,QAAgB,IACpD,iBAAiBA,QAAQ,gCAAgCA,QAAQ,4BAA4BA,QAAQ,IAAI;AAc3G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,OAAO,MAAMC,gBAAgB,GAAIC,MAAmB,IAClD;;;;;;;2BAOyBA,MAAM,CAACC,cAAc;;;;;;;WAOrCD,MAAM,CAACE,GAAG;wBACGF,MAAM,CAACG,SAAS;;;;;;;;;;;;;IAapC;AAEJ;;;;;;AAMA,OAAO,MAAMC,aAAa,GACxBJ,MAA+C,IAE/C;WACSA,MAAM,CAACK,IAAI;mBACHL,MAAM,CAACG,SAAS;YACvBN,qBAAqB,CAAC,iBAAiB,CAAC,EAAE;AAEtD;AACA,OAAO,MAAMS,eAAe,GAAID,IAAY,IAC1C,UAAUV,WAAW,EAAE;UACfU,IAAI;;;YAGF;AAEZ;AACA,OAAO,MAAME,eAAe,GAAIF,IAAY,IAC1C,UAAUV,WAAW,EAAE;UACfU,IAAI;;;YAGF;AAEZ;;;;;;AAMA,OAAO,MAAMG,aAAa,GAAGA,CAACH,IAAY,EAAEH,GAAW,KACrD,QAAQH,gBAAgB,CAAC;EAAEE,cAAc,EAAE,WAAW;EAAEE,SAAS,EAAE,IAAI;EAAEE,IAAI;EAAEH;AAAG,CAAE,CAAC;;;MAGjFE,aAAa,CAAC;EAAEC,IAAI;EAAEF,SAAS,EAAE;AAAI,CAAE,CAAC;;;;WAInCR,WAAW,CAAC,IAAI,CAAC;SACnBU,IAAI;;oBAEO","ignoreList":[]}
1
+ {"version":3,"file":"matchSql.js","names":["EVENT_COLUMNS","eventRecordsetColumns","map","name","type","join","readColumns","prefix","RECORDSET_ALIAS","EVENT_COLUMN_SOURCE","data","tags","uuid","occurred_at","metadata","eventColumnList","eventInsertSelectList","allowedTypesPredicate","typesCol","taggedMatchChain","tokens","queryItemsExpr","tag","afterExpr","qualifiedRows","main","wildcardReadSql","typeOnlyReadSql","taggedReadSql"],"sources":["../../../src/internal/matchSql.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -30,10 +30,14 @@ export const compileFetchPlan = (tables, query) => {
30
30
  case 'typeOnly':
31
31
  {
32
32
  // node-postgres binds a JS array param as a Postgres array literal, so
33
- // `type = ANY($2)` matches any of the item's types. The item's own list is
34
- // bound as it stands: a branded `EventType` IS its string to the driver, so
35
- // nothing here has to unwrap or copy it.
36
- const types = shape.types;
33
+ // `type = ANY($2)` matches any of the item's types. A branded `EventType` IS
34
+ // its string to the driver, so nothing has to be unwrapped — but the list is
35
+ // COPIED here, at compile time. The driver serialises the array afresh on
36
+ // every `bind`, and a subscription re-binds on every poll, so binding the
37
+ // caller's own array would let an edit the caller makes after subscribing
38
+ // reach the next fetch. The tagged arm is immune by construction, since it
39
+ // serialises once below; this copy is what makes the two arms agree.
40
+ const types = [...shape.types];
37
41
  return {
38
42
  text: typeOnlyReadSql(tables.main),
39
43
  bind: (after, limit) => [after, types, limit]
@@ -1 +1 @@
1
- {"version":3,"file":"readPlan.js","names":["classifyServableQuery","ORIGIN","taggedReadSql","typeOnlyReadSql","wildcardReadSql","jsonbText","toQueryItemsJson","compileFetchPlan","tables","query","shape","kind","text","main","bind","after","limit","types","itemsJson","tag","runFetch","sql","plan","unsafe"],"sources":["../../../src/internal/readPlan.ts"],"sourcesContent":[null],"mappings":"AAyBA,SAASA,qBAAqB,EAAEC,MAAM,QAAoB,iBAAiB;AAE3E,SAASC,aAAa,EAAEC,eAAe,EAAEC,eAAe,QAAQ,eAAY;AAC5E,SAAwBC,SAAS,EAAEC,gBAAgB,QAAQ,gBAAa;AA0BxE;;;;;;;;;;;;;;;;;;AAkBA,OAAO,MAAMC,gBAAgB,GAAGA,CAC9BC,MAAkB,EAClBC,KAAY,KACC;EACb,MAAMC,KAAK,GAAGV,qBAAqB,CAACS,KAAK,CAAC;EAC1C,QAAQC,KAAK,CAACC,IAAI;IAChB,KAAK,UAAU;MACb,OAAO;QACLC,IAAI,EAAER,eAAe,CAACI,MAAM,CAACK,IAAI,CAAC;QAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEC,KAAK;OACtC;IACH,KAAK,UAAU;MAAE;QACf;QACA;QACA;QACA;QACA,MAAMC,KAAK,GAAGP,KAAK,CAACO,KAAK;QACzB,OAAO;UACLL,IAAI,EAAET,eAAe,CAACK,MAAM,CAACK,IAAI,CAAC;UAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEE,KAAK,EAAED,KAAK;SAC7C;MACH;IACA,KAAK,QAAQ;MAAE;QACb;QACA;QACA,MAAME,SAAS,GAAGb,SAAS,CAACC,gBAAgB,CAACG,KAAK,CAAC,CAAC;QACpD,OAAO;UACLG,IAAI,EAAEV,aAAa,CAACM,MAAM,CAACK,IAAI,EAAEL,MAAM,CAACW,GAAG,CAAC;UAC5CL,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACE,SAAS,EAAEH,KAAK,EAAEC,KAAK;SACjD;MACH;EACF;AACF,CAAC;AAED;;;;AAIA,OAAO,MAAMI,QAAQ,GAAGA,CACtBC,GAAwB,EACxBC,IAAe,EACfP,KAA2B,EAC3BC,KAA4B,KAE5BK,GAAG,CAACE,MAAM,CAAWD,IAAI,CAACV,IAAI,EAAEU,IAAI,CAACR,IAAI,CAACC,KAAK,IAAId,MAAM,EAAEe,KAAK,IAAI,IAAI,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"readPlan.js","names":["classifyServableQuery","ORIGIN","taggedReadSql","typeOnlyReadSql","wildcardReadSql","jsonbText","toQueryItemsJson","compileFetchPlan","tables","query","shape","kind","text","main","bind","after","limit","types","itemsJson","tag","runFetch","sql","plan","unsafe"],"sources":["../../../src/internal/readPlan.ts"],"sourcesContent":[null],"mappings":"AAyBA,SAASA,qBAAqB,EAAEC,MAAM,QAAoB,iBAAiB;AAE3E,SAASC,aAAa,EAAEC,eAAe,EAAEC,eAAe,QAAQ,eAAY;AAC5E,SAAwBC,SAAS,EAAEC,gBAAgB,QAAQ,gBAAa;AA0BxE;;;;;;;;;;;;;;;;;;AAkBA,OAAO,MAAMC,gBAAgB,GAAGA,CAC9BC,MAAkB,EAClBC,KAAY,KACC;EACb,MAAMC,KAAK,GAAGV,qBAAqB,CAACS,KAAK,CAAC;EAC1C,QAAQC,KAAK,CAACC,IAAI;IAChB,KAAK,UAAU;MACb,OAAO;QACLC,IAAI,EAAER,eAAe,CAACI,MAAM,CAACK,IAAI,CAAC;QAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEC,KAAK;OACtC;IACH,KAAK,UAAU;MAAE;QACf;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,MAAMC,KAAK,GAAG,CAAC,GAAGP,KAAK,CAACO,KAAK,CAAC;QAC9B,OAAO;UACLL,IAAI,EAAET,eAAe,CAACK,MAAM,CAACK,IAAI,CAAC;UAClCC,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACD,KAAK,EAAEE,KAAK,EAAED,KAAK;SAC7C;MACH;IACA,KAAK,QAAQ;MAAE;QACb;QACA;QACA,MAAME,SAAS,GAAGb,SAAS,CAACC,gBAAgB,CAACG,KAAK,CAAC,CAAC;QACpD,OAAO;UACLG,IAAI,EAAEV,aAAa,CAACM,MAAM,CAACK,IAAI,EAAEL,MAAM,CAACW,GAAG,CAAC;UAC5CL,IAAI,EAAEA,CAACC,KAAK,EAAEC,KAAK,KAAK,CAACE,SAAS,EAAEH,KAAK,EAAEC,KAAK;SACjD;MACH;EACF;AACF,CAAC;AAED;;;;AAIA,OAAO,MAAMI,QAAQ,GAAGA,CACtBC,GAAwB,EACxBC,IAAe,EACfP,KAA2B,EAC3BC,KAA4B,KAE5BK,GAAG,CAACE,MAAM,CAAWD,IAAI,CAACV,IAAI,EAAEU,IAAI,CAACR,IAAI,CAACC,KAAK,IAAId,MAAM,EAAEe,KAAK,IAAI,IAAI,CAAC,CAAC","ignoreList":[]}
@@ -26,12 +26,34 @@ export const toEventJson = event => ({
26
26
  data: Encoding.encodeBase64(event.data),
27
27
  tags: [...event.tags],
28
28
  uuid: event.uuid,
29
- occurred_at: DateTime.formatIso(event.occurredAt)
29
+ occurred_at: DateTime.formatIso(event.occurredAt),
30
+ metadata: event.metadata
30
31
  });
32
+ /**
33
+ * The `metadata` column as the event's bag, checked to be a JSON OBJECT.
34
+ *
35
+ * The store only ever writes an object, but `jsonb` admits any JSON value — an
36
+ * array, a string, a number, a boolean, JSON `null` (which `NOT NULL` does not
37
+ * exclude) — so a hand-written row can hold one. Such a row is corrupt, and
38
+ * handing an event whose `metadata` is not a bag to every projection
39
+ * downstream is worse than stopping at the read. This is the CONTAINER check
40
+ * only; the shape rule itself has one home, core's `Metadata` doc. The VALUES
41
+ * are deliberately not re-checked as strings, because a value check on read
42
+ * alone would make an event the store accepted unreadable for ever.
43
+ */
44
+ const metadataFrom = value => {
45
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
46
+ throw new Error(`@kairos-es/store-postgres: the \`metadata\` column did not hold a JSON object (got ${JSON.stringify(value)}).`);
47
+ }
48
+ return value;
49
+ };
31
50
  /**
32
51
  * Map a raw main-table row to a core `SequencedEvent`. `data` NULL → empty bytes
33
52
  * (a payload-less event round-trips to a zero-length `Uint8Array`); `occurred_at`
34
- * Date → `DateTime.Utc`; `id` string → branded `Position`.
53
+ * Date → `DateTime.Utc`; `id` string → branded `Position`; `metadata` through
54
+ * `metadataFrom`. The column is `NOT NULL DEFAULT '{}'`, so there is no absent
55
+ * case to reconcile: an event appended with an empty bag reads back as `{}` on
56
+ * this engine exactly as on the in-memory oracle.
35
57
  *
36
58
  * The branded scalars (`type`, `tags`, `uuid`, `position`) are minted by trusted
37
59
  * `as`-cast, NOT by re-running `EventType.make` / `Tag.make` etc. This is
@@ -49,7 +71,8 @@ export const rowToSequenced = row => ({
49
71
  data: row.data ?? new Uint8Array(0),
50
72
  tags: row.tags,
51
73
  uuid: row.uuid,
52
- occurredAt: DateTime.unsafeFromDate(row.occurred_at)
74
+ occurredAt: DateTime.unsafeFromDate(row.occurred_at),
75
+ metadata: metadataFrom(row.metadata)
53
76
  },
54
77
  position: BigInt(row.id)
55
78
  });
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","names":["DateTime","Encoding","jsonbText","value","JSON","stringify","toQueryItemsJson","query","items","map","item","types","tags","toEventJson","event","type","data","encodeBase64","uuid","occurred_at","formatIso","occurredAt","rowToSequenced","row","Uint8Array","unsafeFromDate","position","BigInt","id"],"sources":["../../../src/internal/transport.ts"],"sourcesContent":[null],"mappings":"AAsBA,SAASA,QAAQ,EAAEC,QAAQ,QAAQ,QAAQ;AAG3C;;;;;;;;;;;;;AAaA,OAAO,MAAMC,SAAS,GAAIC,KAAc,IAAaC,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC;AAQ1E;AACA,OAAO,MAAMG,gBAAgB,GAAIC,KAAY,IAC3CA,KAAK,CAACC,KAAK,CAACC,GAAG,CAAEC,IAAI,KAAM;EACzBC,KAAK,EAAE,CAAC,GAAGD,IAAI,CAACC,KAAK,CAAC;EACtBC,IAAI,EAAE,CAAC,GAAGF,IAAI,CAACE,IAAI;CACpB,CAAC,CAAC;AA4BL;AACA,OAAO,MAAMC,WAAW,GAAIC,KAAe,KAAiB;EAC1DC,IAAI,EAAED,KAAK,CAACC,IAAI;EAChB;EACA;EACAC,IAAI,EAAEf,QAAQ,CAACgB,YAAY,CAACH,KAAK,CAACE,IAAI,CAAC;EACvCJ,IAAI,EAAE,CAAC,GAAGE,KAAK,CAACF,IAAI,CAAC;EACrBM,IAAI,EAAEJ,KAAK,CAACI,IAAI;EAChBC,WAAW,EAAEnB,QAAQ,CAACoB,SAAS,CAACN,KAAK,CAACO,UAAU;CACjD,CAAC;AA4BF;;;;;;;;;;;;;;;AAeA,OAAO,MAAMC,cAAc,GAAIC,GAAa,KAAsB;EAChET,KAAK,EAAE;IACLC,IAAI,EAAEQ,GAAG,CAACR,IAAwB;IAClCC,IAAI,EAAEO,GAAG,CAACP,IAAI,IAAI,IAAIQ,UAAU,CAAC,CAAC,CAAC;IACnCZ,IAAI,EAAEW,GAAG,CAACX,IAAmC;IAC7CM,IAAI,EAAEK,GAAG,CAACL,IAAwB;IAClCG,UAAU,EAAErB,QAAQ,CAACyB,cAAc,CAACF,GAAG,CAACJ,WAAW;GACpD;EACDO,QAAQ,EAAEC,MAAM,CAACJ,GAAG,CAACK,EAAE;CACxB,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"transport.js","names":["DateTime","Encoding","jsonbText","value","JSON","stringify","toQueryItemsJson","query","items","map","item","types","tags","toEventJson","event","type","data","encodeBase64","uuid","occurred_at","formatIso","occurredAt","metadata","metadataFrom","Array","isArray","Error","rowToSequenced","row","Uint8Array","unsafeFromDate","position","BigInt","id"],"sources":["../../../src/internal/transport.ts"],"sourcesContent":[null],"mappings":"AA4BA,SAASA,QAAQ,EAAEC,QAAQ,QAAQ,QAAQ;AAG3C;;;;;;;;;;;;;AAaA,OAAO,MAAMC,SAAS,GAAIC,KAAc,IAAaC,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC;AAQ1E;AACA,OAAO,MAAMG,gBAAgB,GAAIC,KAAY,IAC3CA,KAAK,CAACC,KAAK,CAACC,GAAG,CAAEC,IAAI,KAAM;EACzBC,KAAK,EAAE,CAAC,GAAGD,IAAI,CAACC,KAAK,CAAC;EACtBC,IAAI,EAAE,CAAC,GAAGF,IAAI,CAACE,IAAI;CACpB,CAAC,CAAC;AA+BL;AACA,OAAO,MAAMC,WAAW,GAAIC,KAAe,KAAiB;EAC1DC,IAAI,EAAED,KAAK,CAACC,IAAI;EAChB;EACA;EACAC,IAAI,EAAEf,QAAQ,CAACgB,YAAY,CAACH,KAAK,CAACE,IAAI,CAAC;EACvCJ,IAAI,EAAE,CAAC,GAAGE,KAAK,CAACF,IAAI,CAAC;EACrBM,IAAI,EAAEJ,KAAK,CAACI,IAAI;EAChBC,WAAW,EAAEnB,QAAQ,CAACoB,SAAS,CAACN,KAAK,CAACO,UAAU,CAAC;EACjDC,QAAQ,EAAER,KAAK,CAACQ;CACjB,CAAC;AAgCF;;;;;;;;;;;;AAYA,MAAMC,YAAY,GAAIpB,KAAc,IAAc;EAChD,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAIqB,KAAK,CAACC,OAAO,CAACtB,KAAK,CAAC,EAAE;IACvE,MAAM,IAAIuB,KAAK,CACb,sFAAsFtB,IAAI,CAACC,SAAS,CAACF,KAAK,CAAC,IAAI,CAChH;EACH;EACA,OAAOA,KAAiB;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;AAkBA,OAAO,MAAMwB,cAAc,GAAIC,GAAa,KAAsB;EAChEd,KAAK,EAAE;IACLC,IAAI,EAAEa,GAAG,CAACb,IAAwB;IAClCC,IAAI,EAAEY,GAAG,CAACZ,IAAI,IAAI,IAAIa,UAAU,CAAC,CAAC,CAAC;IACnCjB,IAAI,EAAEgB,GAAG,CAAChB,IAAmC;IAC7CM,IAAI,EAAEU,GAAG,CAACV,IAAwB;IAClCG,UAAU,EAAErB,QAAQ,CAAC8B,cAAc,CAACF,GAAG,CAACT,WAAW,CAAC;IACpDG,QAAQ,EAAEC,YAAY,CAACK,GAAG,CAACN,QAAQ;GACpC;EACDS,QAAQ,EAAEC,MAAM,CAACJ,GAAG,CAACK,EAAE;CACxB,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kairos-es/store-postgres",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.4",
4
4
  "description": "Postgres DcbEventStore backend for kairos-es",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
@@ -16,7 +16,7 @@
16
16
  "@effect/sql": "^0.52.0",
17
17
  "@effect/sql-pg": "^0.53.0",
18
18
  "effect": "^3.22.0",
19
- "@kairos-es/core": "^1.0.0-alpha.3"
19
+ "@kairos-es/core": "^1.0.0-alpha.4"
20
20
  },
21
21
  "main": "./dist/cjs/index.js",
22
22
  "module": "./dist/esm/index.js",
@@ -18,7 +18,12 @@
18
18
  * consumer, this package only provides the idempotent PAYLOAD.
19
19
  *
20
20
  * Idempotence: every statement is `CREATE … IF NOT EXISTS` or `CREATE OR REPLACE
21
- * FUNCTION`, so re-running against an existing store is a no-op. Names come from
21
+ * FUNCTION`, so re-running it is safe. It is NOT a no-op across versions: a
22
+ * re-run replaces the append functions with this version's, and does NOT alter
23
+ * an existing table, so a column a newer version adds must be added by hand
24
+ * before the re-run (the release notes give the statement). A store whose
25
+ * table gained a column but whose functions were never replaced keeps writing
26
+ * through the old ones, which do not know the column. Names come from
22
27
  * `sql(identifier)` (via the pre-quoted builder in `internal/ddl.ts`); the DDL
23
28
  * bodies carry no bound values (pure schema), and the append functions keep
24
29
  * their runtime VALUES as bound parameters, never interpolated.
@@ -28,8 +28,11 @@
28
28
  import type { SqlClient, Statement } from '@effect/sql'
29
29
  import {
30
30
  allowedTypesPredicate,
31
+ eventColumnList,
32
+ eventInsertSelectList,
31
33
  eventRecordsetColumns,
32
34
  qualifiedRows,
35
+ RECORDSET_ALIAS,
33
36
  taggedMatchChain,
34
37
  } from './matchSql'
35
38
 
@@ -250,6 +253,16 @@ export interface AppendBodyOptions {
250
253
  * preserves batch order, and `RETURNING id, tags` is captured into a temp
251
254
  * result set so the tag fan-out and the head can both read it. `data` arrives as
252
255
  * a base64 text field and is `decode(…, 'base64')`-restored to `bytea`.
256
+ *
257
+ * The recordset definition, its projection, the `INSERT INTO (…)` target list and
258
+ * the `SELECT` list are all derived from the one `EVENT_COLUMNS` descriptor in
259
+ * `matchSql.ts`, never written out here. The last two must agree POSITIONALLY and a
260
+ * mismatch is not an error, so deriving both from one walk is what keeps them from
261
+ * falling out of step; a column added without a source is a compile error there.
262
+ * What the compiler does NOT reach is whether the source READS the right field, or
263
+ * whether the column comes back out on the read; the round-trip contract group run
264
+ * against this engine is what proves a new column, and only with a value distinct
265
+ * per column, which is what makes a swap visible.
253
266
  */
254
267
  const insertFanoutNotify = (
255
268
  names: ResolvedNames,
@@ -273,18 +286,18 @@ const insertFanoutNotify = (
273
286
  PERFORM pg_notify(${channel}, '1');
274
287
  END IF;`
275
288
  : ''
276
- return ` WITH ne AS (
277
- SELECT type, data, tags, uuid, occurred_at, ordinality
289
+ const ne = RECORDSET_ALIAS
290
+ return ` WITH ${ne} AS (
291
+ SELECT ${eventColumnList}, ordinality
278
292
  FROM ROWS FROM(
279
293
  jsonb_to_recordset(new_events) AS (${eventRecordsetColumns})
280
294
  ) WITH ORDINALITY
281
295
  ),
282
296
  inserted AS (
283
- INSERT INTO ${main} (type, data, tags, uuid, occurred_at)
284
- SELECT ne.type, decode(ne.data, 'base64'), ne.tags, ne.uuid,
285
- ne.occurred_at
286
- FROM ne
287
- ORDER BY ne.ordinality
297
+ INSERT INTO ${main} (${eventColumnList})
298
+ SELECT ${eventInsertSelectList}
299
+ FROM ${ne}
300
+ ORDER BY ${ne}.ordinality
288
301
  RETURNING id, tags
289
302
  ),
290
303
  fanned AS (
@@ -337,9 +350,12 @@ const conditionalAppendBody = (
337
350
  // its ITEMS — none at all, an item carrying no tags, an item carrying tags —
338
351
  // which between them cover every `Query` value the grammar can express, so a new
339
352
  // SHAPE changes which SQL the read compiles without changing what this body has
340
- // to match. The exposure is the GRAMMAR itself: a new `QueryItem` field, or a new
341
- // meaning for an existing one, is something this body ignores rather than fails
342
- // on, and no `switch` over the shape union would have caught that either.
353
+ // to match. The exposure is the GRAMMAR itself: a field ADDED to `QueryItem`, or a
354
+ // new meaning for an existing one, is something this body ignores rather than
355
+ // fails on, and no `switch` over the shape union would have caught that either. A
356
+ // key the grammar does NOT define never reaches this body: core's
357
+ // `servableQueryFault` refuses it at the contract boundary, which is what keeps a
358
+ // smuggled predicate from being dropped here in silence.
343
359
  const after = 'COALESCE(after_id, 0)'
344
360
  return `
345
361
  DECLARE
@@ -537,14 +553,18 @@ export const ddlStatements = (names: ResolvedNames): ReadonlyArray<string> => {
537
553
  // positions — a rolled-back insert permanently consumes its id, which is
538
554
  // fine: ordering is by id alone and the store is never made gapless.
539
555
  // `data` is NULLABLE (a payload-less event is valid); `occurred_at` is
540
- // informational domain time, never an ordering key.
556
+ // informational domain time, never an ordering key. `metadata` is the
557
+ // event's cleartext context bag (ADR-0017): `jsonb` only so a containment
558
+ // index stays possible without a rewrite, though nothing queries it and no
559
+ // index is built; `NOT NULL DEFAULT '{}'` gives an empty bag one shape.
541
560
  `CREATE TABLE IF NOT EXISTS ${main} (
542
561
  id bigserial,
543
562
  type text NOT NULL,
544
563
  data bytea,
545
564
  tags text[] NOT NULL,
546
565
  uuid text NOT NULL,
547
- occurred_at timestamptz NOT NULL
566
+ occurred_at timestamptz NOT NULL,
567
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb
548
568
  ) WITH (${AUTOVACUUM_WITH});`,
549
569
 
550
570
  // Covering unique index: uniqueness on id plus INCLUDE(type) so the read
@@ -39,6 +39,7 @@ const EVENT_COLUMNS = [
39
39
  ['tags', 'text[]'],
40
40
  ['uuid', 'text'],
41
41
  ['occurred_at', 'timestamptz'],
42
+ ['metadata', 'jsonb'],
42
43
  ] as const satisfies ReadonlyArray<
43
44
  readonly [name: string, recordsetType: string]
44
45
  >
@@ -55,7 +56,8 @@ export type EventColumnName = (typeof EVENT_COLUMNS)[number][0]
55
56
 
56
57
  /**
57
58
  * The `jsonb_to_recordset(new_events) AS (…)` column definitions —
58
- * `type text, data text, tags text[], uuid text, occurred_at timestamptz`. The
59
+ * `type text, data text, tags text[], uuid text, occurred_at timestamptz,
60
+ * metadata jsonb`. The
59
61
  * transport `data` is base64 TEXT (restored to `bytea` by `decode(…, 'base64')`
60
62
  * at insert), which is why it is `text` here, not `bytea`.
61
63
  */
@@ -73,6 +75,55 @@ export const readColumns = (prefix = ''): string =>
73
75
  ', ',
74
76
  )
75
77
 
78
+ /**
79
+ * The alias the append body gives the expanded `new_events` recordset — the `ne`
80
+ * CTE in `ddl.ts` — which every expression in `EVENT_COLUMN_SOURCE` reads from.
81
+ * Exported so the CTE is declared under the one name its readers assume.
82
+ */
83
+ export const RECORDSET_ALIAS = 'ne'
84
+
85
+ /**
86
+ * What the append body inserts into each event column, read from the recordset row.
87
+ *
88
+ * Typed as a `Record` over `EventColumnName` so that adding a column to
89
+ * `EVENT_COLUMNS` without saying where its value comes from is a COMPILE error,
90
+ * rather than a column the insert silently leaves at its default. Every column but
91
+ * `data` passes through as the recordset already types it — `text[]` tags,
92
+ * `timestamptz`, `jsonb` metadata — because `jsonb_to_recordset` did the casting;
93
+ * `data` crosses as base64 TEXT and is restored to `bytea` here, its one decode.
94
+ */
95
+ const EVENT_COLUMN_SOURCE: Record<EventColumnName, string> = {
96
+ type: `${RECORDSET_ALIAS}.type`,
97
+ data: `decode(${RECORDSET_ALIAS}.data, 'base64')`,
98
+ tags: `${RECORDSET_ALIAS}.tags`,
99
+ uuid: `${RECORDSET_ALIAS}.uuid`,
100
+ occurred_at: `${RECORDSET_ALIAS}.occurred_at`,
101
+ metadata: `${RECORDSET_ALIAS}.metadata`,
102
+ }
103
+
104
+ /**
105
+ * The bare event column names — `type, data, tags, uuid, occurred_at, metadata` —
106
+ * which the append body uses twice: as the recordset CTE's projection and as the
107
+ * `INSERT INTO t (…)` target list.
108
+ */
109
+ export const eventColumnList: string = EVENT_COLUMNS.map(([name]) => name).join(
110
+ ', ',
111
+ )
112
+
113
+ /**
114
+ * The append insert's SELECT list: one source expression per column, in the SAME
115
+ * ORDER as `eventColumnList`.
116
+ *
117
+ * The two halves of `INSERT INTO t (a, b) SELECT x, y` agree POSITION BY POSITION
118
+ * and nothing checks that they do: two columns of compatible type swap without an
119
+ * error at any layer and the data lands in the wrong one. Both halves are therefore
120
+ * one walk of the one descriptor, so the append body has no second ordering to keep
121
+ * in step and no hand-written list for a new column to be missing from.
122
+ */
123
+ export const eventInsertSelectList: string = EVENT_COLUMNS.map(
124
+ ([name]) => EVENT_COLUMN_SOURCE[name],
125
+ ).join(', ')
126
+
76
127
  /**
77
128
  * The allowed-types filter for a candidate row aliased `m`: an item with no
78
129
  * types matches ANY type; otherwise the event's type must be one of them.
@@ -83,10 +83,14 @@ export const compileFetchPlan = (
83
83
  }
84
84
  case 'typeOnly': {
85
85
  // node-postgres binds a JS array param as a Postgres array literal, so
86
- // `type = ANY($2)` matches any of the item's types. The item's own list is
87
- // bound as it stands: a branded `EventType` IS its string to the driver, so
88
- // nothing here has to unwrap or copy it.
89
- const types = shape.types
86
+ // `type = ANY($2)` matches any of the item's types. A branded `EventType` IS
87
+ // its string to the driver, so nothing has to be unwrapped — but the list is
88
+ // COPIED here, at compile time. The driver serialises the array afresh on
89
+ // every `bind`, and a subscription re-binds on every poll, so binding the
90
+ // caller's own array would let an edit the caller makes after subscribing
91
+ // reach the next fetch. The tagged arm is immune by construction, since it
92
+ // serialises once below; this copy is what makes the two arms agree.
93
+ const types = [...shape.types]
90
94
  return {
91
95
  text: typeOnlyReadSql(tables.main),
92
96
  bind: (after, limit) => [after, types, limit],
@@ -8,7 +8,7 @@
8
8
  * where transport code lives, and the two per-column type maps (`EventJson`,
9
9
  * `EventRow`) sit next to each other rather than in two files.
10
10
  *
11
- * The 5-column event contract stays single-sourced on `EventColumnName`
11
+ * The event column contract stays single-sourced on `EventColumnName`
12
12
  * (`internal/matchSql.ts`), the one column-NAME descriptor: both type maps here
13
13
  * are mapped types over it, so a column rename in `EVENT_COLUMNS` is a COMPILE
14
14
  * error in this module, never a silent transport drift the lax read boundary
@@ -19,7 +19,13 @@
19
19
  * (`toEventJson`) serialises `data` as base64 text and domain time as an ISO
20
20
  * string, both restored in SQL.
21
21
  */
22
- import type { DcbEvent, Position, Query, SequencedEvent } from '@kairos-es/core'
22
+ import type {
23
+ DcbEvent,
24
+ Metadata,
25
+ Position,
26
+ Query,
27
+ SequencedEvent,
28
+ } from '@kairos-es/core'
23
29
  import { DateTime, Encoding } from 'effect'
24
30
  import type { EventColumnName } from './matchSql'
25
31
 
@@ -54,9 +60,11 @@ export const toQueryItemsJson = (query: Query): ReadonlyArray<QueryItemJson> =>
54
60
  /**
55
61
  * The per-column TS types of the transport JSON shape — one entry per
56
62
  * `EVENT_COLUMNS` name. `data` is base64 TEXT and `occurred_at` an ISO string
57
- * (both restored in SQL: `decode(…, 'base64')` / `timestamptz`); the rest map
58
- * straight across. Kept as a plain map so `EventJson` below is a mapped type over
59
- * the ONE column descriptor rather than a hand-restated column list.
63
+ * (both restored in SQL: `decode(…, 'base64')` / `timestamptz`); `metadata`
64
+ * travels as a nested JSON object, which `jsonb_to_recordset` hands to the
65
+ * insert as `jsonb` untouched; the rest map straight across. Kept as a plain
66
+ * map so `EventJson` below is a mapped type over the ONE column descriptor
67
+ * rather than a hand-restated column list.
60
68
  */
61
69
  interface EventJsonColumns {
62
70
  readonly type: string
@@ -64,6 +72,7 @@ interface EventJsonColumns {
64
72
  readonly tags: ReadonlyArray<string>
65
73
  readonly uuid: string
66
74
  readonly occurred_at: string
75
+ readonly metadata: Metadata
67
76
  }
68
77
 
69
78
  /**
@@ -86,12 +95,16 @@ export const toEventJson = (event: DcbEvent): EventJson => ({
86
95
  tags: [...event.tags],
87
96
  uuid: event.uuid,
88
97
  occurred_at: DateTime.formatIso(event.occurredAt),
98
+ metadata: event.metadata,
89
99
  })
90
100
 
91
101
  /**
92
102
  * The per-column TS types of a raw driver row — one entry per `EVENT_COLUMNS`
93
103
  * name. These are node-postgres's decoded JS types: `data` a `Buffer` (or null
94
- * for a payload-less event), `occurred_at` a JS `Date`, `tags` a `string[]`. `id`
104
+ * for a payload-less event), `occurred_at` a JS `Date`, `tags` a `string[]`,
105
+ * `metadata` whatever node-postgres parses a `jsonb` value into — declared
106
+ * `unknown`, because `jsonb` is the one column here whose SQL type does not
107
+ * fix its JS shape, and `metadataFrom` below is where it is checked. `id`
95
108
  * (the `bigserial` position) is NOT here — it is prepended by the read projection
96
109
  * and absent from the events recordset, so it sits outside the shared descriptor.
97
110
  */
@@ -101,6 +114,7 @@ interface EventRowColumns {
101
114
  readonly tags: ReadonlyArray<string>
102
115
  readonly uuid: string
103
116
  readonly occurred_at: Date
117
+ readonly metadata: unknown
104
118
  }
105
119
 
106
120
  /**
@@ -114,10 +128,34 @@ export type EventRow = { readonly id: string } & {
114
128
  readonly [K in EventColumnName]: EventRowColumns[K]
115
129
  }
116
130
 
131
+ /**
132
+ * The `metadata` column as the event's bag, checked to be a JSON OBJECT.
133
+ *
134
+ * The store only ever writes an object, but `jsonb` admits any JSON value — an
135
+ * array, a string, a number, a boolean, JSON `null` (which `NOT NULL` does not
136
+ * exclude) — so a hand-written row can hold one. Such a row is corrupt, and
137
+ * handing an event whose `metadata` is not a bag to every projection
138
+ * downstream is worse than stopping at the read. This is the CONTAINER check
139
+ * only; the shape rule itself has one home, core's `Metadata` doc. The VALUES
140
+ * are deliberately not re-checked as strings, because a value check on read
141
+ * alone would make an event the store accepted unreadable for ever.
142
+ */
143
+ const metadataFrom = (value: unknown): Metadata => {
144
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
145
+ throw new Error(
146
+ `@kairos-es/store-postgres: the \`metadata\` column did not hold a JSON object (got ${JSON.stringify(value)}).`,
147
+ )
148
+ }
149
+ return value as Metadata
150
+ }
151
+
117
152
  /**
118
153
  * Map a raw main-table row to a core `SequencedEvent`. `data` NULL → empty bytes
119
154
  * (a payload-less event round-trips to a zero-length `Uint8Array`); `occurred_at`
120
- * Date → `DateTime.Utc`; `id` string → branded `Position`.
155
+ * Date → `DateTime.Utc`; `id` string → branded `Position`; `metadata` through
156
+ * `metadataFrom`. The column is `NOT NULL DEFAULT '{}'`, so there is no absent
157
+ * case to reconcile: an event appended with an empty bag reads back as `{}` on
158
+ * this engine exactly as on the in-memory oracle.
121
159
  *
122
160
  * The branded scalars (`type`, `tags`, `uuid`, `position`) are minted by trusted
123
161
  * `as`-cast, NOT by re-running `EventType.make` / `Tag.make` etc. This is
@@ -136,6 +174,7 @@ export const rowToSequenced = (row: EventRow): SequencedEvent => ({
136
174
  tags: row.tags as unknown as DcbEvent['tags'],
137
175
  uuid: row.uuid as DcbEvent['uuid'],
138
176
  occurredAt: DateTime.unsafeFromDate(row.occurred_at),
177
+ metadata: metadataFrom(row.metadata),
139
178
  },
140
179
  position: BigInt(row.id) as Position,
141
180
  })