@kairos-es/codec 1.0.0-alpha.4 → 1.0.0-alpha.6

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 (137) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/MetadataSource.js +1 -1
  3. package/dist/cjs/MetadataSource.js.map +1 -1
  4. package/dist/cjs/Serializer.js +3 -3
  5. package/dist/cjs/Serializer.js.map +1 -1
  6. package/dist/cjs/Uuid.js +6 -3
  7. package/dist/cjs/Uuid.js.map +1 -1
  8. package/dist/cjs/decider.js +1 -1
  9. package/dist/cjs/decisionModel.js +1 -1
  10. package/dist/cjs/decisionModel.js.map +1 -1
  11. package/dist/cjs/decode.js +5 -5
  12. package/dist/cjs/decode.js.map +1 -1
  13. package/dist/cjs/deserialiseThenDecode.js +1 -1
  14. package/dist/cjs/deserialiseThenDecode.js.map +1 -1
  15. package/dist/cjs/errors.js +6 -4
  16. package/dist/cjs/errors.js.map +1 -1
  17. package/dist/cjs/event.js.map +1 -1
  18. package/dist/cjs/precondition.js +2 -2
  19. package/dist/cjs/precondition.js.map +1 -1
  20. package/dist/cjs/projection.js +9 -10
  21. package/dist/cjs/projection.js.map +1 -1
  22. package/dist/cjs/readLedger.js +3 -3
  23. package/dist/cjs/readLedger.js.map +1 -1
  24. package/dist/cjs/registry.js.map +1 -1
  25. package/dist/cjs/toEvent.js +4 -4
  26. package/dist/cjs/toEvent.js.map +1 -1
  27. package/dist/dts-cjs/MetadataSource.d.ts +8 -0
  28. package/dist/{dts → dts-cjs}/MetadataSource.d.ts.map +1 -1
  29. package/dist/{dts → dts-cjs}/Serializer.d.ts +3 -3
  30. package/dist/{dts → dts-cjs}/Serializer.d.ts.map +1 -1
  31. package/dist/{dts → dts-cjs}/Uuid.d.ts +6 -3
  32. package/dist/{dts → dts-cjs}/Uuid.d.ts.map +1 -1
  33. package/dist/{dts → dts-cjs}/decider.d.ts +7 -7
  34. package/dist/{dts → dts-cjs}/decider.d.ts.map +1 -1
  35. package/dist/{dts → dts-cjs}/decision.d.ts +2 -2
  36. package/dist/{dts → dts-cjs}/decode.d.ts +3 -3
  37. package/dist/{dts → dts-cjs}/decode.d.ts.map +1 -1
  38. package/dist/{dts → dts-cjs}/deserialiseThenDecode.d.ts +3 -3
  39. package/dist/{dts → dts-cjs}/deserialiseThenDecode.d.ts.map +1 -1
  40. package/dist/{dts → dts-cjs}/errors.d.ts +4 -3
  41. package/dist/dts-cjs/errors.d.ts.map +1 -0
  42. package/dist/{dts → dts-cjs}/event.d.ts +18 -8
  43. package/dist/dts-cjs/event.d.ts.map +1 -0
  44. package/dist/dts-cjs/package.json +3 -0
  45. package/dist/{dts → dts-cjs}/precondition.d.ts +2 -2
  46. package/dist/{dts → dts-cjs}/projection.d.ts +2 -2
  47. package/dist/dts-cjs/projection.d.ts.map +1 -0
  48. package/dist/{dts → dts-cjs}/readLedger.d.ts +4 -4
  49. package/dist/{dts → dts-cjs}/readLedger.d.ts.map +1 -1
  50. package/dist/{dts → dts-cjs}/toEvent.d.ts +2 -2
  51. package/dist/dts-esm/MetadataSource.d.ts +8 -0
  52. package/dist/dts-esm/MetadataSource.d.ts.map +1 -0
  53. package/dist/dts-esm/Serializer.d.ts +27 -0
  54. package/dist/dts-esm/Serializer.d.ts.map +1 -0
  55. package/dist/dts-esm/Uuid.d.ts +22 -0
  56. package/dist/dts-esm/Uuid.d.ts.map +1 -0
  57. package/dist/dts-esm/decider.d.ts +206 -0
  58. package/dist/dts-esm/decider.d.ts.map +1 -0
  59. package/dist/dts-esm/decision.d.ts +161 -0
  60. package/dist/dts-esm/decision.d.ts.map +1 -0
  61. package/dist/dts-esm/decisionModel.d.ts +149 -0
  62. package/dist/dts-esm/decisionModel.d.ts.map +1 -0
  63. package/dist/dts-esm/decode.d.ts +92 -0
  64. package/dist/dts-esm/decode.d.ts.map +1 -0
  65. package/dist/dts-esm/deserialiseThenDecode.d.ts +62 -0
  66. package/dist/dts-esm/deserialiseThenDecode.d.ts.map +1 -0
  67. package/dist/dts-esm/errors.d.ts +80 -0
  68. package/dist/dts-esm/errors.d.ts.map +1 -0
  69. package/dist/dts-esm/event.d.ts +81 -0
  70. package/dist/dts-esm/event.d.ts.map +1 -0
  71. package/dist/dts-esm/index.d.ts +134 -0
  72. package/dist/dts-esm/index.d.ts.map +1 -0
  73. package/dist/dts-esm/package.json +3 -0
  74. package/dist/dts-esm/precondition.d.ts +244 -0
  75. package/dist/dts-esm/precondition.d.ts.map +1 -0
  76. package/dist/dts-esm/projection.d.ts +56 -0
  77. package/dist/dts-esm/projection.d.ts.map +1 -0
  78. package/dist/dts-esm/readLedger.d.ts +263 -0
  79. package/dist/dts-esm/readLedger.d.ts.map +1 -0
  80. package/dist/dts-esm/registry.d.ts +46 -0
  81. package/dist/dts-esm/registry.d.ts.map +1 -0
  82. package/dist/dts-esm/toEvent.d.ts +45 -0
  83. package/dist/dts-esm/toEvent.d.ts.map +1 -0
  84. package/dist/esm/MetadataSource.js +1 -1
  85. package/dist/esm/MetadataSource.js.map +1 -1
  86. package/dist/esm/Serializer.js +3 -3
  87. package/dist/esm/Serializer.js.map +1 -1
  88. package/dist/esm/Uuid.js +6 -3
  89. package/dist/esm/Uuid.js.map +1 -1
  90. package/dist/esm/decider.js +1 -1
  91. package/dist/esm/decisionModel.js +1 -1
  92. package/dist/esm/decisionModel.js.map +1 -1
  93. package/dist/esm/decode.js +5 -5
  94. package/dist/esm/decode.js.map +1 -1
  95. package/dist/esm/deserialiseThenDecode.js +1 -1
  96. package/dist/esm/deserialiseThenDecode.js.map +1 -1
  97. package/dist/esm/errors.js +6 -4
  98. package/dist/esm/errors.js.map +1 -1
  99. package/dist/esm/event.js.map +1 -1
  100. package/dist/esm/precondition.js +2 -2
  101. package/dist/esm/precondition.js.map +1 -1
  102. package/dist/esm/projection.js +9 -10
  103. package/dist/esm/projection.js.map +1 -1
  104. package/dist/esm/readLedger.js +3 -3
  105. package/dist/esm/readLedger.js.map +1 -1
  106. package/dist/esm/registry.js.map +1 -1
  107. package/dist/esm/toEvent.js +4 -4
  108. package/dist/esm/toEvent.js.map +1 -1
  109. package/package.json +12 -7
  110. package/src/MetadataSource.ts +2 -2
  111. package/src/Serializer.ts +4 -4
  112. package/src/Uuid.ts +7 -4
  113. package/src/decider.ts +9 -9
  114. package/src/decision.ts +1 -1
  115. package/src/decisionModel.ts +1 -1
  116. package/src/decode.ts +12 -18
  117. package/src/deserialiseThenDecode.ts +5 -5
  118. package/src/errors.ts +6 -4
  119. package/src/event.ts +19 -9
  120. package/src/precondition.ts +3 -3
  121. package/src/projection.ts +15 -20
  122. package/src/readLedger.ts +7 -7
  123. package/src/registry.ts +1 -1
  124. package/src/toEvent.ts +4 -4
  125. package/dist/dts/MetadataSource.d.ts +0 -8
  126. package/dist/dts/errors.d.ts.map +0 -1
  127. package/dist/dts/event.d.ts.map +0 -1
  128. package/dist/dts/projection.d.ts.map +0 -1
  129. /package/dist/{dts → dts-cjs}/decision.d.ts.map +0 -0
  130. /package/dist/{dts → dts-cjs}/decisionModel.d.ts +0 -0
  131. /package/dist/{dts → dts-cjs}/decisionModel.d.ts.map +0 -0
  132. /package/dist/{dts → dts-cjs}/index.d.ts +0 -0
  133. /package/dist/{dts → dts-cjs}/index.d.ts.map +0 -0
  134. /package/dist/{dts → dts-cjs}/precondition.d.ts.map +0 -0
  135. /package/dist/{dts → dts-cjs}/registry.d.ts +0 -0
  136. /package/dist/{dts → dts-cjs}/registry.d.ts.map +0 -0
  137. /package/dist/{dts → dts-cjs}/toEvent.d.ts.map +0 -0
@@ -20,10 +20,10 @@
20
20
  * than memory.
21
21
  *
22
22
  * Be precise about what adding `concurrency` here would and would not cost,
23
- * because the obvious reason is the wrong one. Effect v3's `mapEffect` is
23
+ * because the obvious reason is the wrong one. Effect's `mapEffect` is
24
24
  * order-PRESERVING even when concurrent — reordering needs the separate
25
- * `unordered: true` option (verified against the installed
26
- * `effect@3.22`'s `Stream.d.ts`, and probed at runtime) — so a bare
25
+ * `unordered: true` option (verified against `effect@4`'s `Channel.mapEffect`,
26
+ * which takes the ordered path unless that option is set) — so a bare
27
27
  * `concurrency` would NOT hand the fold its events out of position order. What
28
28
  * it would actually cost is the back-pressure above, and it would run
29
29
  * application-authored `Schema` transforms (an ADR-0004 decryption hook, say)
@@ -1 +1 @@
1
- {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,EAAuB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAIpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AA0JzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACpE,QAAQ,CAAC,KACR,CAAC,CAAC,CAAC,EAAE,CAAC,EACP,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC,KACxC,MAAM,CAAC,MAAM,CAChB,YAAY,EACZ,CAAC,GAAG,UAAU,EACd,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAClC,CAA4C,CAAA"}
1
+ {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,EAAuB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAIpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAoJzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACpE,QAAQ,CAAC,KACR,CAAC,CAAC,CAAC,EAAE,CAAC,EACP,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC,KACxC,MAAM,CAAC,MAAM,CAChB,YAAY,EACZ,CAAC,GAAG,UAAU,EACd,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAClC,CAA4C,CAAA"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The two-step every decode in this package performs, in one implementation:
3
3
  * deserialise the wire bytes through the `Serializer` its caller already holds,
4
- * then `Schema.decodeUnknown` the result, each half's failure wrapped as the
4
+ * then `Schema.decodeUnknownEffect` the result, each half's failure wrapped as the
5
5
  * `CodecError` whose `reason` says WHICH half failed.
6
6
  *
7
7
  * **What it is the single home of.** The two `reason` strings `'deserialise'`
@@ -17,7 +17,7 @@
17
17
  * as a function and not as a second test.
18
18
  *
19
19
  * **The order is contract, not accident.** Deserialise has to run first because
20
- * `Schema.decodeUnknown` has nothing to read until it has, and the observable
20
+ * `Schema.decodeUnknownEffect` has nothing to read until it has, and the observable
21
21
  * consequence is that the two reasons PARTITION the causes an operator acts on:
22
22
  * rotten bytes are always `'deserialise'` and never `'decode'`, so a storage or
23
23
  * producer problem never arrives dressed as schema drift. Swapping the labels
@@ -58,5 +58,5 @@ import type { Context } from 'effect';
58
58
  import { Effect, Schema } from 'effect';
59
59
  import { CodecError } from './errors.js';
60
60
  import type { Serializer } from './Serializer.js';
61
- export declare const deserialiseThenDecode: <R>(serializer: Context.Tag.Service<Serializer>, schema: Schema.Schema<unknown, unknown, R>, bytes: Uint8Array) => Effect.Effect<unknown, CodecError, R>;
61
+ export declare const deserialiseThenDecode: <R>(serializer: Context.Service.Shape<typeof Serializer>, schema: Schema.Decoder<unknown, R>, bytes: Uint8Array) => Effect.Effect<unknown, CodecError, R>;
62
62
  //# sourceMappingURL=deserialiseThenDecode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deserialiseThenDecode.d.ts","sourceRoot":"","sources":["../../src/deserialiseThenDecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACrC,YAAY,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAC3C,QAAQ,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,EAC1C,OAAO,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAUpC,CAAA"}
1
+ {"version":3,"file":"deserialiseThenDecode.d.ts","sourceRoot":"","sources":["../../src/deserialiseThenDecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACrC,YAAY,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,EACpD,QAAQ,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAClC,OAAO,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAUpC,CAAA"}
@@ -30,9 +30,10 @@ export declare class CodecError extends CodecError_base<{
30
30
  *
31
31
  * A GETTER rather than a second field, so `reason` stays the single declaration.
32
32
  * It is visible because `Data.TaggedError`'s constructor is
33
- * `super(args?.message, …)` followed by `Object.assign(this, args)` (verified
34
- * against `effect@3.22`'s `Data.ts`): the args above carry no `message`, so
35
- * nothing shadows this prototype accessor with an own property.
33
+ * `super(args?.message, …)` followed by copying the args' own enumerable keys
34
+ * onto the instance (verified against `effect@4`'s `internal/core.ts`): the
35
+ * args above carry no `message`, so nothing shadows this prototype accessor
36
+ * with an own property.
36
37
  */
37
38
  get message(): string;
38
39
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAgBA,2EAA2E;AAC3E,qBAAa,UAAW,SAAQ,gBAA+B;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF;;;;AAED,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAC;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,IAAa,OAAO,IAAI,MAAM,CAE7B;CACF"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Event definitions: a tagged `Schema` built through `event(type, fields,
3
- * tagsFor)`. Each def is a `Schema<Payload, Wire, R>` plus its branded versioned
3
+ * tagsFor)`. Each def is a `Schema.Codec<Payload, Wire, R, R>` plus its branded versioned
4
4
  * `type` (ADR-0005) captured *beside* the payload, and a required `tagsFor`
5
5
  * mapper deriving the event's tags from its decoded payload (ADR-0006).
6
6
  *
@@ -40,19 +40,29 @@ export type TagsFor<A> = (payload: A) => Arr.NonEmptyReadonlyArray<Tag>;
40
40
  /**
41
41
  * An event definition: its branded `type`, the `Schema` mapping its typed
42
42
  * payload `A` to its wire encoding `I` (requiring `R`), and the `tagsFor` mapper
43
- * that derives the event's tags from a decoded payload. `Schema` is invariant in
44
- * `A`/`I`, so `EventDef` cannot be `out A`/`out I`.
43
+ * that derives the event's tags from a decoded payload.
44
+ *
45
+ * `R` is ONE requirement for both directions, which is why the schema is a
46
+ * `Schema.Codec<A, I, R, R>` rather than leaving decoding and encoding services
47
+ * apart. A def is decoded on the read path and encoded by `toEvent`, so a
48
+ * consumer providing a def's services provides them for both; an application
49
+ * encryption transform needs its key either way. A struct whose two directions
50
+ * differ still fits, the codec being covariant in both, and `R` is then their
51
+ * union.
52
+ *
53
+ * `tagsFor` CONSUMES an `A`, so `EventDef` is invariant in `A` whatever the
54
+ * schema's own variance, and is therefore not declared `out A`.
45
55
  */
46
56
  export interface EventDef<A = unknown, I = unknown, R = never> {
47
57
  readonly type: EventType;
48
- readonly schema: Schema.Schema<A, I, R>;
58
+ readonly schema: Schema.Codec<A, I, R, R>;
49
59
  readonly tagsFor: TagsFor<A>;
50
60
  }
51
61
  /**
52
- * The heterogeneous bound (mirrors `Schema.Schema.Any`) for arrays/records of
53
- * mixed defs, where the precise `A`/`I` differ per element. `tagsFor` erases to
54
- * `(a: any) => …`, which is harmless: only the write path (`toEvent`) calls it,
55
- * and the registry/decode path never does (stored events already carry tags).
62
+ * The heterogeneous bound for arrays/records of mixed defs, where the precise
63
+ * `A`/`I` differ per element. `tagsFor` erases to `(a: any) => …`, which is
64
+ * harmless: only the write path (`toEvent`) calls it, and the registry/decode
65
+ * path never does (stored events already carry tags).
56
66
  */
57
67
  export type EventDefAny = EventDef<any, any, unknown>;
58
68
  /**
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,QAAQ,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;;;GAKG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,GAAG,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAA;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,KAAK;IAC3D,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAC7B;AAED;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,GAChB,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EAEnC,MAAM,IAAI,EACV,QAAQ,MAAM,EACd,SAAS,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAC3C;IACD,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;CAStD,CAAA"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -137,7 +137,7 @@ import type { Uuid } from './Uuid.js';
137
137
  * path meant to deny the input cheaply. Wrap such work in `Effect.suspend`.
138
138
  */
139
139
  export interface Precondition<Id, Service, E, R> {
140
- readonly tag: Context.Tag<Id, Service>;
140
+ readonly tag: Context.Key<Id, Service>;
141
141
  readonly evaluate: Effect.Effect<Service, E, R>;
142
142
  }
143
143
  /**
@@ -211,7 +211,7 @@ export declare const decideOnly: <P extends Record<string, SliceProjection>, Com
211
211
  * condition here. If that turns up in practice, a composing override is the
212
212
  * additive answer and this hatch is not it.
213
213
  *
214
- * `Effect.mapInputContext` over
214
+ * `Effect.updateContext` over
215
215
  * `Context.omit(AppendIsOwned)` is what lets it through the store's ownership
216
216
  * refusal — the one route, and `AppendIsOwned.ts` owns why removing the marker is
217
217
  * the shape rather than a second tag or a sanctioning flag.
@@ -5,7 +5,7 @@
5
5
  * A `SliceProjection<S, R>` is a core `AnyProjection<S>` (directly composable —
6
6
  * its `evolve` folds a `DecodedEvent`) enriched with the `type -> Schema` map
7
7
  * `decodeSlices` merges and decodes through. That map's value type carries `R`
8
- * covariantly (`Schema<unknown, unknown, R>`), so the union of the defs'
8
+ * covariantly (`Schema.Decoder<unknown, R>`), so the union of the defs'
9
9
  * requirements flows to the decision model with no cast (and no phantom marker).
10
10
  * Because `evolve` is already erased, a built slice drops straight into
11
11
  * `composeProjections` — no `AnyProjection.of` ceremony.
@@ -27,7 +27,7 @@ import type { EventDef } from './event.js';
27
27
  * (and the `out R` annotation keeps union-widening sound) with no phantom marker.
28
28
  */
29
29
  export interface SliceProjection<out S = unknown, out R = unknown> extends AnyProjection<S> {
30
- readonly schemas: ReadonlyMap<string, Schema.Schema<unknown, unknown, R>>;
30
+ readonly schemas: ReadonlyMap<string, Schema.Decoder<unknown, R>>;
31
31
  }
32
32
  /** The fluent builder: accumulate `.on(def, fold)` steps, then `.build()`. */
33
33
  export interface ProjectionBuilder<S, R = never> {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../src/projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,KAAK,aAAa,EAIlB,KAAK,GAAG,EACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,CAC/D,SAAQ,aAAa,CAAC,CAAC,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;CAClE;AAED,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK;IAC7C;;;;;;;OAOG;IACH,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EACT,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EACvB,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GAChC,iBAAiB,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAA;IAC/B;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA;KAAE,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAC/E;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,cAAc,CAAC,KAAG,iBAAiB,CAAC,CAAC,EAAE,KAAK,CA4FzE,CAAA"}
@@ -76,7 +76,7 @@ export interface Hop {
76
76
  readonly query: Query;
77
77
  readonly head?: Position;
78
78
  }
79
- declare const ReadLedger_base: Context.TagClass<ReadLedger, "@kairos-es/codec/ReadLedger", {
79
+ declare const ReadLedger_base: Context.ServiceClass<ReadLedger, "@kairos-es/codec/ReadLedger", {
80
80
  /**
81
81
  * File a query, and hand back the effect that will fill in its head.
82
82
  *
@@ -101,7 +101,7 @@ declare const ReadLedger_base: Context.TagClass<ReadLedger, "@kairos-es/codec/Re
101
101
  * requirement channel nothing is exactly what makes this change additive.
102
102
  * `modelAtHead` is that path and is why the rule exists.
103
103
  *
104
- * A BRACKET-ONLY function is the opposite case and yields the tag deliberately.
104
+ * A BRACKET-ONLY function is the opposite case and yields the service deliberately.
105
105
  * `decideOnly` does, and naming the requirement is what turns *"call me inside a
106
106
  * bracket"* from a runtime defect into a compile error — presence being the one
107
107
  * direction the type system can decide here. So the test is what the function
@@ -117,8 +117,8 @@ export declare class ReadLedger extends ReadLedger_base {
117
117
  * Fill in a recorded hop's head. Never called if the read does not complete.
118
118
  *
119
119
  * On the package's public surface because it is already ON it: `record` returns
120
- * one, `ReadLedger` is exported, so a consumer holding the tag holds this type and
121
- * could not name it. `Hop` was exported and this was not — the same interface, two
120
+ * one, `ReadLedger` is exported, so a consumer holding the service holds this
121
+ * type and could not name it. `Hop` was exported and this was not — the same interface, two
122
122
  * treatments.
123
123
  */
124
124
  export type CloseHop = (head: Position) => Effect.Effect<void>;
@@ -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;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"}
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,eAmBE;CAAG;AAErC;;;;;;;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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
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)
3
+ * `DcbEvent`. Encode is `Schema.encodeEffect(def.schema)` (a `SchemaError`
4
+ * becomes a `CodecError`; any encryption transform runs here, *before* serialisation)
5
5
  * then `serialiser.serialise`. The wire `tags` are derived from the def's
6
6
  * required `tagsFor` mapper (ADR-0006) — they are never hand-passed, so two
7
7
  * command sites emitting the same event type cannot tag it differently. A mapper
@@ -0,0 +1,8 @@
1
+ import { Context } from 'effect';
2
+ declare const MetadataSource_base: Context.ServiceClass<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,mBAEnC;CAAG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The pluggable serialiser: the `Uint8Array` <-> value boundary applied
3
+ * *outside* `Schema`. Encode is `Schema.encodeEffect` then `serialise`; decode is
4
+ * `deserialise` then `Schema.decodeUnknownEffect`. Both codec paths read the same
5
+ * `Serializer` from context, so encode and decode cannot mismatch; swapping
6
+ * JSON for msgpack is a different layer with no schema or call-site changes.
7
+ *
8
+ * `deserialise` may throw synchronously (corrupt bytes): wrapping it as a
9
+ * `CodecError` is the *caller's* concern — every decode site wraps it in
10
+ * `Effect.try`. Keeping the service interface plain (no Effect) lets a layer be
11
+ * a trivial `Layer.succeed`.
12
+ */
13
+ import { Context, Layer } from 'effect';
14
+ declare const Serializer_base: Context.ServiceClass<Serializer, "@kairos-es/codec/Serializer", {
15
+ readonly serialise: (v: unknown) => Uint8Array;
16
+ readonly deserialise: (b: Uint8Array) => unknown;
17
+ }>;
18
+ export declare class Serializer extends Serializer_base {
19
+ }
20
+ /**
21
+ * The shipped default: JSON over UTF-8. `serialise` = `JSON.stringify` then
22
+ * `TextEncoder`; `deserialise` = `TextDecoder` then `JSON.parse` (which throws
23
+ * synchronously on corrupt bytes, wrapped to `CodecError` at the call site).
24
+ */
25
+ export declare const SerializerDefault: Layer.Layer<Serializer>;
26
+ export {};
27
+ //# sourceMappingURL=Serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Serializer.d.ts","sourceRoot":"","sources":["../../src/Serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;;wBAKf,CAAC,CAAC,EAAE,OAAO,KAAK,UAAU;0BACxB,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO;;AAJpD,qBAAa,UAAW,SAAQ,eAME;CAAG;AAKrC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAMrD,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { Context, Effect, Layer } from 'effect';
2
+ declare const Uuid_base: Context.ServiceClass<Uuid, "@kairos-es/codec/Uuid", {
3
+ readonly generate: Effect.Effect<string>;
4
+ }>;
5
+ export declare class Uuid extends Uuid_base {
6
+ }
7
+ /** Live uuid generation via WebCrypto (no `node:crypto`). */
8
+ export declare const UuidLive: Layer.Layer<Uuid>;
9
+ /**
10
+ * A deterministic uuid layer for suites, wrapping core's shared
11
+ * `makeSequentialUuid` (the single source of truth for the counter scheme).
12
+ * Each BUILD of the layer makes a fresh generator, so it owns its own counter and
13
+ * yields a stable v4-shaped sequence `00000000-0000-4000-8000-<12 hex>` starting
14
+ * at `...000000000000`. A build is not one per `Effect.provide`: Effect memoises
15
+ * a layer across the provisions that share a memo map, so a nested second
16
+ * provision of this layer continues the counter rather than restarting it, and
17
+ * `Layer.fresh` is the way to ask for a restart. Generation is wrapped in `Effect.sync` because the
18
+ * generator advances its counter (a side effect on each call).
19
+ */
20
+ export declare const UuidTest: Layer.Layer<Uuid>;
21
+ export {};
22
+ //# sourceMappingURL=Uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Uuid.d.ts","sourceRoot":"","sources":["../../src/Uuid.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;;uBAIxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;;AAF5C,qBAAa,IAAK,SAAQ,SAGE;CAAG;AAE/B,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAErC,CAAA;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAGrC,CAAA"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * A `Decider`: the write side's unit of decision. It pairs the projections a
3
+ * command handler reads (its decision model) with an effectful `decide` step
4
+ * that turns the folded state plus a command into the events to append.
5
+ *
6
+ * This is PRODUCTION code and it lives beside the `buildDecisionModel` it
7
+ * drives. It began in `@kairos-es/testing` because the Given/When/Then surface
8
+ * was its first consumer, but nothing in it is test apparatus: every import
9
+ * resolves to this package or to `@kairos-es/core`, and a test framework is
10
+ * never one of them. That home was a real hazard rather than a tidiness
11
+ * complaint — `@kairos-es/testing` peers `@effect/vitest`, so a command handler
12
+ * typed against `Decider` (as this repo's own worked example is, in `src/` and
13
+ * not `test/`) named a package whose sibling module imports `expect` and `it` at
14
+ * top level, and a handler that actually RAN a command would have
15
+ * runtime-imported `runDecider` from it, loading a test framework into a
16
+ * production module graph. `@kairos-es/read/testing` documents that same hazard
17
+ * as the reason a subpath may add no peer; the difference here is that this is
18
+ * not a testing surface at all, so the fix is a home rather than a rule.
19
+ *
20
+ * `@kairos-es/testing` now imports these two symbols like any other consumer,
21
+ * and NO compatibility re-export is left behind there: nothing is published yet,
22
+ * so a re-export would be permanent clutter bought for no consumer, and it would
23
+ * preserve in that package's public surface exactly the coupling the move
24
+ * exists to remove. That is the argument ADR-0008 made when `retryOnConflict`
25
+ * moved to the package that owns the error it matches, and it holds here for the
26
+ * same reason — a write-side consumer depending on the wrong package is
27
+ * backwards, whichever direction the dependency points.
28
+ *
29
+ * `projections` is a *function of the command* because a DCB decision model is
30
+ * parametrised by the command's own identifiers (e.g. narrow to
31
+ * `course:{command.courseId}`), which keeps the consistency boundary — and the
32
+ * `failIfEventsMatch` guard the read produces — as tight as the decision
33
+ * actually needs. This mirrors dcb-events, where the command handler calls
34
+ * `buildDecisionModel(store, { ...projections built from command.data })`.
35
+ *
36
+ * `runDecider` runs the DCB command cycle against whatever `DcbEventStore` is in
37
+ * context: build the decision model for the command (a real `read` + decode +
38
+ * fold via `buildDecisionModel`), decide, then `append` the new events under the
39
+ * append condition the read produced. That IS the optimistic-concurrency
40
+ * contract, in production and in a scenario alike — which is also why the
41
+ * Given/When/Then surface built on it exercises the real fold and the real store
42
+ * rather than a mock. It is a free function rather than a `Context.Service`,
43
+ * so it is still not the "production command-runner service method" a retrying
44
+ * `Layer` would need (ADR-0008): the correct retry remains
45
+ * `retryOnConflict(runDecider(...))`, wrapping the whole cycle so a fresh read
46
+ * re-derives the condition.
47
+ *
48
+ * The `decide` step produces its events effectfully (they are encoded via
49
+ * `toEvent`, so it requires `Serializer | Uuid | R`) and may fail on its own
50
+ * error channel (a domain rule violation, e.g. "course already exists"); the
51
+ * append may fail with `AppendConditionFailed` if a concurrent writer moved the
52
+ * boundary, and decode may fail with `CodecError`. All surface on the error
53
+ * channel, so a caller handles all three the same way — and
54
+ * `@kairos-es/testing`'s `.thenError(tag)` can assert any of them.
55
+ *
56
+ * `decide` may also answer `Unchanged` — "already done, nothing to append" — but
57
+ * only where its type says so: `Decider`'s fifth type parameter `O` defaults to
58
+ * the non-empty batch, and `runDecider` returns `DecisionResult<O>`, which is
59
+ * plain `Position` unless `O` admits `Unchanged`. So a decider that cannot say
60
+ * "already done" keeps exactly the result type it always had — an untyped one
61
+ * and one built in a wrapper generic in its success type included — and one
62
+ * that can makes its caller handle `Position | Unchanged`. `runDecider` returns an
63
+ * `Unchanged` without calling `append`, so `append`'s refusal of an empty batch
64
+ * is untouched and never met. `decision.ts` owns why it is a success rather than
65
+ * an error or an empty batch, and why it is recognised by a type id.
66
+ */
67
+ import type { AppendConditionFailed, CompositeState, DcbEvent } from '@kairos-es/core';
68
+ import { DcbEventStore } from '@kairos-es/core';
69
+ import type { Array as Arr } from 'effect';
70
+ import { Effect } from 'effect';
71
+ import { type DecisionOutput, type DecisionResult } from './decision.js';
72
+ import { type RequirementOf } from './decisionModel.js';
73
+ import type { CodecError } from './errors.js';
74
+ import type { SliceProjection } from './projection.js';
75
+ import type { TaglessSliceInLedger } from './readLedger.js';
76
+ import type { Serializer } from './Serializer.js';
77
+ import type { Uuid } from './Uuid.js';
78
+ /**
79
+ * A decision unit: the projections whose folded state a command is decided
80
+ * against, and the `decide` step producing the events to append.
81
+ *
82
+ * `decide` may fail with a domain error `E` (a tagged error is idiomatic, so
83
+ * `@kairos-es/testing`'s `.thenError` can match its `_tag`). It receives the
84
+ * composed decision-model `state` and the `command`, and returns the non-empty
85
+ * batch of new events — effectfully, because each event is produced via
86
+ * `toEvent` (encode -> serialise), which requires `Serializer | Uuid | R`.
87
+ *
88
+ * The projection record is bounded by this package's `SliceProjection` (the
89
+ * schema-backed, state-erased bound for a heterogeneous record); the
90
+ * precise per-key state is recovered by core's shared `CompositeState`. The
91
+ * requirement `R` is the union carried by the record's slices' schemas.
92
+ *
93
+ * `O` is what `decide` may succeed with. It defaults to the non-empty batch, and
94
+ * a decider that can answer "already done" widens it to `DecisionOutput`
95
+ * (`NonEmptyReadonlyArray<DcbEvent> | Unchanged`). It is LAST and DEFAULTED so
96
+ * that every `Decider<P, Command, E, R>` already written means exactly what it
97
+ * meant. Its bound is `DecisionOutput`, which still excludes a possibly-empty
98
+ * array — the widening adds an answer and removes no guarantee.
99
+ */
100
+ export interface Decider<P extends Record<string, SliceProjection>, Command, E = never, R = never, O extends DecisionOutput = Arr.NonEmptyReadonlyArray<DcbEvent>> {
101
+ readonly projections: (command: Command) => P;
102
+ readonly decide: (state: CompositeState<P>, command: Command) => Effect.Effect<O, E, Serializer | Uuid | R>;
103
+ }
104
+ /**
105
+ * Build a `Decider` with all four of its type arguments INFERRED: the slice
106
+ * record `P` from what `projections` returns, the error union `E` and the extra
107
+ * requirement `R` from what `decide` returns. The command type is the one thing
108
+ * a caller still writes, once, as the annotation on the `projections` parameter
109
+ * — `Command` occurs only in parameter positions, so nothing else could supply
110
+ * it, and it is domain information (the command this decision is parametrised
111
+ * by) rather than plumbing.
112
+ *
113
+ * It adds no capability: the interface stays directly inhabitable and this
114
+ * returns exactly the object literal a caller would have written. What it
115
+ * changes is what an author must SPELL. An object literal annotated
116
+ * `Decider<P, Command, E>` has to state the whole slice record — a
117
+ * `ReturnType<typeof someProjection>` per key, a slice's state type being
118
+ * inferred by `projection().on().build()` and so having no name to write — plus
119
+ * the union of every error its decide branches can fail with. Dropping the
120
+ * annotation instead is not open to the author: without it `decide`'s `state`
121
+ * and `command` parameters have no contextual type and are implicitly `any`. So
122
+ * the cost landed hardest on the worked example, where some thirty lines of type
123
+ * plumbing sat between the reader and the three decisions that file exists to
124
+ * teach.
125
+ *
126
+ * `Eff` captures decide's WHOLE return type as one type parameter instead of
127
+ * inferring `E` and `R` from an `Effect<…, E, Serializer | Uuid | R>` shaped
128
+ * target, and that is the part that had to be got right rather than merely
129
+ * written down. A real `decide` returns a UNION of effects — one `Effect.fail`
130
+ * per rule it enforces, plus the produce path — and TypeScript infers a type
131
+ * parameter from a union source by choosing one constituent's candidate, not by
132
+ * unioning them. Against the shaped target `E` therefore came out as whichever
133
+ * branch won, and every other branch was then rejected against it. Inference to
134
+ * a NAKED type variable takes the union whole, which is why `Eff` is the
135
+ * parameter and `Effect.Error` / `Effect.Services` recover the two
136
+ * channels afterwards: those do distribute across a union of effects.
137
+ *
138
+ * The constraint on `Eff` is load-bearing twice over. It is what still refuses a
139
+ * `decide` that could produce an EMPTY batch, the one guarantee the shaped
140
+ * target used to give and the one `append` relies on. It is also what
141
+ * contextually types the produce path's `(event) => [event]` as a one-element
142
+ * TUPLE; unconstrained, that widens to `DcbEvent[]`, which is not a
143
+ * `NonEmptyReadonlyArray` and would fail at the call site.
144
+ *
145
+ * The single `as` is narrow and unavoidable: the declared return is a
146
+ * conditional over an unresolved `Eff`, so while `Eff` is still a type variable
147
+ * the checker cannot relate `(…) => Eff` to `(…) => Effect<…,
148
+ * Effect.Error<Eff>, …>`. The value is the two functions it was handed, so
149
+ * there is nothing for the cast to be wrong about.
150
+ *
151
+ * The success channel is how a decider opts into `Unchanged` without writing a
152
+ * fifth type argument, and it is why this function is declared TWICE. The first
153
+ * declaration bounds `Eff` by the non-empty batch and returns a `Decider` with
154
+ * the DEFAULT `O`; the second bounds it by `DecisionOutput` and returns one whose
155
+ * `O` is `DecisionOutput`. A `decide` with a branch returning
156
+ * `Decision.unchanged(…)` fails the first bound and lands on the second, and one
157
+ * with no such branch keeps the default. Either way `O` is one of the two a
158
+ * caller ever writes, never the inferred success type passed through: inference
159
+ * is more precise than anyone writes — the produce path's one-element tuple, say
160
+ * — and a `Decider<…, readonly [DcbEvent]>` would not be the
161
+ * `Decider<P, Command, E, R>` its caller spells, though it behaves identically.
162
+ * Asking by ASSIGNABILITY rather than by a conditional over `Eff`'s success is
163
+ * what keeps an untyped (`any`) success, and a success that is a type variable
164
+ * bounded by the batch, on the default; `decision.ts` owns that argument, and
165
+ * the one type query the pair cannot answer as before.
166
+ *
167
+ * `R` excludes `Serializer | Uuid` because that is what `R` MEANS on `Decider`:
168
+ * the interface writes decide's requirement as `Serializer | Uuid | R`, so `R`
169
+ * is what the produce side needs BEYOND the codec's own two services. Leaving
170
+ * them in would state the same requirement twice and make an ordinary decider
171
+ * read as though it carried an extra one, though the set `runDecider` ends up
172
+ * asking for is identical either way. The exclusion cannot swallow a caller's
173
+ * own service by accident: a `Context.Service` class's requirement type carries
174
+ * its key as a literal `key` field, so only a service declared under `@kairos-es/codec/Uuid` or
175
+ * `@kairos-es/codec/Serializer` matches — and a service under that key IS that
176
+ * service, context being keyed by the same string at runtime.
177
+ */
178
+ export declare function decider<P extends Record<string, SliceProjection>, Command, Eff extends Effect.Effect<Arr.NonEmptyReadonlyArray<DcbEvent>, unknown, unknown>>(projections: (command: Command) => P, decide: (state: CompositeState<P>, command: Command) => Eff): Decider<P, Command, Effect.Error<Eff>, Exclude<Effect.Services<Eff>, Serializer | Uuid>>;
179
+ export declare function decider<P extends Record<string, SliceProjection>, Command, Eff extends Effect.Effect<DecisionOutput, unknown, unknown>>(projections: (command: Command) => P, decide: (state: CompositeState<P>, command: Command) => Eff): Decider<P, Command, Effect.Error<Eff>, Exclude<Effect.Services<Eff>, Serializer | Uuid>, DecisionOutput>;
180
+ /**
181
+ * Run the full DCB command cycle for a decider against the ambient
182
+ * `DcbEventStore`: build the decision model (real read + decode + fold), decide,
183
+ * and append under the read's append condition. Returns the last new position —
184
+ * or, when `decide` answered `Unchanged`, that `Unchanged`, having appended
185
+ * nothing. The result type is `DecisionResult<O>`, so it is plain `Position` for
186
+ * every decider that cannot answer `Unchanged`, including one whose `O` is still
187
+ * a type variable bounded by the batch. ONE signature, deliberately:
188
+ * `decision.ts` says why that alias, and not an overload, is what carries it.
189
+ *
190
+ * The requirement is `DcbEventStore | Serializer | Uuid | R |
191
+ * RequirementOf<P>`: `Serializer` enters through both the decode
192
+ * (`buildDecisionModel`) and produce (`toEvent`) sides, `Uuid` through produce,
193
+ * the slices' `RequirementOf<P>` through decode, and `R` through produce. (For a
194
+ * def whose `Schema` carries a requirement, `RequirementOf<P>` and `R` are the
195
+ * same tag.) Any `decide` failure, a decode `CodecError`, an
196
+ * `AppendConditionFailed`, or the read's own `TaglessSliceInLedger` propagates on
197
+ * the error channel unchanged.
198
+ *
199
+ * ⚠ INSIDE a bracket this function is REFUSED, as a defect, at the store's shared
200
+ * append decorator, and `decideOnly` is what a body reaches for instead.
201
+ * `index.ts` states that pair, why each refuses exactly where the other is the
202
+ * answer, and why neither can be expressed over the other. Read it before
203
+ * changing either signature; this file does not restate the argument.
204
+ */
205
+ export declare const runDecider: <P extends Record<string, SliceProjection>, Command, E, R, O extends DecisionOutput = Arr.NonEmptyReadonlyArray<DcbEvent>>(decider: Decider<P, Command, E, R, O>, command: Command) => Effect.Effect<DecisionResult<O>, E | CodecError | AppendConditionFailed | TaglessSliceInLedger, DcbEventStore | Serializer | Uuid | R | RequirementOf<P>>;
206
+ //# sourceMappingURL=decider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decider.d.ts","sourceRoot":"","sources":["../../src/decider.ts"],"names":[],"mappings":"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"}