@kairos-es/codec 1.0.0-alpha.2 → 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.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Schema-first codec with an encryption seam for kairos-es (ADR-0004).
8
8
  single shared Effect instance (per [ADR-0003](../../docs/adr)):
9
9
 
10
10
  ```sh
11
- pnpm add @kairos-es/codec@alpha @kairos-es/core@alpha effect
11
+ pnpm add @kairos-es/codec@alpha @kairos-es/core@alpha effect@^3.22.0
12
12
  ```
13
13
 
14
14
  The typed-payload to opaque-bytes seam: `event(type, fields, tagsFor)` defines a
@@ -18,7 +18,32 @@ decision model or a read model folds through; `modelAtHead(slices)` reads, decod
18
18
  through each def's `Schema`, and folds purely, returning `{ state, head }`;
19
19
  `buildDecisionModel(slices)` is that same read plus the `AppendCondition` a write
20
20
  needs; and `toEvent` produces a wire event (encode, serialise, tags derived, clock
21
- and uuid from services).
21
+ and uuid from services, and a metadata bag).
22
+
23
+ Every event carries `metadata`, a flat bag of strings (core's `Metadata`) of context about the
24
+ recording — a `traceparent`, a correlation id — never anything the business asserts.
25
+ Pass it per call as `toEvent(def, payload, { metadata })`, or provide it once at the
26
+ edge of a request with `Effect.provideService(MetadataSource, bag)`; a per-call bag
27
+ replaces the ambient one, and with neither the event carries `{}`. A bag core's
28
+ `Metadata` schema refuses, such as one holding a value that is not a string, fails
29
+ `toEvent` with a `CodecError` (`reason: 'metadata'`). Metadata is cleartext, never
30
+ queryable and never seen by `tagsFor` or by a builder fold (`.on(def, fold)`). A
31
+ read model's `apply` sees it on each decoded event as `decoded.sequenced.event.metadata`.
32
+
33
+ To read metadata in a FOLD, leave the builder and write the `SliceProjection` by
34
+ hand: an `initialState`, a `query`, a `schemas` map from each event type it folds to
35
+ that def's schema, and an erased `evolve(state, decoded)` that reads
36
+ `decoded.sequenced.event.metadata`. It goes everywhere a built slice goes. Three
37
+ things the builder does for you, a hand-written slice must do itself:
38
+
39
+ - **Keep the def's requirement in the schema cast** —
40
+ `def.schema as unknown as Schema.Schema<unknown, unknown, R>` with the def's own
41
+ `R`. Cast a def that needs a service to `never` instead, and the slice compiles
42
+ without that service and dies at run time.
43
+ - **Check `decoded.sequenced.event.type` in `evolve`.** It is handed every event its
44
+ query matches, decoded through the schemas of every slice in the record, so an
45
+ event your `schemas` never named can still arrive, decoded by a neighbour's.
46
+ - **Cast `state` back to its own type**, since `evolve` is erased.
22
47
 
23
48
  `modelAtHead` is the read side's third materialisation KIND — checkpoint-free and
24
49
  read-time, no table, no runner, nothing maintained — and `head` is its consistency
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MetadataSource = void 0;
7
+ var _effect = require("effect");
8
+ class MetadataSource extends /*#__PURE__*/_effect.Context.Tag('@kairos-es/codec/MetadataSource')() {}
9
+ exports.MetadataSource = MetadataSource;
10
+ //# sourceMappingURL=MetadataSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataSource.js","names":["_effect","require","MetadataSource","Context","Tag","exports"],"sources":["../../src/MetadataSource.ts"],"sourcesContent":[null],"mappings":";;;;;;AAsCA,IAAAA,OAAA,GAAAC,OAAA;AAEM,MAAOC,cAAe,sBAAQC,eAAO,CAACC,GAAG,CAC7C,iCAAiC,CAClC,EAA4B;AAAAC,OAAA,CAAAH,cAAA,GAAAA,cAAA","ignoreList":[]}
package/dist/cjs/index.js CHANGED
@@ -15,6 +15,12 @@ Object.defineProperty(exports, "Decision", {
15
15
  return _decision.Decision;
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "MetadataSource", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _MetadataSource.MetadataSource;
22
+ }
23
+ });
18
24
  Object.defineProperty(exports, "NoReadsRecorded", {
19
25
  enumerable: true,
20
26
  get: function () {
@@ -165,6 +171,7 @@ var _decisionModel = require("./decisionModel.js");
165
171
  var _decode = require("./decode.js");
166
172
  var _errors = require("./errors.js");
167
173
  var _event = require("./event.js");
174
+ var _MetadataSource = require("./MetadataSource.js");
168
175
  var _precondition = require("./precondition.js");
169
176
  var _projection = require("./projection.js");
170
177
  var _readLedger = require("./readLedger.js");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_decider","require","_decision","_decisionModel","_decode","_errors","_event","_precondition","_projection","_readLedger","_registry","_Serializer","_toEvent","_Uuid"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuHA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAD,OAAA;AAQA,IAAAE,cAAA,GAAAF,OAAA;AAKA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,MAAA,GAAAL,OAAA;AACA,IAAAM,aAAA,GAAAN,OAAA;AAMA,IAAAO,WAAA,GAAAP,OAAA;AAKA,IAAAQ,WAAA,GAAAR,OAAA;AAOA,IAAAS,SAAA,GAAAT,OAAA;AACA,IAAAU,WAAA,GAAAV,OAAA;AACA,IAAAW,QAAA,GAAAX,OAAA;AACA,IAAAY,KAAA,GAAAZ,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_decider","require","_decision","_decisionModel","_decode","_errors","_event","_MetadataSource","_precondition","_projection","_readLedger","_registry","_Serializer","_toEvent","_Uuid"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwHA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAD,OAAA;AAQA,IAAAE,cAAA,GAAAF,OAAA;AAKA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,MAAA,GAAAL,OAAA;AACA,IAAAM,eAAA,GAAAN,OAAA;AACA,IAAAO,aAAA,GAAAP,OAAA;AAMA,IAAAQ,WAAA,GAAAR,OAAA;AAKA,IAAAS,WAAA,GAAAT,OAAA;AAOA,IAAAU,SAAA,GAAAV,OAAA;AACA,IAAAW,WAAA,GAAAX,OAAA;AACA,IAAAY,QAAA,GAAAZ,OAAA;AACA,IAAAa,KAAA,GAAAb,OAAA","ignoreList":[]}
@@ -174,8 +174,23 @@ const recordQuery = query => withLedger(NO_CLOSE, ledger => ledger.record(query)
174
174
  /** The tagless slice keys in a record, in declaration order. */
175
175
  exports.recordQuery = recordQuery;
176
176
  const taglessKeys = projections => Object.entries(projections).filter(([, projection]) => projection.query.items.some(item => item.tags.length === 0)).map(([key]) => key);
177
- /** Would recording this record's query leave the accumulated union unservable? */
178
- const unionWouldBeUnservable = (existing, incoming) => (0, _core.servableQueryFault)((0, _core.unionQueries)([...existing.map(h => h.query), incoming])) !== undefined;
177
+ /**
178
+ * Would recording this record's query leave the accumulated union unservable in
179
+ * its SHAPE — the one fault a slice's tags can fix, and so the one this ledger
180
+ * reports?
181
+ *
182
+ * An unknown key anywhere in the union answers no. It is not a tagless slice and no
183
+ * slice's tags would fix it, and the store refuses it as a defect naming the key at
184
+ * the read of the hop that carries it, so an earlier hop's key has already been
185
+ * refused once by the time a later record is judged. Judged here it would surface
186
+ * as this ledger's error, on the error channel, naming a slice with nothing wrong
187
+ * with it — and a hop is recorded before its read runs, so an earlier hop's key
188
+ * would go on doing that to every clean read after it.
189
+ */
190
+ const unionWouldBeUnservable = (existing, incoming) => {
191
+ const union = (0, _core.unionQueries)([...existing.map(h => h.query), incoming]);
192
+ return (0, _core.unknownQueryKeyFault)(union) === undefined && (0, _core.servableQueryFault)(union) !== undefined;
193
+ };
179
194
  /**
180
195
  * Refuse a read that would leave the bracket's accumulated union unservable,
181
196
  * BEFORE the read is paid for.
@@ -1 +1 @@
1
- {"version":3,"file":"readLedger.js","names":["_core","require","_effect","ReadLedger","Context","Tag","exports","NoReadsRecorded","Data","TaggedError","message","TaglessSliceInLedger","sliceKey","deriveLayeredCondition","hops","length","undefined","merged","unionQueries","map","hop","query","arrived","flatMap","head","after","reduce","a","b","ORIGIN","failIfEventsMatch","makeReadLedger","Effect","gen","ref","Ref","make","layer","Layer","succeed","record","modify","update","current","index","get","withLedger","absent","f","serviceOption","ledger","Option","isNone","value","NO_CLOSE","void","recordQuery","taglessKeys","projections","Object","entries","filter","projection","items","some","item","tags","key","unionWouldBeUnservable","existing","incoming","servableQueryFault","h","assertServableAddition","composeProjections","offending","ambientLayeredCondition","none","fromNullable"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"readLedger.js","names":["_core","require","_effect","ReadLedger","Context","Tag","exports","NoReadsRecorded","Data","TaggedError","message","TaglessSliceInLedger","sliceKey","deriveLayeredCondition","hops","length","undefined","merged","unionQueries","map","hop","query","arrived","flatMap","head","after","reduce","a","b","ORIGIN","failIfEventsMatch","makeReadLedger","Effect","gen","ref","Ref","make","layer","Layer","succeed","record","modify","update","current","index","get","withLedger","absent","f","serviceOption","ledger","Option","isNone","value","NO_CLOSE","void","recordQuery","taglessKeys","projections","Object","entries","filter","projection","items","some","item","tags","key","unionWouldBeUnservable","existing","incoming","union","h","unknownQueryKeyFault","servableQueryFault","assertServableAddition","composeProjections","offending","ambientLayeredCondition","none","fromNullable"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -4,10 +4,33 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.toEvent = void 0;
7
+ var _core = require("@kairos-es/core");
7
8
  var _effect = require("effect");
8
9
  var _errors = require("./errors.js");
10
+ var _MetadataSource = require("./MetadataSource.js");
9
11
  var _Serializer = require("./Serializer.js");
10
12
  var _Uuid = require("./Uuid.js");
13
+ /**
14
+ * Event production (codec edge-helper): turn a typed payload into a wire
15
+ * `DcbEvent`. Encode is `Schema.encode(def.schema)` (a `ParseError` becomes a
16
+ * `CodecError`; any encryption transform runs here, *before* serialisation)
17
+ * then `serialiser.serialise`. The wire `tags` are derived from the def's
18
+ * required `tagsFor` mapper (ADR-0006) — they are never hand-passed, so two
19
+ * command sites emitting the same event type cannot tag it differently. A mapper
20
+ * that throws (e.g. an ill-formed `key:value` rejected by `Tag.make`) is
21
+ * surfaced on the `CodecError` channel, not as a defect. `uuid`
22
+ * comes from `options.uuid` or the `Uuid` service; `occurredAt` from
23
+ * `options.occurredAt` or the Effect clock (`DateTime.now`), keeping `core`
24
+ * clock- and RNG-free while staying overridable for backdated imports.
25
+ * `metadata` comes from `options.metadata` or the OPTIONAL ambient
26
+ * `MetadataSource` service, and is `{}` when neither supplies it (ADR-0017). A
27
+ * bag core's `Metadata` schema refuses, such as one holding a value that is not a
28
+ * string, fails on the `CodecError` channel (`reason: 'metadata'`), whichever of
29
+ * the two supplied it. It never reaches `tagsFor`, the
30
+ * event's schema or the serialiser, so it can enter neither the tag junction
31
+ * table nor the encryption seam.
32
+ */
33
+
11
34
  /**
12
35
  * Encode `payload` under `def` and stamp it into a wire `DcbEvent`, deriving its
13
36
  * `tags` from `def.tagsFor(payload)` (a throwing mapper surfaces as a
@@ -16,10 +39,40 @@ var _Uuid = require("./Uuid.js");
16
39
  * wire-envelope fields (the query surface), so a `tagsFor` mapper may only key
17
40
  * off cleartext payload fields (ADR-0006). `uuid` / `occurredAt` are
18
41
  * exact-optional overrides; absent, they come from the `Uuid` service and the
19
- * Effect clock.
42
+ * Effect clock. `metadata` is an exact-optional override too; absent, it comes
43
+ * from the ambient `MetadataSource` if one is provided and is `{}` otherwise.
44
+ * The ambient read adds nothing to the requirement channel. A bag core's
45
+ * `Metadata` schema refuses fails as a `CodecError` with `reason: 'metadata'`.
20
46
  */
21
47
  const toEvent = (def, payload, options) => _effect.Effect.gen(function* () {
22
- // Derive tags first. A mapper is app code that can throw (e.g. `Tag.make`
48
+ // Resolve metadata before anything else. Per-call wins, ambient fills,
49
+ // absent yields `{}`. `serviceOption` keeps `MetadataSource` out of the
50
+ // requirement channel.
51
+ //
52
+ // The bag is then CHECKED against core's `Metadata` schema, whichever arm
53
+ // supplied it. The type holds a typed caller to a bag of strings, but an
54
+ // `any` or untyped JavaScript gets past it, and the engines then disagree
55
+ // about what they stored: the cross-engine parity of this field rests on its
56
+ // values being strings, and this is the one place a value is refused. It is
57
+ // refused HERE, at write, and never on read: a read-side check would make an
58
+ // event the store had accepted unreadable for ever. A bad bag is the
59
+ // caller's mistake, so it fails on the `CodecError` channel exactly as a
60
+ // throwing `tagsFor` does, never as a defect. Checking consumes no sequence,
61
+ // so placing it above the tag derivation leaves the property below intact.
62
+ //
63
+ // The bag is COPIED, never stamped by reference: an ambient bag would
64
+ // otherwise be ONE object shared by every event of a request, and the
65
+ // caller's own object would be shared with the event it built, so a mutation
66
+ // of either before the append would rewrite the other. (After the append no
67
+ // store shares anything with its caller; that is each store's guarantee.)
68
+ const given = options?.metadata === undefined ? _effect.Option.getOrElse(yield* _effect.Effect.serviceOption(_MetadataSource.MetadataSource), () => ({})) : options.metadata;
69
+ const metadata = {
70
+ ...(yield* _effect.Schema.decodeUnknown(_core.Metadata)(given).pipe(_effect.Effect.mapError(cause => new _errors.CodecError({
71
+ reason: 'metadata',
72
+ cause
73
+ }))))
74
+ };
75
+ // Derive tags next. A mapper is app code that can throw (e.g. `Tag.make`
23
76
  // rejects an ill-formed `key:value`), and the codec's contract is that such
24
77
  // failures are values on the `CodecError` channel, never defects (errors.ts).
25
78
  // Deriving before the uuid/clock effects also means a bad tag fails without
@@ -44,7 +97,8 @@ const toEvent = (def, payload, options) => _effect.Effect.gen(function* () {
44
97
  data,
45
98
  tags,
46
99
  uuid,
47
- occurredAt
100
+ occurredAt,
101
+ metadata
48
102
  };
49
103
  });
50
104
  exports.toEvent = toEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"toEvent.js","names":["_effect","require","_errors","_Serializer","_Uuid","toEvent","def","payload","options","Effect","gen","tags","try","tagsFor","catch","cause","CodecError","reason","serializer","Serializer","encoded","Schema","encode","schema","pipe","mapError","data","serialise","uuid","Uuid","generate","occurredAt","DateTime","now","type","exports"],"sources":["../../src/toEvent.ts"],"sourcesContent":[null],"mappings":";;;;;;AAcA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAEA,IAAAE,WAAA,GAAAF,OAAA;AACA,IAAAG,KAAA,GAAAH,OAAA;AAEA;;;;;;;;;;AAUO,MAAMI,OAAO,GAAGA,CACrBC,GAAsB,EACtBC,OAAU,EACVC,OAGC,KAEDC,cAAM,CAACC,GAAG,CAAC,aAAS;EAClB;EACA;EACA;EACA;EACA;EACA,MAAMC,IAAI,GAAG,OAAOF,cAAM,CAACG,GAAG,CAAC;IAC7BA,GAAG,EAAEA,CAAA,KAAMN,GAAG,CAACO,OAAO,CAACN,OAAO,CAAC;IAC/BO,KAAK,EAAGC,KAAK,IAAK,IAAIC,kBAAU,CAAC;MAAEC,MAAM,EAAE,MAAM;MAAEF;IAAK,CAAE;GAC3D,CAAC;EACF,MAAMG,UAAU,GAAG,OAAOC,sBAAU;EACpC,MAAMC,OAAO,GAAG,OAAOC,cAAM,CAACC,MAAM,CAAChB,GAAG,CAACiB,MAAM,CAAC,CAAChB,OAAO,CAAC,CAACiB,IAAI,CAC5Df,cAAM,CAACgB,QAAQ,CAAEV,KAAK,IAAK,IAAIC,kBAAU,CAAC;IAAEC,MAAM,EAAE,QAAQ;IAAEF;EAAK,CAAE,CAAC,CAAC,CACxE;EACD,MAAMW,IAAI,GAAGR,UAAU,CAACS,SAAS,CAACP,OAAO,CAAC;EAC1C,MAAMQ,IAAI,GAAGpB,OAAO,EAAEoB,IAAI,KAAK,OAAO,CAAC,OAAOC,UAAI,EAAEC,QAAQ,CAAC;EAC7D,MAAMC,UAAU,GAAGvB,OAAO,EAAEuB,UAAU,KAAK,OAAOC,gBAAQ,CAACC,GAAG,CAAC;EAC/D,OAAO;IACLC,IAAI,EAAE5B,GAAG,CAAC4B,IAAI;IACdR,IAAI;IACJf,IAAI;IACJiB,IAAI;IACJG;GACD;AACH,CAAC,CAAC;AAAAI,OAAA,CAAA9B,OAAA,GAAAA,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"toEvent.js","names":["_core","require","_effect","_errors","_MetadataSource","_Serializer","_Uuid","toEvent","def","payload","options","Effect","gen","given","metadata","undefined","Option","getOrElse","serviceOption","MetadataSource","Schema","decodeUnknown","Metadata","pipe","mapError","cause","CodecError","reason","tags","try","tagsFor","catch","serializer","Serializer","encoded","encode","schema","data","serialise","uuid","Uuid","generate","occurredAt","DateTime","now","type","exports"],"sources":["../../src/toEvent.ts"],"sourcesContent":[null],"mappings":";;;;;;AAoBA,IAAAA,KAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAEA,IAAAG,eAAA,GAAAH,OAAA;AACA,IAAAI,WAAA,GAAAJ,OAAA;AACA,IAAAK,KAAA,GAAAL,OAAA;AA1BA;;;;;;;;;;;;;;;;;;;;;AA4BA;;;;;;;;;;;;;AAaO,MAAMM,OAAO,GAAGA,CACrBC,GAAsB,EACtBC,OAAU,EACVC,OAIC,KAEDC,cAAM,CAACC,GAAG,CAAC,aAAS;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,KAAK,GACTH,OAAO,EAAEI,QAAQ,KAAKC,SAAS,GAC3BC,cAAM,CAACC,SAAS,CACd,OAAON,cAAM,CAACO,aAAa,CAACC,8BAAc,CAAC,EAC3C,OAAiB,EAAE,CAAC,CACrB,GACDT,OAAO,CAACI,QAAQ;EACtB,MAAMA,QAAQ,GAAa;IACzB,IAAI,OAAOM,cAAM,CAACC,aAAa,CAACC,cAAQ,CAAC,CAACT,KAAK,CAAC,CAACU,IAAI,CACnDZ,cAAM,CAACa,QAAQ,CACZC,KAAK,IAAK,IAAIC,kBAAU,CAAC;MAAEC,MAAM,EAAE,UAAU;MAAEF;IAAK,CAAE,CAAC,CACzD,CACF;GACF;EACD;EACA;EACA;EACA;EACA;EACA,MAAMG,IAAI,GAAG,OAAOjB,cAAM,CAACkB,GAAG,CAAC;IAC7BA,GAAG,EAAEA,CAAA,KAAMrB,GAAG,CAACsB,OAAO,CAACrB,OAAO,CAAC;IAC/BsB,KAAK,EAAGN,KAAK,IAAK,IAAIC,kBAAU,CAAC;MAAEC,MAAM,EAAE,MAAM;MAAEF;IAAK,CAAE;GAC3D,CAAC;EACF,MAAMO,UAAU,GAAG,OAAOC,sBAAU;EACpC,MAAMC,OAAO,GAAG,OAAOd,cAAM,CAACe,MAAM,CAAC3B,GAAG,CAAC4B,MAAM,CAAC,CAAC3B,OAAO,CAAC,CAACc,IAAI,CAC5DZ,cAAM,CAACa,QAAQ,CAAEC,KAAK,IAAK,IAAIC,kBAAU,CAAC;IAAEC,MAAM,EAAE,QAAQ;IAAEF;EAAK,CAAE,CAAC,CAAC,CACxE;EACD,MAAMY,IAAI,GAAGL,UAAU,CAACM,SAAS,CAACJ,OAAO,CAAC;EAC1C,MAAMK,IAAI,GAAG7B,OAAO,EAAE6B,IAAI,KAAK,OAAO,CAAC,OAAOC,UAAI,EAAEC,QAAQ,CAAC;EAC7D,MAAMC,UAAU,GAAGhC,OAAO,EAAEgC,UAAU,KAAK,OAAOC,gBAAQ,CAACC,GAAG,CAAC;EAC/D,OAAO;IACLC,IAAI,EAAErC,GAAG,CAACqC,IAAI;IACdR,IAAI;IACJT,IAAI;IACJW,IAAI;IACJG,UAAU;IACV5B;GACD;AACH,CAAC,CAAC;AAAAgC,OAAA,CAAAvC,OAAA,GAAAA,OAAA","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import { Context } from 'effect';
2
+ declare const MetadataSource_base: Context.TagClass<MetadataSource, "@kairos-es/codec/MetadataSource", {
3
+ readonly [x: string]: string;
4
+ }>;
5
+ export declare class MetadataSource extends MetadataSource_base {
6
+ }
7
+ export {};
8
+ //# sourceMappingURL=MetadataSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataSource.d.ts","sourceRoot":"","sources":["../../src/MetadataSource.ts"],"names":[],"mappings":"AAsCA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;;;;AAEhC,qBAAa,cAAe,SAAQ,mBAEP;CAAG"}
@@ -17,8 +17,9 @@
17
17
  * on this path: the type is discovered at runtime, so no def was named to
18
18
  * narrow it (see `registry.ts`).
19
19
  *
20
- * `toEvent(def, payload, { uuid?, occurredAt? })` produces a wire event (encode
21
- * -> serialise, tags derived from `def.tagsFor`, clock + uuid from services).
20
+ * `toEvent(def, payload, { uuid?, occurredAt?, metadata? })` produces a wire
21
+ * event (encode -> serialise, tags derived from `def.tagsFor`, clock + uuid from
22
+ * services, metadata from the call or the optional ambient `MetadataSource`).
22
23
  * Serialisation is a pluggable `Serializer` (JSON
23
24
  * default). Encryption, when needed, is an *application*-authored `Schema`
24
25
  * transform on a payload field; the codec only propagates its requirement and
@@ -122,6 +123,7 @@ export { buildDecisionModel, modelAtHead, type RequirementOf, } from './decision
122
123
  export { decodeSlices } from './decode.js';
123
124
  export { CodecError, UnknownEventType } from './errors.js';
124
125
  export { type EventDef, type EventDefAny, event, type TagsFor } from './event.js';
126
+ export { MetadataSource } from './MetadataSource.js';
125
127
  export { decideOnly, type Precondition, transact, unsafeAppend, } from './precondition.js';
126
128
  export { type ProjectionBuilder, projection, type SliceProjection, } from './projection.js';
127
129
  export { type CloseHop, type Hop, NoReadsRecorded, ReadLedger, TaglessSliceInLedger, } from './readLedger.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqHG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EACL,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,WAAW,EACX,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,EACL,UAAU,EACV,KAAK,YAAY,EACjB,QAAQ,EACR,YAAY,GACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,GAAG,EACR,eAAe,EACf,UAAU,EACV,oBAAoB,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsHG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EACL,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,WAAW,EACX,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EACL,UAAU,EACV,KAAK,YAAY,EACjB,QAAQ,EACR,YAAY,GACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,GAAG,EACR,eAAe,EACf,UAAU,EACV,oBAAoB,GACrB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"readLedger.d.ts","sourceRoot":"","sources":["../../src/readLedger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,QAAQ,EACR,KAAK,EACN,MAAM,iBAAiB,CAAA;AAOxB,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAA;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CACzB;;IAuBG;;;;;;;;;;;;OAYG;qBACc,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;mBAC3C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;;AAnCpD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAW,SAAQ,eAmB7B;CAAG;AAEN;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;;;;AAE9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAgB,SAAQ,qBACnC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CACrB;IACC;;;;;;;OAOG;IACH,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oBAAqB,SAAQ,0BAExC;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;IAC9B,2DAA2D;IAC3D,IAAa,OAAO,IAAI,MAAM,CAO7B;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,aAAa,CAAC,GAAG,CAAC,KACvB,eAAe,GAAG,SAiBpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;CACjD,CAsBC,CAAA;AAsBF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CACT,CAAA;AAqBxD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,KACzC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAaxC,CAAA;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,CACjD,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAK/B,CAAA"}
1
+ {"version":3,"file":"readLedger.d.ts","sourceRoot":"","sources":["../../src/readLedger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,QAAQ,EACR,KAAK,EACN,MAAM,iBAAiB,CAAA;AAQxB,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAA;AAElE;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CACzB;;IAuBG;;;;;;;;;;;;OAYG;qBACc,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;mBAC3C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;;AAnCpD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,UAAW,SAAQ,eAmB7B;CAAG;AAEN;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;;;;AAE9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAgB,SAAQ,qBACnC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CACrB;IACC;;;;;;;OAOG;IACH,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oBAAqB,SAAQ,0BAExC;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;IAC9B,2DAA2D;IAC3D,IAAa,OAAO,IAAI,MAAM,CAO7B;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,aAAa,CAAC,GAAG,CAAC,KACvB,eAAe,GAAG,SAiBpB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;CACjD,CAsBC,CAAA;AAsBF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CACT,CAAA;AAoCxD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,KACzC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAaxC,CAAA;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,CACjD,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAK/B,CAAA"}
@@ -10,8 +10,15 @@
10
10
  * comes from `options.uuid` or the `Uuid` service; `occurredAt` from
11
11
  * `options.occurredAt` or the Effect clock (`DateTime.now`), keeping `core`
12
12
  * clock- and RNG-free while staying overridable for backdated imports.
13
+ * `metadata` comes from `options.metadata` or the OPTIONAL ambient
14
+ * `MetadataSource` service, and is `{}` when neither supplies it (ADR-0017). A
15
+ * bag core's `Metadata` schema refuses, such as one holding a value that is not a
16
+ * string, fails on the `CodecError` channel (`reason: 'metadata'`), whichever of
17
+ * the two supplied it. It never reaches `tagsFor`, the
18
+ * event's schema or the serialiser, so it can enter neither the tag junction
19
+ * table nor the encryption seam.
13
20
  */
14
- import type { DcbEvent } from '@kairos-es/core';
21
+ import { type DcbEvent, Metadata } from '@kairos-es/core';
15
22
  import { DateTime, Effect } from 'effect';
16
23
  import { CodecError } from './errors.js';
17
24
  import type { EventDef } from './event.js';
@@ -25,10 +32,14 @@ import { Uuid } from './Uuid.js';
25
32
  * wire-envelope fields (the query surface), so a `tagsFor` mapper may only key
26
33
  * off cleartext payload fields (ADR-0006). `uuid` / `occurredAt` are
27
34
  * exact-optional overrides; absent, they come from the `Uuid` service and the
28
- * Effect clock.
35
+ * Effect clock. `metadata` is an exact-optional override too; absent, it comes
36
+ * from the ambient `MetadataSource` if one is provided and is `{}` otherwise.
37
+ * The ambient read adds nothing to the requirement channel. A bag core's
38
+ * `Metadata` schema refuses fails as a `CodecError` with `reason: 'metadata'`.
29
39
  */
30
40
  export declare const toEvent: <A, I, R>(def: EventDef<A, I, R>, payload: A, options?: {
31
41
  readonly uuid?: string;
32
42
  readonly occurredAt?: DateTime.Utc;
43
+ readonly metadata?: Metadata;
33
44
  }) => Effect.Effect<DcbEvent, CodecError, Serializer | Uuid | R>;
34
45
  //# sourceMappingURL=toEvent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toEvent.d.ts","sourceRoot":"","sources":["../../src/toEvent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7B,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACtB,SAAS,CAAC,EACV,UAAU;IACR,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAA;CACnC,KACA,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,CAAC,CAyBxD,CAAA"}
1
+ {"version":3,"file":"toEvent.d.ts","sourceRoot":"","sources":["../../src/toEvent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,KAAK,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAkB,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7B,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACtB,SAAS,CAAC,EACV,UAAU;IACR,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAA;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAC7B,KACA,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,CAAC,CA4DxD,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { Context } from 'effect';
2
+ export class MetadataSource extends /*#__PURE__*/Context.Tag('@kairos-es/codec/MetadataSource')() {}
3
+ //# sourceMappingURL=MetadataSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetadataSource.js","names":["Context","MetadataSource","Tag"],"sources":["../../src/MetadataSource.ts"],"sourcesContent":[null],"mappings":"AAsCA,SAASA,OAAO,QAAQ,QAAQ;AAEhC,OAAM,MAAOC,cAAe,sBAAQD,OAAO,CAACE,GAAG,CAC7C,iCAAiC,CAClC,EAA4B","ignoreList":[]}
package/dist/esm/index.js CHANGED
@@ -17,8 +17,9 @@
17
17
  * on this path: the type is discovered at runtime, so no def was named to
18
18
  * narrow it (see `registry.ts`).
19
19
  *
20
- * `toEvent(def, payload, { uuid?, occurredAt? })` produces a wire event (encode
21
- * -> serialise, tags derived from `def.tagsFor`, clock + uuid from services).
20
+ * `toEvent(def, payload, { uuid?, occurredAt?, metadata? })` produces a wire
21
+ * event (encode -> serialise, tags derived from `def.tagsFor`, clock + uuid from
22
+ * services, metadata from the call or the optional ambient `MetadataSource`).
22
23
  * Serialisation is a pluggable `Serializer` (JSON
23
24
  * default). Encryption, when needed, is an *application*-authored `Schema`
24
25
  * transform on a payload field; the codec only propagates its requirement and
@@ -122,6 +123,7 @@ export { buildDecisionModel, modelAtHead } from "./decisionModel.js";
122
123
  export { decodeSlices } from "./decode.js";
123
124
  export { CodecError, UnknownEventType } from "./errors.js";
124
125
  export { event } from "./event.js";
126
+ export { MetadataSource } from "./MetadataSource.js";
125
127
  export { decideOnly, transact, unsafeAppend } from "./precondition.js";
126
128
  export { projection } from "./projection.js";
127
129
  export { NoReadsRecorded, ReadLedger, TaglessSliceInLedger } from "./readLedger.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["decider","runDecider","Decision","isUnchanged","Unchanged","UnchangedTypeId","buildDecisionModel","modelAtHead","decodeSlices","CodecError","UnknownEventType","event","decideOnly","transact","unsafeAppend","projection","NoReadsRecorded","ReadLedger","TaglessSliceInLedger","makeRegistry","Serializer","SerializerDefault","toEvent","Uuid","UuidLive","UuidTest"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuHA,SAAuBA,OAAO,EAAEC,UAAU,QAAQ,cAAW;AAC7D,SACEC,QAAQ,EAGRC,WAAW,EACXC,SAAS,EACTC,eAAe,QACV,eAAY;AACnB,SACEC,kBAAkB,EAClBC,WAAW,QAEN,oBAAiB;AACxB,SAASC,YAAY,QAAQ,aAAU;AACvC,SAASC,UAAU,EAAEC,gBAAgB,QAAQ,aAAU;AACvD,SAA0CC,KAAK,QAAsB,YAAS;AAC9E,SACEC,UAAU,EAEVC,QAAQ,EACRC,YAAY,QACP,mBAAgB;AACvB,SAEEC,UAAU,QAEL,iBAAc;AACrB,SAGEC,eAAe,EACfC,UAAU,EACVC,oBAAoB,QACf,iBAAc;AACrB,SAASC,YAAY,QAAuB,eAAY;AACxD,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,iBAAc;AAC5D,SAASC,OAAO,QAAQ,cAAW;AACnC,SAASC,IAAI,EAAEC,QAAQ,EAAEC,QAAQ,QAAQ,WAAQ","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["decider","runDecider","Decision","isUnchanged","Unchanged","UnchangedTypeId","buildDecisionModel","modelAtHead","decodeSlices","CodecError","UnknownEventType","event","MetadataSource","decideOnly","transact","unsafeAppend","projection","NoReadsRecorded","ReadLedger","TaglessSliceInLedger","makeRegistry","Serializer","SerializerDefault","toEvent","Uuid","UuidLive","UuidTest"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwHA,SAAuBA,OAAO,EAAEC,UAAU,QAAQ,cAAW;AAC7D,SACEC,QAAQ,EAGRC,WAAW,EACXC,SAAS,EACTC,eAAe,QACV,eAAY;AACnB,SACEC,kBAAkB,EAClBC,WAAW,QAEN,oBAAiB;AACxB,SAASC,YAAY,QAAQ,aAAU;AACvC,SAASC,UAAU,EAAEC,gBAAgB,QAAQ,aAAU;AACvD,SAA0CC,KAAK,QAAsB,YAAS;AAC9E,SAASC,cAAc,QAAQ,qBAAkB;AACjD,SACEC,UAAU,EAEVC,QAAQ,EACRC,YAAY,QACP,mBAAgB;AACvB,SAEEC,UAAU,QAEL,iBAAc;AACrB,SAGEC,eAAe,EACfC,UAAU,EACVC,oBAAoB,QACf,iBAAc;AACrB,SAASC,YAAY,QAAuB,eAAY;AACxD,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,iBAAc;AAC5D,SAASC,OAAO,QAAQ,cAAW;AACnC,SAASC,IAAI,EAAEC,QAAQ,EAAEC,QAAQ,QAAQ,WAAQ","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import { composeProjections, ORIGIN, servableQueryFault, unionQueries } from '@kairos-es/core';
1
+ import { composeProjections, ORIGIN, servableQueryFault, unionQueries, unknownQueryKeyFault } from '@kairos-es/core';
2
2
  import { Context, Data, Effect, Layer, Option, Ref } from 'effect';
3
3
  /**
4
4
  * The ambient ledger, present only inside a bracket.
@@ -163,8 +163,23 @@ const NO_CLOSE = () => Effect.void;
163
163
  export const recordQuery = query => withLedger(NO_CLOSE, ledger => ledger.record(query));
164
164
  /** The tagless slice keys in a record, in declaration order. */
165
165
  const taglessKeys = projections => Object.entries(projections).filter(([, projection]) => projection.query.items.some(item => item.tags.length === 0)).map(([key]) => key);
166
- /** Would recording this record's query leave the accumulated union unservable? */
167
- const unionWouldBeUnservable = (existing, incoming) => servableQueryFault(unionQueries([...existing.map(h => h.query), incoming])) !== undefined;
166
+ /**
167
+ * Would recording this record's query leave the accumulated union unservable in
168
+ * its SHAPE — the one fault a slice's tags can fix, and so the one this ledger
169
+ * reports?
170
+ *
171
+ * An unknown key anywhere in the union answers no. It is not a tagless slice and no
172
+ * slice's tags would fix it, and the store refuses it as a defect naming the key at
173
+ * the read of the hop that carries it, so an earlier hop's key has already been
174
+ * refused once by the time a later record is judged. Judged here it would surface
175
+ * as this ledger's error, on the error channel, naming a slice with nothing wrong
176
+ * with it — and a hop is recorded before its read runs, so an earlier hop's key
177
+ * would go on doing that to every clean read after it.
178
+ */
179
+ const unionWouldBeUnservable = (existing, incoming) => {
180
+ const union = unionQueries([...existing.map(h => h.query), incoming]);
181
+ return unknownQueryKeyFault(union) === undefined && servableQueryFault(union) !== undefined;
182
+ };
168
183
  /**
169
184
  * Refuse a read that would leave the bracket's accumulated union unservable,
170
185
  * BEFORE the read is paid for.
@@ -1 +1 @@
1
- {"version":3,"file":"readLedger.js","names":["composeProjections","ORIGIN","servableQueryFault","unionQueries","Context","Data","Effect","Layer","Option","Ref","ReadLedger","Tag","NoReadsRecorded","TaggedError","message","TaglessSliceInLedger","sliceKey","deriveLayeredCondition","hops","length","undefined","merged","map","hop","query","arrived","flatMap","head","after","reduce","a","b","failIfEventsMatch","makeReadLedger","gen","ref","make","layer","succeed","record","modify","update","current","index","get","withLedger","absent","f","serviceOption","ledger","isNone","value","NO_CLOSE","void","recordQuery","taglessKeys","projections","Object","entries","filter","projection","items","some","item","tags","key","unionWouldBeUnservable","existing","incoming","h","assertServableAddition","offending","ambientLayeredCondition","none","fromNullable"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"readLedger.js","names":["composeProjections","ORIGIN","servableQueryFault","unionQueries","unknownQueryKeyFault","Context","Data","Effect","Layer","Option","Ref","ReadLedger","Tag","NoReadsRecorded","TaggedError","message","TaglessSliceInLedger","sliceKey","deriveLayeredCondition","hops","length","undefined","merged","map","hop","query","arrived","flatMap","head","after","reduce","a","b","failIfEventsMatch","makeReadLedger","gen","ref","make","layer","succeed","record","modify","update","current","index","get","withLedger","absent","f","serviceOption","ledger","isNone","value","NO_CLOSE","void","recordQuery","taglessKeys","projections","Object","entries","filter","projection","items","some","item","tags","key","unionWouldBeUnservable","existing","incoming","union","h","assertServableAddition","offending","ambientLayeredCondition","none","fromNullable"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,27 @@
1
- import { DateTime, Effect, Schema } from 'effect';
1
+ /**
2
+ * Event production (codec edge-helper): turn a typed payload into a wire
3
+ * `DcbEvent`. Encode is `Schema.encode(def.schema)` (a `ParseError` becomes a
4
+ * `CodecError`; any encryption transform runs here, *before* serialisation)
5
+ * then `serialiser.serialise`. The wire `tags` are derived from the def's
6
+ * required `tagsFor` mapper (ADR-0006) — they are never hand-passed, so two
7
+ * command sites emitting the same event type cannot tag it differently. A mapper
8
+ * that throws (e.g. an ill-formed `key:value` rejected by `Tag.make`) is
9
+ * surfaced on the `CodecError` channel, not as a defect. `uuid`
10
+ * comes from `options.uuid` or the `Uuid` service; `occurredAt` from
11
+ * `options.occurredAt` or the Effect clock (`DateTime.now`), keeping `core`
12
+ * clock- and RNG-free while staying overridable for backdated imports.
13
+ * `metadata` comes from `options.metadata` or the OPTIONAL ambient
14
+ * `MetadataSource` service, and is `{}` when neither supplies it (ADR-0017). A
15
+ * bag core's `Metadata` schema refuses, such as one holding a value that is not a
16
+ * string, fails on the `CodecError` channel (`reason: 'metadata'`), whichever of
17
+ * the two supplied it. It never reaches `tagsFor`, the
18
+ * event's schema or the serialiser, so it can enter neither the tag junction
19
+ * table nor the encryption seam.
20
+ */
21
+ import { Metadata } from '@kairos-es/core';
22
+ import { DateTime, Effect, Option, Schema } from 'effect';
2
23
  import { CodecError } from "./errors.js";
24
+ import { MetadataSource } from "./MetadataSource.js";
3
25
  import { Serializer } from "./Serializer.js";
4
26
  import { Uuid } from "./Uuid.js";
5
27
  /**
@@ -10,10 +32,40 @@ import { Uuid } from "./Uuid.js";
10
32
  * wire-envelope fields (the query surface), so a `tagsFor` mapper may only key
11
33
  * off cleartext payload fields (ADR-0006). `uuid` / `occurredAt` are
12
34
  * exact-optional overrides; absent, they come from the `Uuid` service and the
13
- * Effect clock.
35
+ * Effect clock. `metadata` is an exact-optional override too; absent, it comes
36
+ * from the ambient `MetadataSource` if one is provided and is `{}` otherwise.
37
+ * The ambient read adds nothing to the requirement channel. A bag core's
38
+ * `Metadata` schema refuses fails as a `CodecError` with `reason: 'metadata'`.
14
39
  */
15
40
  export const toEvent = (def, payload, options) => Effect.gen(function* () {
16
- // Derive tags first. A mapper is app code that can throw (e.g. `Tag.make`
41
+ // Resolve metadata before anything else. Per-call wins, ambient fills,
42
+ // absent yields `{}`. `serviceOption` keeps `MetadataSource` out of the
43
+ // requirement channel.
44
+ //
45
+ // The bag is then CHECKED against core's `Metadata` schema, whichever arm
46
+ // supplied it. The type holds a typed caller to a bag of strings, but an
47
+ // `any` or untyped JavaScript gets past it, and the engines then disagree
48
+ // about what they stored: the cross-engine parity of this field rests on its
49
+ // values being strings, and this is the one place a value is refused. It is
50
+ // refused HERE, at write, and never on read: a read-side check would make an
51
+ // event the store had accepted unreadable for ever. A bad bag is the
52
+ // caller's mistake, so it fails on the `CodecError` channel exactly as a
53
+ // throwing `tagsFor` does, never as a defect. Checking consumes no sequence,
54
+ // so placing it above the tag derivation leaves the property below intact.
55
+ //
56
+ // The bag is COPIED, never stamped by reference: an ambient bag would
57
+ // otherwise be ONE object shared by every event of a request, and the
58
+ // caller's own object would be shared with the event it built, so a mutation
59
+ // of either before the append would rewrite the other. (After the append no
60
+ // store shares anything with its caller; that is each store's guarantee.)
61
+ const given = options?.metadata === undefined ? Option.getOrElse(yield* Effect.serviceOption(MetadataSource), () => ({})) : options.metadata;
62
+ const metadata = {
63
+ ...(yield* Schema.decodeUnknown(Metadata)(given).pipe(Effect.mapError(cause => new CodecError({
64
+ reason: 'metadata',
65
+ cause
66
+ }))))
67
+ };
68
+ // Derive tags next. A mapper is app code that can throw (e.g. `Tag.make`
17
69
  // rejects an ill-formed `key:value`), and the codec's contract is that such
18
70
  // failures are values on the `CodecError` channel, never defects (errors.ts).
19
71
  // Deriving before the uuid/clock effects also means a bad tag fails without
@@ -38,7 +90,8 @@ export const toEvent = (def, payload, options) => Effect.gen(function* () {
38
90
  data,
39
91
  tags,
40
92
  uuid,
41
- occurredAt
93
+ occurredAt,
94
+ metadata
42
95
  };
43
96
  });
44
97
  //# sourceMappingURL=toEvent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toEvent.js","names":["DateTime","Effect","Schema","CodecError","Serializer","Uuid","toEvent","def","payload","options","gen","tags","try","tagsFor","catch","cause","reason","serializer","encoded","encode","schema","pipe","mapError","data","serialise","uuid","generate","occurredAt","now","type"],"sources":["../../src/toEvent.ts"],"sourcesContent":[null],"mappings":"AAcA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,MAAM,QAAQ,QAAQ;AACjD,SAASC,UAAU,QAAQ,aAAU;AAErC,SAASC,UAAU,QAAQ,iBAAc;AACzC,SAASC,IAAI,QAAQ,WAAQ;AAE7B;;;;;;;;;;AAUA,OAAO,MAAMC,OAAO,GAAGA,CACrBC,GAAsB,EACtBC,OAAU,EACVC,OAGC,KAEDR,MAAM,CAACS,GAAG,CAAC,aAAS;EAClB;EACA;EACA;EACA;EACA;EACA,MAAMC,IAAI,GAAG,OAAOV,MAAM,CAACW,GAAG,CAAC;IAC7BA,GAAG,EAAEA,CAAA,KAAML,GAAG,CAACM,OAAO,CAACL,OAAO,CAAC;IAC/BM,KAAK,EAAGC,KAAK,IAAK,IAAIZ,UAAU,CAAC;MAAEa,MAAM,EAAE,MAAM;MAAED;IAAK,CAAE;GAC3D,CAAC;EACF,MAAME,UAAU,GAAG,OAAOb,UAAU;EACpC,MAAMc,OAAO,GAAG,OAAOhB,MAAM,CAACiB,MAAM,CAACZ,GAAG,CAACa,MAAM,CAAC,CAACZ,OAAO,CAAC,CAACa,IAAI,CAC5DpB,MAAM,CAACqB,QAAQ,CAAEP,KAAK,IAAK,IAAIZ,UAAU,CAAC;IAAEa,MAAM,EAAE,QAAQ;IAAED;EAAK,CAAE,CAAC,CAAC,CACxE;EACD,MAAMQ,IAAI,GAAGN,UAAU,CAACO,SAAS,CAACN,OAAO,CAAC;EAC1C,MAAMO,IAAI,GAAGhB,OAAO,EAAEgB,IAAI,KAAK,OAAO,CAAC,OAAOpB,IAAI,EAAEqB,QAAQ,CAAC;EAC7D,MAAMC,UAAU,GAAGlB,OAAO,EAAEkB,UAAU,KAAK,OAAO3B,QAAQ,CAAC4B,GAAG,CAAC;EAC/D,OAAO;IACLC,IAAI,EAAEtB,GAAG,CAACsB,IAAI;IACdN,IAAI;IACJZ,IAAI;IACJc,IAAI;IACJE;GACD;AACH,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"toEvent.js","names":["Metadata","DateTime","Effect","Option","Schema","CodecError","MetadataSource","Serializer","Uuid","toEvent","def","payload","options","gen","given","metadata","undefined","getOrElse","serviceOption","decodeUnknown","pipe","mapError","cause","reason","tags","try","tagsFor","catch","serializer","encoded","encode","schema","data","serialise","uuid","generate","occurredAt","now","type"],"sources":["../../src/toEvent.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;AAoBA,SAAwBA,QAAQ,QAAQ,iBAAiB;AACzD,SAASC,QAAQ,EAAEC,MAAM,EAAEC,MAAM,EAAEC,MAAM,QAAQ,QAAQ;AACzD,SAASC,UAAU,QAAQ,aAAU;AAErC,SAASC,cAAc,QAAQ,qBAAkB;AACjD,SAASC,UAAU,QAAQ,iBAAc;AACzC,SAASC,IAAI,QAAQ,WAAQ;AAE7B;;;;;;;;;;;;;AAaA,OAAO,MAAMC,OAAO,GAAGA,CACrBC,GAAsB,EACtBC,OAAU,EACVC,OAIC,KAEDV,MAAM,CAACW,GAAG,CAAC,aAAS;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,KAAK,GACTF,OAAO,EAAEG,QAAQ,KAAKC,SAAS,GAC3Bb,MAAM,CAACc,SAAS,CACd,OAAOf,MAAM,CAACgB,aAAa,CAACZ,cAAc,CAAC,EAC3C,OAAiB,EAAE,CAAC,CACrB,GACDM,OAAO,CAACG,QAAQ;EACtB,MAAMA,QAAQ,GAAa;IACzB,IAAI,OAAOX,MAAM,CAACe,aAAa,CAACnB,QAAQ,CAAC,CAACc,KAAK,CAAC,CAACM,IAAI,CACnDlB,MAAM,CAACmB,QAAQ,CACZC,KAAK,IAAK,IAAIjB,UAAU,CAAC;MAAEkB,MAAM,EAAE,UAAU;MAAED;IAAK,CAAE,CAAC,CACzD,CACF;GACF;EACD;EACA;EACA;EACA;EACA;EACA,MAAME,IAAI,GAAG,OAAOtB,MAAM,CAACuB,GAAG,CAAC;IAC7BA,GAAG,EAAEA,CAAA,KAAMf,GAAG,CAACgB,OAAO,CAACf,OAAO,CAAC;IAC/BgB,KAAK,EAAGL,KAAK,IAAK,IAAIjB,UAAU,CAAC;MAAEkB,MAAM,EAAE,MAAM;MAAED;IAAK,CAAE;GAC3D,CAAC;EACF,MAAMM,UAAU,GAAG,OAAOrB,UAAU;EACpC,MAAMsB,OAAO,GAAG,OAAOzB,MAAM,CAAC0B,MAAM,CAACpB,GAAG,CAACqB,MAAM,CAAC,CAACpB,OAAO,CAAC,CAACS,IAAI,CAC5DlB,MAAM,CAACmB,QAAQ,CAAEC,KAAK,IAAK,IAAIjB,UAAU,CAAC;IAAEkB,MAAM,EAAE,QAAQ;IAAED;EAAK,CAAE,CAAC,CAAC,CACxE;EACD,MAAMU,IAAI,GAAGJ,UAAU,CAACK,SAAS,CAACJ,OAAO,CAAC;EAC1C,MAAMK,IAAI,GAAGtB,OAAO,EAAEsB,IAAI,KAAK,OAAO,CAAC,OAAO1B,IAAI,EAAE2B,QAAQ,CAAC;EAC7D,MAAMC,UAAU,GAAGxB,OAAO,EAAEwB,UAAU,KAAK,OAAOnC,QAAQ,CAACoC,GAAG,CAAC;EAC/D,OAAO;IACLC,IAAI,EAAE5B,GAAG,CAAC4B,IAAI;IACdN,IAAI;IACJR,IAAI;IACJU,IAAI;IACJE,UAAU;IACVrB;GACD;AACH,CAAC,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kairos-es/codec",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.4",
4
4
  "description": "Schema-first codec with encryption seam for kairos-es",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
@@ -12,7 +12,7 @@
12
12
  "homepage": "https://github.com/neverbland/kairos-es",
13
13
  "peerDependencies": {
14
14
  "effect": "^3.22.0",
15
- "@kairos-es/core": "^1.0.0-alpha.2"
15
+ "@kairos-es/core": "^1.0.0-alpha.4"
16
16
  },
17
17
  "main": "./dist/cjs/index.js",
18
18
  "module": "./dist/esm/index.js",
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The ambient metadata service: an OPTIONAL source of the `metadata` bag that
3
+ * `toEvent` stamps on an event when the call itself passes none (ADR-0017).
4
+ *
5
+ * An application provides it once, at the edge of a unit of work — an HTTP
6
+ * request, a job — and every event appended inside that scope carries the bag
7
+ * with no command handler, decider or `toEvent` call site mentioning it:
8
+ *
9
+ * ```ts
10
+ * handleRequest.pipe(
11
+ * Effect.provideService(MetadataSource, { traceparent: header }),
12
+ * )
13
+ * ```
14
+ *
15
+ * It is read through `Effect.serviceOption`, never `yield* MetadataSource`, and
16
+ * that choice is the whole design. `serviceOption` returns `Effect<Option<…>>`
17
+ * with BOTH the requirement and the error channel as `never`, so this tag never
18
+ * appears in `toEvent`'s requirement channel nor in any signature above it, and
19
+ * no consumer is forced to provide a layer it does not want. The `Uuid` service
20
+ * beside this is a REQUIRED tag; adopting that shape here would put a metadata
21
+ * layer on every consumer of the codec. Core stays a passive carrier: the
22
+ * ambient read happens here, in the codec, where reading a service breaches no
23
+ * purity rule.
24
+ *
25
+ * A per-call `options.metadata` REPLACES this value rather than merging with it:
26
+ * per-call wins, ambient fills, and absent yields `{}`. A merge would make the
27
+ * bag an event carries depend on two sources at once, and a caller who passes a
28
+ * bag explicitly is stating what the event's bag is.
29
+ *
30
+ * One key is reserved, as a convention and not a column: `traceparent`. Reserved
31
+ * means that when a bag carries W3C trace context it carries it under that key,
32
+ * holding a W3C `traceparent` header value, so tracing tools match it; kairos
33
+ * itself never writes or reads it. Every other key is the application's: a key
34
+ * is kairos's to name only when kairos writes it or a standard owns the
35
+ * spelling, and `correlationId` / `causationId` are suggested spellings rather
36
+ * than reserved ones (ADR-0017).
37
+ */
38
+ import type { Metadata } from '@kairos-es/core'
39
+ import { Context } from 'effect'
40
+
41
+ export class MetadataSource extends Context.Tag(
42
+ '@kairos-es/codec/MetadataSource',
43
+ )<MetadataSource, Metadata>() {}
package/src/index.ts CHANGED
@@ -17,8 +17,9 @@
17
17
  * on this path: the type is discovered at runtime, so no def was named to
18
18
  * narrow it (see `registry.ts`).
19
19
  *
20
- * `toEvent(def, payload, { uuid?, occurredAt? })` produces a wire event (encode
21
- * -> serialise, tags derived from `def.tagsFor`, clock + uuid from services).
20
+ * `toEvent(def, payload, { uuid?, occurredAt?, metadata? })` produces a wire
21
+ * event (encode -> serialise, tags derived from `def.tagsFor`, clock + uuid from
22
+ * services, metadata from the call or the optional ambient `MetadataSource`).
22
23
  * Serialisation is a pluggable `Serializer` (JSON
23
24
  * default). Encryption, when needed, is an *application*-authored `Schema`
24
25
  * transform on a payload field; the codec only propagates its requirement and
@@ -134,6 +135,7 @@ export {
134
135
  export { decodeSlices } from './decode'
135
136
  export { CodecError, UnknownEventType } from './errors'
136
137
  export { type EventDef, type EventDefAny, event, type TagsFor } from './event'
138
+ export { MetadataSource } from './MetadataSource'
137
139
  export {
138
140
  decideOnly,
139
141
  type Precondition,
package/src/readLedger.ts CHANGED
@@ -73,6 +73,7 @@ import {
73
73
  ORIGIN,
74
74
  servableQueryFault,
75
75
  unionQueries,
76
+ unknownQueryKeyFault,
76
77
  } from '@kairos-es/core'
77
78
  import { Context, Data, Effect, Layer, Option, Ref } from 'effect'
78
79
 
@@ -329,14 +330,29 @@ const taglessKeys = (
329
330
  )
330
331
  .map(([key]) => key)
331
332
 
332
- /** Would recording this record's query leave the accumulated union unservable? */
333
+ /**
334
+ * Would recording this record's query leave the accumulated union unservable in
335
+ * its SHAPE — the one fault a slice's tags can fix, and so the one this ledger
336
+ * reports?
337
+ *
338
+ * An unknown key anywhere in the union answers no. It is not a tagless slice and no
339
+ * slice's tags would fix it, and the store refuses it as a defect naming the key at
340
+ * the read of the hop that carries it, so an earlier hop's key has already been
341
+ * refused once by the time a later record is judged. Judged here it would surface
342
+ * as this ledger's error, on the error channel, naming a slice with nothing wrong
343
+ * with it — and a hop is recorded before its read runs, so an earlier hop's key
344
+ * would go on doing that to every clean read after it.
345
+ */
333
346
  const unionWouldBeUnservable = (
334
347
  existing: ReadonlyArray<Hop>,
335
348
  incoming: Query,
336
- ): boolean =>
337
- servableQueryFault(
338
- unionQueries([...existing.map((h) => h.query), incoming]),
339
- ) !== undefined
349
+ ): boolean => {
350
+ const union = unionQueries([...existing.map((h) => h.query), incoming])
351
+ return (
352
+ unknownQueryKeyFault(union) === undefined &&
353
+ servableQueryFault(union) !== undefined
354
+ )
355
+ }
340
356
 
341
357
  /**
342
358
  * Refuse a read that would leave the bracket's accumulated union unservable,
package/src/toEvent.ts CHANGED
@@ -10,11 +10,19 @@
10
10
  * comes from `options.uuid` or the `Uuid` service; `occurredAt` from
11
11
  * `options.occurredAt` or the Effect clock (`DateTime.now`), keeping `core`
12
12
  * clock- and RNG-free while staying overridable for backdated imports.
13
+ * `metadata` comes from `options.metadata` or the OPTIONAL ambient
14
+ * `MetadataSource` service, and is `{}` when neither supplies it (ADR-0017). A
15
+ * bag core's `Metadata` schema refuses, such as one holding a value that is not a
16
+ * string, fails on the `CodecError` channel (`reason: 'metadata'`), whichever of
17
+ * the two supplied it. It never reaches `tagsFor`, the
18
+ * event's schema or the serialiser, so it can enter neither the tag junction
19
+ * table nor the encryption seam.
13
20
  */
14
- import type { DcbEvent } from '@kairos-es/core'
15
- import { DateTime, Effect, Schema } from 'effect'
21
+ import { type DcbEvent, Metadata } from '@kairos-es/core'
22
+ import { DateTime, Effect, Option, Schema } from 'effect'
16
23
  import { CodecError } from './errors'
17
24
  import type { EventDef } from './event'
25
+ import { MetadataSource } from './MetadataSource'
18
26
  import { Serializer } from './Serializer'
19
27
  import { Uuid } from './Uuid'
20
28
 
@@ -26,7 +34,10 @@ import { Uuid } from './Uuid'
26
34
  * wire-envelope fields (the query surface), so a `tagsFor` mapper may only key
27
35
  * off cleartext payload fields (ADR-0006). `uuid` / `occurredAt` are
28
36
  * exact-optional overrides; absent, they come from the `Uuid` service and the
29
- * Effect clock.
37
+ * Effect clock. `metadata` is an exact-optional override too; absent, it comes
38
+ * from the ambient `MetadataSource` if one is provided and is `{}` otherwise.
39
+ * The ambient read adds nothing to the requirement channel. A bag core's
40
+ * `Metadata` schema refuses fails as a `CodecError` with `reason: 'metadata'`.
30
41
  */
31
42
  export const toEvent = <A, I, R>(
32
43
  def: EventDef<A, I, R>,
@@ -34,10 +45,45 @@ export const toEvent = <A, I, R>(
34
45
  options?: {
35
46
  readonly uuid?: string
36
47
  readonly occurredAt?: DateTime.Utc
48
+ readonly metadata?: Metadata
37
49
  },
38
50
  ): Effect.Effect<DcbEvent, CodecError, Serializer | Uuid | R> =>
39
51
  Effect.gen(function* () {
40
- // Derive tags first. A mapper is app code that can throw (e.g. `Tag.make`
52
+ // Resolve metadata before anything else. Per-call wins, ambient fills,
53
+ // absent yields `{}`. `serviceOption` keeps `MetadataSource` out of the
54
+ // requirement channel.
55
+ //
56
+ // The bag is then CHECKED against core's `Metadata` schema, whichever arm
57
+ // supplied it. The type holds a typed caller to a bag of strings, but an
58
+ // `any` or untyped JavaScript gets past it, and the engines then disagree
59
+ // about what they stored: the cross-engine parity of this field rests on its
60
+ // values being strings, and this is the one place a value is refused. It is
61
+ // refused HERE, at write, and never on read: a read-side check would make an
62
+ // event the store had accepted unreadable for ever. A bad bag is the
63
+ // caller's mistake, so it fails on the `CodecError` channel exactly as a
64
+ // throwing `tagsFor` does, never as a defect. Checking consumes no sequence,
65
+ // so placing it above the tag derivation leaves the property below intact.
66
+ //
67
+ // The bag is COPIED, never stamped by reference: an ambient bag would
68
+ // otherwise be ONE object shared by every event of a request, and the
69
+ // caller's own object would be shared with the event it built, so a mutation
70
+ // of either before the append would rewrite the other. (After the append no
71
+ // store shares anything with its caller; that is each store's guarantee.)
72
+ const given: unknown =
73
+ options?.metadata === undefined
74
+ ? Option.getOrElse(
75
+ yield* Effect.serviceOption(MetadataSource),
76
+ (): Metadata => ({}),
77
+ )
78
+ : options.metadata
79
+ const metadata: Metadata = {
80
+ ...(yield* Schema.decodeUnknown(Metadata)(given).pipe(
81
+ Effect.mapError(
82
+ (cause) => new CodecError({ reason: 'metadata', cause }),
83
+ ),
84
+ )),
85
+ }
86
+ // Derive tags next. A mapper is app code that can throw (e.g. `Tag.make`
41
87
  // rejects an ill-formed `key:value`), and the codec's contract is that such
42
88
  // failures are values on the `CodecError` channel, never defects (errors.ts).
43
89
  // Deriving before the uuid/clock effects also means a bad tag fails without
@@ -59,5 +105,6 @@ export const toEvent = <A, I, R>(
59
105
  tags,
60
106
  uuid,
61
107
  occurredAt,
108
+ metadata,
62
109
  }
63
110
  })