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

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 (91) hide show
  1. package/README.md +61 -29
  2. package/dist/cjs/clients.js +34 -24
  3. package/dist/cjs/clients.js.map +1 -1
  4. package/dist/cjs/config.js +9 -15
  5. package/dist/cjs/config.js.map +1 -1
  6. package/dist/cjs/ensureSchema.js +8 -3
  7. package/dist/cjs/ensureSchema.js.map +1 -1
  8. package/dist/cjs/index.js.map +1 -1
  9. package/dist/cjs/internal/ddl.js +29 -12
  10. package/dist/cjs/internal/ddl.js.map +1 -1
  11. package/dist/cjs/internal/matchSql.js +57 -4
  12. package/dist/cjs/internal/matchSql.js.map +1 -1
  13. package/dist/cjs/internal/readPlan.js +33 -5
  14. package/dist/cjs/internal/readPlan.js.map +1 -1
  15. package/dist/cjs/internal/transport.js +42 -15
  16. package/dist/cjs/internal/transport.js.map +1 -1
  17. package/dist/cjs/store.js +30 -25
  18. package/dist/cjs/store.js.map +1 -1
  19. package/dist/dts-cjs/clients.d.ts +66 -0
  20. package/dist/dts-cjs/clients.d.ts.map +1 -0
  21. package/dist/{dts → dts-cjs}/config.d.ts +9 -19
  22. package/dist/{dts → dts-cjs}/config.d.ts.map +1 -1
  23. package/dist/{dts → dts-cjs}/ensureSchema.d.ts +8 -3
  24. package/dist/dts-cjs/ensureSchema.d.ts.map +1 -0
  25. package/dist/{dts → dts-cjs}/index.d.ts +4 -3
  26. package/dist/dts-cjs/index.d.ts.map +1 -0
  27. package/dist/{dts → dts-cjs}/internal/ddl.d.ts +1 -1
  28. package/dist/{dts → dts-cjs}/internal/ddl.d.ts.map +1 -1
  29. package/dist/{dts → dts-cjs}/internal/matchSql.d.ts +26 -2
  30. package/dist/dts-cjs/internal/matchSql.d.ts.map +1 -0
  31. package/dist/{dts → dts-cjs}/internal/readPlan.d.ts +1 -1
  32. package/dist/{dts → dts-cjs}/internal/readPlan.d.ts.map +1 -1
  33. package/dist/{dts → dts-cjs}/internal/transport.d.ts +34 -19
  34. package/dist/dts-cjs/internal/transport.d.ts.map +1 -0
  35. package/dist/dts-cjs/package.json +3 -0
  36. package/dist/dts-cjs/store.d.ts.map +1 -0
  37. package/dist/dts-esm/clients.d.ts +66 -0
  38. package/dist/dts-esm/clients.d.ts.map +1 -0
  39. package/dist/dts-esm/config.d.ts +48 -0
  40. package/dist/dts-esm/config.d.ts.map +1 -0
  41. package/dist/dts-esm/ensureSchema.d.ts +40 -0
  42. package/dist/dts-esm/ensureSchema.d.ts.map +1 -0
  43. package/dist/dts-esm/index.d.ts +42 -0
  44. package/dist/dts-esm/index.d.ts.map +1 -0
  45. package/dist/dts-esm/internal/ddl.d.ts +174 -0
  46. package/dist/dts-esm/internal/ddl.d.ts.map +1 -0
  47. package/dist/dts-esm/internal/matchSql.d.ts +164 -0
  48. package/dist/dts-esm/internal/matchSql.d.ts.map +1 -0
  49. package/dist/dts-esm/internal/readPlan.d.ts +72 -0
  50. package/dist/dts-esm/internal/readPlan.d.ts.map +1 -0
  51. package/dist/dts-esm/internal/transport.d.ts +131 -0
  52. package/dist/dts-esm/internal/transport.d.ts.map +1 -0
  53. package/dist/dts-esm/package.json +3 -0
  54. package/dist/dts-esm/store.d.ts +17 -0
  55. package/dist/dts-esm/store.d.ts.map +1 -0
  56. package/dist/esm/clients.js +34 -24
  57. package/dist/esm/clients.js.map +1 -1
  58. package/dist/esm/config.js +9 -15
  59. package/dist/esm/config.js.map +1 -1
  60. package/dist/esm/ensureSchema.js +8 -3
  61. package/dist/esm/ensureSchema.js.map +1 -1
  62. package/dist/esm/index.js +4 -3
  63. package/dist/esm/index.js.map +1 -1
  64. package/dist/esm/internal/ddl.js +30 -13
  65. package/dist/esm/internal/ddl.js.map +1 -1
  66. package/dist/esm/internal/matchSql.js +55 -2
  67. package/dist/esm/internal/matchSql.js.map +1 -1
  68. package/dist/esm/internal/readPlan.js +32 -5
  69. package/dist/esm/internal/readPlan.js.map +1 -1
  70. package/dist/esm/internal/transport.js +42 -15
  71. package/dist/esm/internal/transport.js.map +1 -1
  72. package/dist/esm/store.js +30 -25
  73. package/dist/esm/store.js.map +1 -1
  74. package/package.json +13 -11
  75. package/src/clients.ts +43 -31
  76. package/src/config.ts +12 -13
  77. package/src/ensureSchema.ts +8 -3
  78. package/src/index.ts +4 -3
  79. package/src/internal/ddl.ts +33 -13
  80. package/src/internal/matchSql.ts +63 -1
  81. package/src/internal/readPlan.ts +11 -6
  82. package/src/internal/transport.ts +71 -24
  83. package/src/store.ts +35 -28
  84. package/dist/dts/clients.d.ts +0 -34
  85. package/dist/dts/clients.d.ts.map +0 -1
  86. package/dist/dts/ensureSchema.d.ts.map +0 -1
  87. package/dist/dts/index.d.ts.map +0 -1
  88. package/dist/dts/internal/matchSql.d.ts.map +0 -1
  89. package/dist/dts/internal/transport.d.ts.map +0 -1
  90. package/dist/dts/store.d.ts.map +0 -1
  91. /package/dist/{dts → dts-cjs}/store.d.ts +0 -0
@@ -7,6 +7,30 @@ exports.runFetch = exports.compileFetchPlan = void 0;
7
7
  var _core = require("@kairos-es/core");
8
8
  var _matchSql = require("./matchSql.js");
9
9
  var _transport = require("./transport.js");
10
+ /**
11
+ * The read-plan compiler for the Postgres engine, extracted from `store.ts` so it
12
+ * is a self-contained unit depending only on the PRE-QUOTED table names — never on
13
+ * the SQL clients. `store.ts`'s `read` and its `subscribe` — the latter feeding the
14
+ * plan to core's subscribe machine as that machine's `fetch` seam — both compile a
15
+ * plan here and run it against whichever client they hold.
16
+ *
17
+ * `compileFetchPlan` turns a servable `Query` into prepared SQL text plus a
18
+ * cursor-only `bind`, so a long-lived subscription re-binds only the cursor rather
19
+ * than re-dispatching the shape and re-serialising the query JSON on every poll.
20
+ * Which shape a query IS is not decided here: core's `classifyServableQuery` owns
21
+ * that dispatch beside the grammar it dispatches over (`Query.ts`), including the
22
+ * degenerate empty item's routing. The JSON/JSONB transport shapes and
23
+ * (de)serialisers — `EventRow`, `jsonbText`, `toQueryItemsJson`, `rowToSequenced`
24
+ * — live in `internal/transport.ts`, and this module only compiles plans.
25
+ *
26
+ * A plan compiled here is therefore the one place the Postgres engine dispatches
27
+ * a shape in TypeScript, and the exhaustiveness below protects BOTH verbs that
28
+ * compile one — `read`, and the `subscribe` poll sharing its plan. What it cannot
29
+ * reach is the append: its conflict guard covers the same three shapes inside its
30
+ * plpgsql body, where no compiler follows, and `ddl.ts` owns what that rests on
31
+ * instead.
32
+ */
33
+
10
34
  /**
11
35
  * Compile a servable query into a `FetchPlan`. The SQL comes from the shared
12
36
  * `matchSql` builders (the tagged path composes the same emitted match chain as the
@@ -35,11 +59,15 @@ const compileFetchPlan = (tables, query) => {
35
59
  };
36
60
  case 'typeOnly':
37
61
  {
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;
62
+ // `@effect/sql-pg` binds a JS array of strings as a `text[]` param, so
63
+ // `type = ANY($2)` matches any of the item's types. A branded `EventType` IS
64
+ // its string to the driver, so nothing has to be unwrapped — but the list is
65
+ // COPIED here, at compile time. The driver serialises the array afresh on
66
+ // every `bind`, and a subscription re-binds on every poll, so binding the
67
+ // caller's own array would let an edit the caller makes after subscribing
68
+ // reach the next fetch. The tagged arm is immune by construction, since it
69
+ // serialises once below; this copy is what makes the two arms agree.
70
+ const types = [...shape.types];
43
71
  return {
44
72
  text: (0, _matchSql.typeOnlyReadSql)(tables.main),
45
73
  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;AAGA,IAAAC,SAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AA7BA;;;;;;;;;;;;;;;;;;;;;;;;AAuDA;;;;;;;;;;;;;;;;;;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":[]}
@@ -5,18 +5,20 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.toQueryItemsJson = exports.toEventJson = exports.rowToSequenced = exports.jsonbText = void 0;
7
7
  var _effect = require("effect");
8
+ var _encoding = require("effect/encoding");
8
9
  /**
9
10
  * Serialise a value to a JSON STRING for transport as a `::jsonb`-cast bound
10
11
  * parameter.
11
12
  *
12
- * WHY not `sql.json(value)`: `@effect/sql-pg`'s `json` helper binds the RAW
13
- * value, and node-postgres serialises a JS *array* bound param as a Postgres
14
- * ARRAY literal (`{…}`), not JSON — so `sql.json([...])::jsonb` fails with a
15
- * `22P02` invalid-JSON error (an array literal is not valid JSON). Passing a
16
- * pre-stringified JSON string and casting `::jsonb` sends plain text that
17
- * Postgres parses as JSON, which round-trips reliably for both objects and
18
- * arrays. Kept as a named helper so every JSON-transport call site is consistent
19
- * and the reasoning lives in one place.
13
+ * WHY a string and not `sql.json(value)`: the read plan runs through
14
+ * `sql.unsafe(text, params)` with POSITIONAL parameters, and a positional
15
+ * parameter must be a plain scalar or a flat array of scalars — `@effect/sql-pg`
16
+ * cannot infer a Postgres type for an object or an array of objects, and a
17
+ * `sql.json` fragment is not a value that list can carry. A pre-stringified
18
+ * JSON string binds untyped and the `::jsonb` cast has Postgres parse it, which
19
+ * round-trips reliably for both objects and arrays on the positional path and
20
+ * the tagged-template path alike. Kept as a named helper so every
21
+ * JSON-transport call site is consistent and the reasoning lives in one place.
20
22
  */
21
23
  const jsonbText = value => JSON.stringify(value);
22
24
  /** Serialise a `Query`'s items into their transport JSON shape. */
@@ -29,17 +31,42 @@ const toQueryItemsJson = query => query.items.map(item => ({
29
31
  exports.toQueryItemsJson = toQueryItemsJson;
30
32
  const toEventJson = event => ({
31
33
  type: event.type,
32
- // `Encoding.encodeBase64` (from `effect`) keeps this dependency-free and pure
33
- // — no `Buffer`, so no `@types/node` and no browser/runtime coupling.
34
- data: _effect.Encoding.encodeBase64(event.data),
34
+ // `Base64.encode` (from `effect/encoding`) keeps this dependency-free and pure
35
+ // — no `Buffer`, so no `@types/node` and no browser/runtime coupling. It emits
36
+ // the standard RFC 4648 alphabet with `=` padding, which is what plpgsql's
37
+ // `decode(…, 'base64')` reads.
38
+ data: _encoding.Base64.encode(event.data),
35
39
  tags: [...event.tags],
36
40
  uuid: event.uuid,
37
- occurred_at: _effect.DateTime.formatIso(event.occurredAt)
41
+ occurred_at: _effect.DateTime.formatIso(event.occurredAt),
42
+ metadata: event.metadata
38
43
  });
44
+ /**
45
+ * The `metadata` column as the event's bag, checked to be a JSON OBJECT.
46
+ *
47
+ * The store only ever writes an object, but `jsonb` admits any JSON value — an
48
+ * array, a string, a number, a boolean, JSON `null` (which `NOT NULL` does not
49
+ * exclude) — so a hand-written row can hold one. Such a row is corrupt, and
50
+ * handing an event whose `metadata` is not a bag to every projection
51
+ * downstream is worse than stopping at the read. This is the CONTAINER check
52
+ * only; the shape rule itself has one home, core's `Metadata` doc. The VALUES
53
+ * are deliberately not re-checked as strings, because a value check on read
54
+ * alone would make an event the store accepted unreadable for ever.
55
+ */
56
+ exports.toEventJson = toEventJson;
57
+ const metadataFrom = value => {
58
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
59
+ throw new Error(`@kairos-es/store-postgres: the \`metadata\` column did not hold a JSON object (got ${JSON.stringify(value)}).`);
60
+ }
61
+ return value;
62
+ };
39
63
  /**
40
64
  * Map a raw main-table row to a core `SequencedEvent`. `data` NULL → empty bytes
41
65
  * (a payload-less event round-trips to a zero-length `Uint8Array`); `occurred_at`
42
- * Date → `DateTime.Utc`; `id` string → branded `Position`.
66
+ * Date → `DateTime.Utc`; `id` → branded `Position`; `metadata` through
67
+ * `metadataFrom`. The column is `NOT NULL DEFAULT '{}'`, so there is no absent
68
+ * case to reconcile: an event appended with an empty bag reads back as `{}` on
69
+ * this engine exactly as on the in-memory oracle.
43
70
  *
44
71
  * The branded scalars (`type`, `tags`, `uuid`, `position`) are minted by trusted
45
72
  * `as`-cast, NOT by re-running `EventType.make` / `Tag.make` etc. This is
@@ -51,14 +78,14 @@ const toEventJson = event => ({
51
78
  * (`inMemory.ts`). The read boundary is the analogous trusted deserialisation
52
79
  * point.
53
80
  */
54
- exports.toEventJson = toEventJson;
55
81
  const rowToSequenced = row => ({
56
82
  event: {
57
83
  type: row.type,
58
84
  data: row.data ?? new Uint8Array(0),
59
85
  tags: row.tags,
60
86
  uuid: row.uuid,
61
- occurredAt: _effect.DateTime.unsafeFromDate(row.occurred_at)
87
+ occurredAt: _effect.DateTime.fromDateUnsafe(row.occurred_at),
88
+ metadata: metadataFrom(row.metadata)
62
89
  },
63
90
  position: BigInt(row.id)
64
91
  });
@@ -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","_encoding","jsonbText","value","JSON","stringify","exports","toQueryItemsJson","query","items","map","item","types","tags","toEventJson","event","type","data","Base64","encode","uuid","occurred_at","DateTime","formatIso","occurredAt","metadata","metadataFrom","Array","isArray","Error","rowToSequenced","row","Uint8Array","fromDateUnsafe","position","BigInt","id"],"sources":["../../../src/internal/transport.ts"],"sourcesContent":[null],"mappings":";;;;;;AA4BA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAD,OAAA;AAGA;;;;;;;;;;;;;;AAcO,MAAME,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;EACA;EACA;EACAC,IAAI,EAAEC,gBAAM,CAACC,MAAM,CAACJ,KAAK,CAACE,IAAI,CAAC;EAC/BJ,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;AAoCF;;;;;;;;;;;;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":[]}
package/dist/cjs/store.js CHANGED
@@ -52,15 +52,19 @@ const make = (config, names) => _effect.Effect.gen(function* () {
52
52
  * Nor would such a parameter be load-bearing for the REPEATABLE READ
53
53
  * transaction this runs inside, which is the trap worth naming, since a
54
54
  * closed-over client LOOKS like it must escape to its own snapshot.
55
- * `@effect/sql` resolves a statement's connection when the statement RUNS,
56
- * from the FIBRE CONTEXT rather than from the client value: `withTransaction`
57
- * acquires one connection and `Effect.locally`s it into
58
- * `FiberRef.currentContext` under its `TransactionConnection` tag, and every
59
- * statement a client builds resolves through a `getConnection` that reads
60
- * that tag first, falling back to the pool acquirer only when it is absent
61
- * (`@effect/sql@0.52` `src/internal/client.ts`). A statement therefore joins
62
- * a transaction by being RUN inside it, and passing the client along the call
63
- * chain neither adds to that nor is required by it. `read-postgres`'s
55
+ * `effect/sql` resolves a statement's connection when the statement RUNS,
56
+ * from the FIBRE CONTEXT: `withTransaction` acquires one connection and
57
+ * provides it under that client's OWN `TransactionConnection` key — one key
58
+ * per `SqlClient` instance — and every statement that client builds resolves
59
+ * through a `getConnection` that reads that key first, falling back to the
60
+ * pool only when it is absent (`effect/sql`'s `SqlClient.make`). So a
61
+ * statement joins a transaction by being RUN inside it AND by being built from
62
+ * the SAME client value that opened it; a statement from any other client,
63
+ * even one over the same database, runs on its own pooled connection outside
64
+ * the transaction. Here every statement in the frame — the isolation `SET`,
65
+ * the row fetch and this `MAX(id)` — comes from `pooled`, the client that
66
+ * opened it, so all three share its connection and its snapshot, and passing
67
+ * the client along the call chain would add nothing. `read-postgres`'s
64
68
  * `pinnedConnection` test observes the same fact from the SERVER: two
65
69
  * statements issued inside one transaction report one `pg_backend_pid()`.
66
70
  *
@@ -136,7 +140,7 @@ const make = (config, names) => _effect.Effect.gen(function* () {
136
140
  * conflict (zero rows) vs head (`MAX(id)`) is read from the returned rows by
137
141
  * the caller, never from a caught error.
138
142
  */
139
- const callAppendFn = select => pooled.withTransaction(setLocalLockTimeout(pooled, lockTimeout).pipe(_effect.Effect.zipRight(select)));
143
+ const callAppendFn = select => pooled.withTransaction(setLocalLockTimeout(pooled, lockTimeout).pipe(_effect.Effect.andThen(select)));
140
144
  const append = (events, condition) => {
141
145
  const eventsJson = events.map(_transport.toEventJson);
142
146
  // Raw mechanics: a CONFLICT is `AppendConditionFailed`; a `SqlError` (incl.
@@ -199,22 +203,23 @@ const make = (config, names) => _effect.Effect.gen(function* () {
199
203
  /**
200
204
  * Wire core's subscribe machine to the live clients: `fetch` is the
201
205
  * per-subscription compiled read plan run against the pooled client and mapped
202
- * to `SequencedEvent`s; `listen` is the direct client's ref-counted, non-pooled
203
- * LISTEN on this store's channel (the Neon-safe path — `clients.ts` owns why
204
- * there are two clients at all). The plan is compiled ONCE here so the poll
205
- * loop re-binds only the cursor.
206
+ * to `SequencedEvent`s; `listen` is the direct client's LISTEN on this store's
207
+ * channel (the Neon-safe path — `clients.ts` owns why there are two clients at
208
+ * all), which reserves one of that client's connections for as long as the
209
+ * subscription's wake fibre runs and drains its notification queue as a
210
+ * stream. The plan is compiled ONCE here so the poll loop re-binds only the
211
+ * cursor.
206
212
  *
207
213
  * The wake source is `NOTIFY`, and it is a LATENCY optimisation only: the
208
- * machine's periodic position-based poll is what makes delivery correct, which
209
- * matters more here than the general argument for it suggests. The
210
- * `@effect/sql-pg` listen client SWALLOWS connection errors and does not
211
- * auto-reconnect, so a dropped LISTEN typically goes quiet rather than
212
- * erroring — the machine's listen-side retry then never fires, and the poll is
213
- * the ONLY thing that recovers the subscription. The same silence is what a
214
- * Neon pooled endpoint produces if `PgClientDirect` is misconfigured: the
215
- * pooler drops `LISTEN`/`NOTIFY` without complaint and delivery degrades to
216
- * poll-rate rather than failing, which is why that trap is a deployment-time
217
- * wiring choice and not a runtime error.
214
+ * machine's periodic position-based poll is what makes delivery correct. A
215
+ * listening connection that DROPS fails its queue with the `SqlError` it died
216
+ * of, so the machine's listen-side retry re-subscribes on a fresh connection
217
+ * — but the notifications sent while it was down are gone, and only the poll
218
+ * recovers the events they announced. And some failures are silent: a Neon
219
+ * pooled endpoint, if `PgClientDirect` is misconfigured, accepts `LISTEN` and
220
+ * then never delivers a `NOTIFY`, so delivery degrades to poll-rate rather
221
+ * than failing, which is why that trap is a deployment-time wiring choice and
222
+ * not a runtime error.
218
223
  *
219
224
  * `E` is `SqlError.SqlError` — both seams fail with it, so the machine's single
220
225
  * error parameter carries it straight through to `makeContractStore`.
@@ -223,7 +228,7 @@ const make = (config, names) => _effect.Effect.gen(function* () {
223
228
  const plan = (0, _readPlan.compileFetchPlan)(tables, query);
224
229
  return (0, _core.subscribeStream)({
225
230
  fetch: (from, limit) => (0, _readPlan.runFetch)(pooled, plan, from, limit).pipe(_effect.Effect.map(rows => rows.map(_transport.rowToSequenced))),
226
- listen: direct.listen(names.channel),
231
+ listen: _effect.Stream.unwrap(_effect.Effect.map(direct.listen(names.channel), _effect.Stream.fromQueue)),
227
232
  pollInterval,
228
233
  catchUpPageSize
229
234
  }, after);
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","names":["_core","require","_effect","_clients","_config","_ddl","_readPlan","_transport","setLocalLockTimeout","sql","lockTimeout","make","config","names","Effect","gen","pooled","PgClientPooled","direct","PgClientDirect","pollInterval","DEFAULT_POLL_INTERVAL_MILLIS","catchUpPageSize","DEFAULT_CATCH_UP_PAGE_SIZE","tables","main","quoteQualified","mainTable","tag","tagTable","globalHead","pipe","map","rows","max","undefined","ORIGIN","BigInt","readRowsAndHead","query","options","plan","compileFetchPlan","limit","runFetch","after","lastRow","at","head","id","withTransaction","unsafe","read","events","Stream","fromIterable","rowToSequenced","callAppendFn","select","zipRight","append","condition","eventsJson","toEventJson","appendUnconditionalFn","jsonbText","headFromRows","queryItems","toQueryItemsJson","failIfEventsMatch","afterId","appendFn","length","AppendConditionFailed","Error","subscribe","subscribeStream","fetch","from","listen","channel","layer","decoded","decodePostgresStoreConfig","Layer","effect","DcbEventStore","resolveNames","makeContractStore","exports"],"sources":["../../src/store.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"store.js","names":["_core","require","_effect","_clients","_config","_ddl","_readPlan","_transport","setLocalLockTimeout","sql","lockTimeout","make","config","names","Effect","gen","pooled","PgClientPooled","direct","PgClientDirect","pollInterval","DEFAULT_POLL_INTERVAL_MILLIS","catchUpPageSize","DEFAULT_CATCH_UP_PAGE_SIZE","tables","main","quoteQualified","mainTable","tag","tagTable","globalHead","pipe","map","rows","max","undefined","ORIGIN","BigInt","readRowsAndHead","query","options","plan","compileFetchPlan","limit","runFetch","after","lastRow","at","head","id","withTransaction","unsafe","read","events","Stream","fromIterable","rowToSequenced","callAppendFn","select","andThen","append","condition","eventsJson","toEventJson","appendUnconditionalFn","jsonbText","headFromRows","queryItems","toQueryItemsJson","failIfEventsMatch","afterId","appendFn","length","AppendConditionFailed","Error","subscribe","subscribeStream","fetch","from","listen","unwrap","channel","fromQueue","layer","decoded","decodePostgresStoreConfig","Layer","effect","DcbEventStore","resolveNames","makeContractStore","exports"],"sources":["../../src/store.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The TWO store-owned Postgres clients — the "Neon trap" mitigation (ADR-0002).
3
+ *
4
+ * `@effect/sql-pg` exposes a single `PgClient` (and `SqlClient`) service; a
5
+ * `PgClient.layer` claims BOTH. If we built two `PgClient.layer`s they would
6
+ * collide on that one key — the second would shadow the first. So instead we
7
+ * define two DISTINCT `Context.Service`s, each HOLDING a `PgClient` value:
8
+ *
9
+ * - `PgClientPooled` — the pooled client used for reads, the append function,
10
+ * and `notify`. Its statements borrow a connection from the client's pool per
11
+ * query.
12
+ * - `PgClientDirect` — a client used ONLY by `subscribe`'s `listen`. Its
13
+ * built-in `listen` RESERVES a connection from that client's own pool and
14
+ * holds it for the life of the subscription, so the listening session lives
15
+ * on whatever host the client was configured with. On a Neon POOLED endpoint
16
+ * (`…-pooler…`) that session is a PgBouncer front-door connection, which
17
+ * SILENTLY DROPS `LISTEN`/`NOTIFY` — the subscription would simply never
18
+ * wake. Pointing `PgClientDirect` at Neon's DIRECT (non-pooler) endpoint fixes
19
+ * it. `subscribe` is the ONLY method that touches `PgClientDirect`.
20
+ *
21
+ * Because each live subscription holds one of `PgClientDirect`'s pooled
22
+ * connections until it closes, that client's `maxConnections` is also the number
23
+ * of subscriptions that can be listening at once. A subscription past it waits
24
+ * for a connection on its wake fibre only — delivery still proceeds at the poll
25
+ * rate meanwhile (see `store.ts`) — so size the direct client for the expected
26
+ * subscriber count rather than for query throughput.
27
+ *
28
+ * For a plain (non-Neon) Postgres both services point at the same URL; the split
29
+ * costs nothing there. The two-service design is what makes the Neon fix a
30
+ * deployment-time wiring choice rather than a code change.
31
+ */
32
+ import { PgClient } from '@effect/sql-pg';
33
+ import { Context, Layer } from 'effect';
34
+ import type { SqlError } from 'effect/sql';
35
+ declare const PgClientPooled_base: Context.ServiceClass<PgClientPooled, "@kairos-es/store-postgres/PgClientPooled", PgClient.PgClient>;
36
+ /**
37
+ * The pooled client service: reads, the append function, and `notify`. Holds a
38
+ * `PgClient` value rather than being a `PgClient.layer`, so it never collides
39
+ * with the direct client on the shared `PgClient`/`SqlClient` key.
40
+ */
41
+ export declare class PgClientPooled extends PgClientPooled_base {
42
+ }
43
+ declare const PgClientDirect_base: Context.ServiceClass<PgClientDirect, "@kairos-es/store-postgres/PgClientDirect", PgClient.PgClient>;
44
+ /**
45
+ * The direct (non-pooler) client service: the `subscribe` listener ONLY. Point
46
+ * this at a direct endpoint on Neon so `LISTEN`/`NOTIFY` is not dropped by the
47
+ * pooler.
48
+ */
49
+ export declare class PgClientDirect extends PgClientDirect_base {
50
+ }
51
+ /**
52
+ * Build a `PgClientPooled` layer from a `PgClient` pool config. We construct the
53
+ * client via `PgClient.make` (scoped) and place it in our OWN service, then
54
+ * provide `Reactivity.layer` (which `PgClient.make` requires) — exactly what the
55
+ * built-in `PgClient.layer` does internally, minus the collision-prone claim on
56
+ * the shared `PgClient` key.
57
+ */
58
+ export declare const pooledLayer: (config: PgClient.PgPoolConfig) => Layer.Layer<PgClientPooled, SqlError.SqlError>;
59
+ /**
60
+ * Build a `PgClientDirect` layer from a `PgClient` pool config. Same construction as
61
+ * `pooledLayer`; the two differ only in which endpoint the caller points them
62
+ * at (and that only matters on Neon).
63
+ */
64
+ export declare const directLayer: (config: PgClient.PgPoolConfig) => Layer.Layer<PgClientDirect, SqlError.SqlError>;
65
+ export {};
66
+ //# sourceMappingURL=clients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../src/clients.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;;AAE1C;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,mBAGW;CAAG;;AAElD;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,mBAGW;CAAG;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,QAAQ,CAAC,YAAY,KAC5B,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAG7C,CAAA;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,QAAQ,CAAC,YAAY,KAC5B,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAG7C,CAAA"}
@@ -25,30 +25,20 @@ import { Schema } from 'effect';
25
25
  * `DEFAULT_CATCH_UP_PAGE_SIZE`: how many events a single catch-up/live read
26
26
  * fetches before looping.
27
27
  */
28
- export declare const PostgresStoreConfig: Schema.filter<Schema.Struct<{
29
- pollInterval: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.Number>>, {
30
- exact: true;
31
- }>;
32
- catchUpPageSize: Schema.optionalWith<Schema.filter<typeof Schema.Int>, {
33
- exact: true;
34
- }>;
35
- schema: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.String>>, {
36
- exact: true;
37
- }>;
38
- tablePrefix: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.String>>, {
39
- exact: true;
40
- }>;
41
- lockTimeout: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.Number>>, {
42
- exact: true;
43
- }>;
44
- }>>;
28
+ export declare const PostgresStoreConfig: Schema.Struct<{
29
+ readonly pollInterval: Schema.optionalKey<Schema.Number>;
30
+ readonly catchUpPageSize: Schema.optionalKey<Schema.Int>;
31
+ readonly schema: Schema.optionalKey<Schema.String>;
32
+ readonly tablePrefix: Schema.optionalKey<Schema.String>;
33
+ readonly lockTimeout: Schema.optionalKey<Schema.Number>;
34
+ }>;
45
35
  export type PostgresStoreConfig = typeof PostgresStoreConfig.Type;
46
36
  /**
47
37
  * Decode an unknown value into a validated `PostgresStoreConfig`, throwing a
48
- * `ParseError` on any violation. Used by `layer`/`ensureSchema` so a bad config
38
+ * `SchemaError` on any violation. Used by `layer`/`ensureSchema` so a bad config
49
39
  * fails at construction time.
50
40
  */
51
- export declare const decodePostgresStoreConfig: (u: unknown, overrideOptions?: import("effect/SchemaAST").ParseOptions) => {
41
+ export declare const decodePostgresStoreConfig: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => {
52
42
  readonly schema?: string;
53
43
  readonly tablePrefix?: string;
54
44
  readonly lockTimeout?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAiB/B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;GAkB/B,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAA;AAEjE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;;;;;;CACS,CAAA"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAiB/B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,mBAAmB;;;;;;EAiB/B,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAA;AAEjE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;;;;;;CACS,CAAA"}
@@ -4,7 +4,7 @@
4
4
  * This is deliberately NOT a migrator. It is a single `Effect<void, SqlError,
5
5
  * SqlClient>` that creates (or refreshes) every object a store owns: both
6
6
  * tables, both indexes, and both plpgsql functions. It requires the GENERIC
7
- * `SqlClient` tag — NOT `PgClientPooled` — precisely so a consumer can drop it
7
+ * `SqlClient` service — NOT `PgClientPooled` — precisely so a consumer can drop it
8
8
  * straight into THEIR OWN migrator, e.g.:
9
9
  *
10
10
  * ```ts
@@ -18,13 +18,18 @@
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.
25
30
  */
26
- import { SqlClient, type SqlError } from '@effect/sql';
27
31
  import { Effect } from 'effect';
32
+ import { SqlClient, type SqlError } from 'effect/sql';
28
33
  import { type PostgresStoreConfig } from './config.js';
29
34
  /**
30
35
  * Produce the migration payload for `config`. Resolves the object names once and
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureSchema.d.ts","sourceRoot":"","sources":["../../src/ensureSchema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrD,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"}
@@ -30,9 +30,10 @@
30
30
  * const store = layer(config).pipe(Layer.provide(clients))
31
31
  * ```
32
32
  *
33
- * The store `layer` performs NO DDL: it depends only on the two client tags and
34
- * assumes `ensureSchema` has run. `ensureSchema` requires the generic `SqlClient`
35
- * tag so it slots into any migrator; the runtime uses the store-owned tags.
33
+ * The store `layer` performs NO DDL: it depends only on the two client services
34
+ * and assumes `ensureSchema` has run. `ensureSchema` requires the generic
35
+ * `SqlClient` service so it slots into any migrator; the runtime uses the
36
+ * store-owned services.
36
37
  */
37
38
  export { directLayer, PgClientDirect, PgClientPooled, pooledLayer, } from './clients.js';
38
39
  export type { PostgresStoreConfig } from './config.js';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EACL,WAAW,EACX,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA"}
@@ -25,7 +25,7 @@
25
25
  * would emit; VALUES stay bound parameters (`sql.unsafe` with `params`) and are
26
26
  * never interpolated.
27
27
  */
28
- import type { SqlClient, Statement } from '@effect/sql';
28
+ import type { SqlClient, Statement } from 'effect/sql';
29
29
  /**
30
30
  * A store is one physical `{ schema, tablePrefix }` pair. Every object it owns
31
31
  * (both tables, both indexes, both functions, and the NOTIFY channel) is derived
@@ -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,YAAY,CAAA;AAWtD;;;;;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.
@@ -0,0 +1 @@
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;AAgCnC;;;;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"}
@@ -21,10 +21,10 @@
21
21
  * plpgsql body, where no compiler follows, and `ddl.ts` owns what that rests on
22
22
  * instead.
23
23
  */
24
- import type { SqlClient, SqlError } from '@effect/sql';
25
24
  import type { Position, ReadLimit } from '@kairos-es/core';
26
25
  import { type Query } from '@kairos-es/core';
27
26
  import type { Effect } from 'effect';
27
+ import type { SqlClient, SqlError } from 'effect/sql';
28
28
  import { type EventRow } from './transport.js';
29
29
  /** The pre-quoted table names a plan reads from (see `quoteQualified`). */
30
30
  export interface ReadTables {
@@ -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;AAEH,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;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErD,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"}