@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.
- package/README.md +2 -2
- package/dist/cjs/MetadataSource.js +1 -1
- package/dist/cjs/MetadataSource.js.map +1 -1
- package/dist/cjs/Serializer.js +3 -3
- package/dist/cjs/Serializer.js.map +1 -1
- package/dist/cjs/Uuid.js +6 -3
- package/dist/cjs/Uuid.js.map +1 -1
- package/dist/cjs/decider.js +1 -1
- package/dist/cjs/decisionModel.js +1 -1
- package/dist/cjs/decisionModel.js.map +1 -1
- package/dist/cjs/decode.js +5 -5
- package/dist/cjs/decode.js.map +1 -1
- package/dist/cjs/deserialiseThenDecode.js +1 -1
- package/dist/cjs/deserialiseThenDecode.js.map +1 -1
- package/dist/cjs/errors.js +6 -4
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/event.js.map +1 -1
- package/dist/cjs/precondition.js +2 -2
- package/dist/cjs/precondition.js.map +1 -1
- package/dist/cjs/projection.js +9 -10
- package/dist/cjs/projection.js.map +1 -1
- package/dist/cjs/readLedger.js +3 -3
- package/dist/cjs/readLedger.js.map +1 -1
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/toEvent.js +4 -4
- package/dist/cjs/toEvent.js.map +1 -1
- package/dist/dts-cjs/MetadataSource.d.ts +8 -0
- package/dist/{dts → dts-cjs}/MetadataSource.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/Serializer.d.ts +3 -3
- package/dist/{dts → dts-cjs}/Serializer.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/Uuid.d.ts +6 -3
- package/dist/{dts → dts-cjs}/Uuid.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/decider.d.ts +7 -7
- package/dist/{dts → dts-cjs}/decider.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/decision.d.ts +2 -2
- package/dist/{dts → dts-cjs}/decode.d.ts +3 -3
- package/dist/{dts → dts-cjs}/decode.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/deserialiseThenDecode.d.ts +3 -3
- package/dist/{dts → dts-cjs}/deserialiseThenDecode.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/errors.d.ts +4 -3
- package/dist/dts-cjs/errors.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/event.d.ts +18 -8
- package/dist/dts-cjs/event.d.ts.map +1 -0
- package/dist/dts-cjs/package.json +3 -0
- package/dist/{dts → dts-cjs}/precondition.d.ts +2 -2
- package/dist/{dts → dts-cjs}/projection.d.ts +2 -2
- package/dist/dts-cjs/projection.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/readLedger.d.ts +4 -4
- package/dist/{dts → dts-cjs}/readLedger.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/toEvent.d.ts +2 -2
- package/dist/dts-esm/MetadataSource.d.ts +8 -0
- package/dist/dts-esm/MetadataSource.d.ts.map +1 -0
- package/dist/dts-esm/Serializer.d.ts +27 -0
- package/dist/dts-esm/Serializer.d.ts.map +1 -0
- package/dist/dts-esm/Uuid.d.ts +22 -0
- package/dist/dts-esm/Uuid.d.ts.map +1 -0
- package/dist/dts-esm/decider.d.ts +206 -0
- package/dist/dts-esm/decider.d.ts.map +1 -0
- package/dist/dts-esm/decision.d.ts +161 -0
- package/dist/dts-esm/decision.d.ts.map +1 -0
- package/dist/dts-esm/decisionModel.d.ts +149 -0
- package/dist/dts-esm/decisionModel.d.ts.map +1 -0
- package/dist/dts-esm/decode.d.ts +92 -0
- package/dist/dts-esm/decode.d.ts.map +1 -0
- package/dist/dts-esm/deserialiseThenDecode.d.ts +62 -0
- package/dist/dts-esm/deserialiseThenDecode.d.ts.map +1 -0
- package/dist/dts-esm/errors.d.ts +80 -0
- package/dist/dts-esm/errors.d.ts.map +1 -0
- package/dist/dts-esm/event.d.ts +81 -0
- package/dist/dts-esm/event.d.ts.map +1 -0
- package/dist/dts-esm/index.d.ts +134 -0
- package/dist/dts-esm/index.d.ts.map +1 -0
- package/dist/dts-esm/package.json +3 -0
- package/dist/dts-esm/precondition.d.ts +244 -0
- package/dist/dts-esm/precondition.d.ts.map +1 -0
- package/dist/dts-esm/projection.d.ts +56 -0
- package/dist/dts-esm/projection.d.ts.map +1 -0
- package/dist/dts-esm/readLedger.d.ts +263 -0
- package/dist/dts-esm/readLedger.d.ts.map +1 -0
- package/dist/dts-esm/registry.d.ts +46 -0
- package/dist/dts-esm/registry.d.ts.map +1 -0
- package/dist/dts-esm/toEvent.d.ts +45 -0
- package/dist/dts-esm/toEvent.d.ts.map +1 -0
- package/dist/esm/MetadataSource.js +1 -1
- package/dist/esm/MetadataSource.js.map +1 -1
- package/dist/esm/Serializer.js +3 -3
- package/dist/esm/Serializer.js.map +1 -1
- package/dist/esm/Uuid.js +6 -3
- package/dist/esm/Uuid.js.map +1 -1
- package/dist/esm/decider.js +1 -1
- package/dist/esm/decisionModel.js +1 -1
- package/dist/esm/decisionModel.js.map +1 -1
- package/dist/esm/decode.js +5 -5
- package/dist/esm/decode.js.map +1 -1
- package/dist/esm/deserialiseThenDecode.js +1 -1
- package/dist/esm/deserialiseThenDecode.js.map +1 -1
- package/dist/esm/errors.js +6 -4
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/event.js.map +1 -1
- package/dist/esm/precondition.js +2 -2
- package/dist/esm/precondition.js.map +1 -1
- package/dist/esm/projection.js +9 -10
- package/dist/esm/projection.js.map +1 -1
- package/dist/esm/readLedger.js +3 -3
- package/dist/esm/readLedger.js.map +1 -1
- package/dist/esm/registry.js.map +1 -1
- package/dist/esm/toEvent.js +4 -4
- package/dist/esm/toEvent.js.map +1 -1
- package/package.json +12 -7
- package/src/MetadataSource.ts +2 -2
- package/src/Serializer.ts +4 -4
- package/src/Uuid.ts +7 -4
- package/src/decider.ts +9 -9
- package/src/decision.ts +1 -1
- package/src/decisionModel.ts +1 -1
- package/src/decode.ts +12 -18
- package/src/deserialiseThenDecode.ts +5 -5
- package/src/errors.ts +6 -4
- package/src/event.ts +19 -9
- package/src/precondition.ts +3 -3
- package/src/projection.ts +15 -20
- package/src/readLedger.ts +7 -7
- package/src/registry.ts +1 -1
- package/src/toEvent.ts +4 -4
- package/dist/dts/MetadataSource.d.ts +0 -8
- package/dist/dts/errors.d.ts.map +0 -1
- package/dist/dts/event.d.ts.map +0 -1
- package/dist/dts/projection.d.ts.map +0 -1
- /package/dist/{dts → dts-cjs}/decision.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/decisionModel.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/decisionModel.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/index.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/index.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/precondition.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/registry.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/registry.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/toEvent.d.ts.map +0 -0
package/dist/esm/projection.js
CHANGED
|
@@ -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,
|
|
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.
|
|
@@ -50,18 +50,17 @@ export const projection = initialState => {
|
|
|
50
50
|
// The entry type is annotated `R | R2` rather than inferred, and that
|
|
51
51
|
// annotation is what carries the requirement forward — `build` reads `R`
|
|
52
52
|
// straight off this map, so `RequirementOf` ultimately reads it from here.
|
|
53
|
-
// Widening the copied `R` entries into it costs nothing: `Schema`
|
|
54
|
-
// declared `<
|
|
53
|
+
// Widening the copied `R` entries into it costs nothing: `Schema.Decoder`
|
|
54
|
+
// is declared `<out T, out RD>` upstream, hence covariant in its
|
|
55
55
|
// requirement.
|
|
56
56
|
const nextSchemas = new Map(schemas);
|
|
57
|
-
// Erasing `A`/`I`
|
|
58
|
-
//
|
|
59
|
-
// `Schema<unknown, unknown, R2>` are unrelated in either direction. It is
|
|
57
|
+
// Erasing `A`/`I` needs no cast: a `Schema.Codec` is covariant in both, so
|
|
58
|
+
// `Codec<A, I, R2, R2>` is already a `Decoder<unknown, R2>`. The erasure is
|
|
60
59
|
// sound because the payload is only ever read back through `evolve`, which
|
|
61
|
-
// re-narrows by event type via the matching `fold`.
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
60
|
+
// re-narrows by event type via the matching `fold`. What survives it is
|
|
61
|
+
// `R2`, the def's DECODING requirement — an `Encrypted` field's `CipherKey`
|
|
62
|
+
// is not nothing — and that is the half a slice ever spends, since a slice
|
|
63
|
+
// decodes and never encodes.
|
|
65
64
|
nextSchemas.set(def.type, def.schema);
|
|
66
65
|
const nextFolds = new Map(folds);
|
|
67
66
|
// Contravariance in the payload parameter, so this one is a cast too: the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projection.js","names":["EventType","projection","initialState","make","schemas","folds","on","def","fold","has","type","Error","nextSchemas","Map","set","schema","nextFolds","build","options","types","keys","map","t","query","items","tags","evolve","state","decoded","get","sequenced","event","undefined","payload"],"sources":["../../src/projection.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;AAmBA,SAGEA,SAAS,QAGJ,iBAAiB;AAoCxB;;;;AAIA,OAAO,MAAMC,UAAU,GAAOC,YAAe,IAAiC;EAC5E;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,IAAI,GAAGA,CACXC,
|
|
1
|
+
{"version":3,"file":"projection.js","names":["EventType","projection","initialState","make","schemas","folds","on","def","fold","has","type","Error","nextSchemas","Map","set","schema","nextFolds","build","options","types","keys","map","t","query","items","tags","evolve","state","decoded","get","sequenced","event","undefined","payload"],"sources":["../../src/projection.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;AAmBA,SAGEA,SAAS,QAGJ,iBAAiB;AAoCxB;;;;AAIA,OAAO,MAAMC,UAAU,GAAOC,YAAe,IAAiC;EAC5E;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,IAAI,GAAGA,CACXC,OAAwD,EACxDC,KAA6D,MAChC;IAC7BC,EAAE,EAAEA,CACFC,GAAuB,EACvBC,IAAiC,KACD;MAChC;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,IAAIJ,OAAO,CAACK,GAAG,CAACF,GAAG,CAACG,IAAI,CAAC,EAAE;QACzB,MAAM,IAAIC,KAAK,CACb,yBAAyBJ,GAAG,CAACG,IAAI,mCAAmC,GAClE,gEAAgE,GAChE,gCAAgC,CACnC;MACH;MACA;MACA;MACA;MACA;MACA;MACA;MACA,MAAME,WAAW,GAAG,IAAIC,GAAG,CACzBT,OAAO,CACR;MACD;MACA;MACA;MACA;MACA;MACA;MACA;MACAQ,WAAW,CAACE,GAAG,CAACP,GAAG,CAACG,IAAI,EAAEH,GAAG,CAACQ,MAAM,CAAC;MACrC,MAAMC,SAAS,GAAG,IAAIH,GAAG,CAACR,KAAK,CAAC;MAChC;MACA;MACA;MACAW,SAAS,CAACF,GAAG,CAACP,GAAG,CAACG,IAAI,EAAEF,IAAyC,CAAC;MAClE,OAAOL,IAAI,CAASS,WAAW,EAAEI,SAAS,CAAC;IAC7C,CAAC;IACDC,KAAK,EAAGC,OAAO,IAAI;MACjB;MACA;MACA,MAAMC,KAAK,GAAG,CAAC,GAAGf,OAAO,CAACgB,IAAI,EAAE,CAAC,CAACC,GAAG,CAAEC,CAAC,IAAKtB,SAAS,CAACG,IAAI,CAACmB,CAAC,CAAC,CAAC;MAC/D,MAAMC,KAAK,GAAU;QACnBC,KAAK,EAAE,CAAC;UAAEL,KAAK;UAAEM,IAAI,EAAEP,OAAO,EAAEO,IAAI,IAAI;QAAE,CAAE;OAC7C;MACD,OAAO;QACLvB,YAAY;QACZqB,KAAK;QACL;QACA;QACA;QACA;QACA;QACA;QACAnB,OAAO,EAAE,IAAIS,GAAG,CAACT,OAAO,CAAC;QACzB;QACA;QACA;QACA;QACA;QACA;QACAsB,MAAM,EAAEA,CAACC,KAAK,EAAEC,OAAqB,KAAI;UACvC,MAAMpB,IAAI,GAAGH,KAAK,CAACwB,GAAG,CAACD,OAAO,CAACE,SAAS,CAACC,KAAK,CAACrB,IAAI,CAAC;UACpD,OAAOF,IAAI,KAAKwB,SAAS,GAAGL,KAAK,GAAGnB,IAAI,CAACmB,KAAU,EAAEC,OAAO,CAACK,OAAO,CAAC;QACvE;OACD;IACH;GACD,CAAC;EACF;EACA;EACA,OAAO9B,IAAI,CAAQ,IAAIU,GAAG,EAAE,EAAE,IAAIA,GAAG,EAAE,CAAC;AAC1C,CAAC","ignoreList":[]}
|
package/dist/esm/readLedger.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Context, Data, Effect, Layer, Option, Ref } from 'effect';
|
|
|
8
8
|
* requirement channel nothing is exactly what makes this change additive.
|
|
9
9
|
* `modelAtHead` is that path and is why the rule exists.
|
|
10
10
|
*
|
|
11
|
-
* A BRACKET-ONLY function is the opposite case and yields the
|
|
11
|
+
* A BRACKET-ONLY function is the opposite case and yields the service deliberately.
|
|
12
12
|
* `decideOnly` does, and naming the requirement is what turns *"call me inside a
|
|
13
13
|
* bracket"* from a runtime defect into a compile error — presence being the one
|
|
14
14
|
* direction the type system can decide here. So the test is what the function
|
|
@@ -18,7 +18,7 @@ import { Context, Data, Effect, Layer, Option, Ref } from 'effect';
|
|
|
18
18
|
* Recording is two-phase, and `record`'s own doc below owns why and what shape the
|
|
19
19
|
* second phase takes.
|
|
20
20
|
*/
|
|
21
|
-
export class ReadLedger extends /*#__PURE__*/Context.
|
|
21
|
+
export class ReadLedger extends /*#__PURE__*/Context.Service()('@kairos-es/codec/ReadLedger') {}
|
|
22
22
|
/**
|
|
23
23
|
* Raised when a bracket closes having recorded no read at all.
|
|
24
24
|
*
|
|
@@ -223,5 +223,5 @@ export const assertServableAddition = projections => withLedger(undefined, ledge
|
|
|
223
223
|
* current behaviour is the hazard derives from every hop the bracket walked rather
|
|
224
224
|
* than from its own single read.
|
|
225
225
|
*/
|
|
226
|
-
export const ambientLayeredCondition = /*#__PURE__*/withLedger(/*#__PURE__*/Option.none(), ledger => Effect.map(ledger.hops, hops => Option.
|
|
226
|
+
export const ambientLayeredCondition = /*#__PURE__*/withLedger(/*#__PURE__*/Option.none(), ledger => Effect.map(ledger.hops, hops => Option.fromNullishOr(deriveLayeredCondition(hops))));
|
|
227
227
|
//# sourceMappingURL=readLedger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readLedger.js","names":["composeProjections","ORIGIN","servableQueryFault","unionQueries","unknownQueryKeyFault","Context","Data","Effect","Layer","Option","Ref","ReadLedger","
|
|
1
|
+
{"version":3,"file":"readLedger.js","names":["composeProjections","ORIGIN","servableQueryFault","unionQueries","unknownQueryKeyFault","Context","Data","Effect","Layer","Option","Ref","ReadLedger","Service","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","fromNullishOr"],"sources":["../../src/readLedger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/dist/esm/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":["Effect","deserialiseThenDecode","UnknownEventType","Serializer","makeRegistry","defs","map","Map","def","has","type","Error","set","schema","decode","event","gen","get","undefined","fail","serializer","payload","data"],"sources":["../../src/registry.ts"],"sourcesContent":[null],"mappings":"AA2BA,SAASA,MAAM,QAAqB,QAAQ;AAC5C,SAASC,qBAAqB,QAAQ,4BAAyB;AAC/D,SAA0BC,gBAAgB,QAAQ,aAAU;AAE5D,SAASC,UAAU,QAAQ,iBAAc;AAqBzC,OAAO,MAAMC,YAAY,GACvBC,IAAU,IAC2B;EACrC,MAAMC,GAAG,GAAG,IAAIC,GAAG,
|
|
1
|
+
{"version":3,"file":"registry.js","names":["Effect","deserialiseThenDecode","UnknownEventType","Serializer","makeRegistry","defs","map","Map","def","has","type","Error","set","schema","decode","event","gen","get","undefined","fail","serializer","payload","data"],"sources":["../../src/registry.ts"],"sourcesContent":[null],"mappings":"AA2BA,SAASA,MAAM,QAAqB,QAAQ;AAC5C,SAASC,qBAAqB,QAAQ,4BAAyB;AAC/D,SAA0BC,gBAAgB,QAAQ,aAAU;AAE5D,SAASC,UAAU,QAAQ,iBAAc;AAqBzC,OAAO,MAAMC,YAAY,GACvBC,IAAU,IAC2B;EACrC,MAAMC,GAAG,GAAG,IAAIC,GAAG,EAA4C;EAC/D,KAAK,MAAMC,GAAG,IAAIH,IAAI,EAAE;IACtB,IAAIC,GAAG,CAACG,GAAG,CAACD,GAAG,CAACE,IAAI,CAAC,EAAE;MACrB,MAAM,IAAIC,KAAK,CAAC,yBAAyBH,GAAG,CAACE,IAAI,eAAe,CAAC;IACnE;IACAJ,GAAG,CAACM,GAAG,CAACJ,GAAG,CAACE,IAAI,EAAEF,GAAG,CAACK,MAAM,CAAC;EAC/B;EACA,OAAO;IACLC,MAAM,EAAGC,KAAK,IACZf,MAAM,CAACgB,GAAG,CAAC,aAAS;MAClB,MAAMH,MAAM,GAAGP,GAAG,CAACW,GAAG,CAACF,KAAK,CAACL,IAAI,CAAC;MAClC,IAAIG,MAAM,KAAKK,SAAS,EAAE;QACxB,OAAO,OAAOlB,MAAM,CAACmB,IAAI,CAAC,IAAIjB,gBAAgB,CAAC;UAAEQ,IAAI,EAAEK,KAAK,CAACL;QAAI,CAAE,CAAC,CAAC;MACvE;MACA,MAAMU,UAAU,GAAG,OAAOjB,UAAU;MACpC,MAAMkB,OAAO,GAAG,OAAOpB,qBAAqB,CAC1CmB,UAAU,EACVP,MAAM,EACNE,KAAK,CAACO,IAAI,CACX;MACD,OAAO;QAAEZ,IAAI,EAAEK,KAAK,CAACL,IAAI;QAAEW;MAAO,CAAE;MACpC;MACA;MACA;MACA;IACF,CAAC;GAKJ;AACH,CAAC","ignoreList":[]}
|
package/dist/esm/toEvent.js
CHANGED
|
@@ -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.
|
|
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
|
|
@@ -60,7 +60,7 @@ export const toEvent = (def, payload, options) => Effect.gen(function* () {
|
|
|
60
60
|
// store shares anything with its caller; that is each store's guarantee.)
|
|
61
61
|
const given = options?.metadata === undefined ? Option.getOrElse(yield* Effect.serviceOption(MetadataSource), () => ({})) : options.metadata;
|
|
62
62
|
const metadata = {
|
|
63
|
-
...(yield* Schema.
|
|
63
|
+
...(yield* Schema.decodeUnknownEffect(Metadata)(given).pipe(Effect.mapError(cause => new CodecError({
|
|
64
64
|
reason: 'metadata',
|
|
65
65
|
cause
|
|
66
66
|
}))))
|
|
@@ -78,7 +78,7 @@ export const toEvent = (def, payload, options) => Effect.gen(function* () {
|
|
|
78
78
|
})
|
|
79
79
|
});
|
|
80
80
|
const serializer = yield* Serializer;
|
|
81
|
-
const encoded = yield* Schema.
|
|
81
|
+
const encoded = yield* Schema.encodeEffect(def.schema)(payload).pipe(Effect.mapError(cause => new CodecError({
|
|
82
82
|
reason: 'encode',
|
|
83
83
|
cause
|
|
84
84
|
})));
|
package/dist/esm/toEvent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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","
|
|
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","decodeUnknownEffect","pipe","mapError","cause","reason","tags","try","tagsFor","catch","serializer","encoded","encodeEffect","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,mBAAmB,CAACnB,QAAQ,CAAC,CAACc,KAAK,CAAC,CAACM,IAAI,CACzDlB,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,YAAY,CAACpB,GAAG,CAACqB,MAAM,CAAC,CAACpB,OAAO,CAAC,CAACS,IAAI,CAClElB,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.
|
|
3
|
+
"version": "1.0.0-alpha.6",
|
|
4
4
|
"description": "Schema-first codec with encryption seam for kairos-es",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"repository": {
|
|
@@ -11,17 +11,22 @@
|
|
|
11
11
|
"sideEffects": [],
|
|
12
12
|
"homepage": "https://github.com/neverbland/kairos-es",
|
|
13
13
|
"peerDependencies": {
|
|
14
|
-
"effect": "^
|
|
15
|
-
"@kairos-es/core": "^1.0.0-alpha.
|
|
14
|
+
"effect": "^4.0.5",
|
|
15
|
+
"@kairos-es/core": "^1.0.0-alpha.6"
|
|
16
16
|
},
|
|
17
17
|
"main": "./dist/cjs/index.js",
|
|
18
18
|
"module": "./dist/esm/index.js",
|
|
19
|
-
"types": "./dist/dts/index.d.ts",
|
|
19
|
+
"types": "./dist/dts-cjs/index.d.ts",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/dts-esm/index.d.ts",
|
|
24
|
+
"default": "./dist/esm/index.js"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/dts-cjs/index.d.ts",
|
|
28
|
+
"default": "./dist/cjs/index.js"
|
|
29
|
+
}
|
|
25
30
|
},
|
|
26
31
|
"./package.json": "./package.json"
|
|
27
32
|
},
|
package/src/MetadataSource.ts
CHANGED
|
@@ -38,6 +38,6 @@
|
|
|
38
38
|
import type { Metadata } from '@kairos-es/core'
|
|
39
39
|
import { Context } from 'effect'
|
|
40
40
|
|
|
41
|
-
export class MetadataSource extends Context.
|
|
41
|
+
export class MetadataSource extends Context.Service<MetadataSource, Metadata>()(
|
|
42
42
|
'@kairos-es/codec/MetadataSource',
|
|
43
|
-
)
|
|
43
|
+
) {}
|
package/src/Serializer.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The pluggable serialiser: the `Uint8Array` <-> value boundary applied
|
|
3
|
-
* *outside* `Schema`. Encode is `Schema.
|
|
4
|
-
* `deserialise` then `Schema.
|
|
3
|
+
* *outside* `Schema`. Encode is `Schema.encodeEffect` then `serialise`; decode is
|
|
4
|
+
* `deserialise` then `Schema.decodeUnknownEffect`. Both codec paths read the same
|
|
5
5
|
* `Serializer` from context, so encode and decode cannot mismatch; swapping
|
|
6
6
|
* JSON for msgpack is a different layer with no schema or call-site changes.
|
|
7
7
|
*
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { Context, Layer } from 'effect'
|
|
14
14
|
|
|
15
|
-
export class Serializer extends Context.
|
|
15
|
+
export class Serializer extends Context.Service<
|
|
16
16
|
Serializer,
|
|
17
17
|
{
|
|
18
18
|
readonly serialise: (v: unknown) => Uint8Array
|
|
19
19
|
readonly deserialise: (b: Uint8Array) => unknown
|
|
20
20
|
}
|
|
21
|
-
>() {}
|
|
21
|
+
>()('@kairos-es/codec/Serializer') {}
|
|
22
22
|
|
|
23
23
|
const encoder = new TextEncoder()
|
|
24
24
|
const decoder = new TextDecoder()
|
package/src/Uuid.ts
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
import { makeSequentialUuid } from '@kairos-es/core/testing'
|
|
13
13
|
import { Context, Effect, Layer } from 'effect'
|
|
14
14
|
|
|
15
|
-
export class Uuid extends Context.
|
|
15
|
+
export class Uuid extends Context.Service<
|
|
16
16
|
Uuid,
|
|
17
17
|
{ readonly generate: Effect.Effect<string> }
|
|
18
|
-
>() {}
|
|
18
|
+
>()('@kairos-es/codec/Uuid') {}
|
|
19
19
|
|
|
20
20
|
/** Live uuid generation via WebCrypto (no `node:crypto`). */
|
|
21
21
|
export const UuidLive: Layer.Layer<Uuid> = Layer.succeed(Uuid, {
|
|
@@ -25,9 +25,12 @@ export const UuidLive: Layer.Layer<Uuid> = Layer.succeed(Uuid, {
|
|
|
25
25
|
/**
|
|
26
26
|
* A deterministic uuid layer for suites, wrapping core's shared
|
|
27
27
|
* `makeSequentialUuid` (the single source of truth for the counter scheme).
|
|
28
|
-
* Each layer
|
|
28
|
+
* Each BUILD of the layer makes a fresh generator, so it owns its own counter and
|
|
29
29
|
* yields a stable v4-shaped sequence `00000000-0000-4000-8000-<12 hex>` starting
|
|
30
|
-
* at `...000000000000`.
|
|
30
|
+
* at `...000000000000`. A build is not one per `Effect.provide`: Effect memoises
|
|
31
|
+
* a layer across the provisions that share a memo map, so a nested second
|
|
32
|
+
* provision of this layer continues the counter rather than restarting it, and
|
|
33
|
+
* `Layer.fresh` is the way to ask for a restart. Generation is wrapped in `Effect.sync` because the
|
|
31
34
|
* generator advances its counter (a side effect on each call).
|
|
32
35
|
*/
|
|
33
36
|
export const UuidTest: Layer.Layer<Uuid> = Layer.sync(Uuid, () => {
|
package/src/decider.ts
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* append condition the read produced. That IS the optimistic-concurrency
|
|
40
40
|
* contract, in production and in a scenario alike — which is also why the
|
|
41
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.
|
|
42
|
+
* rather than a mock. It is a free function rather than a `Context.Service`,
|
|
43
43
|
* so it is still not the "production command-runner service method" a retrying
|
|
44
44
|
* `Layer` would need (ADR-0008): the correct retry remains
|
|
45
45
|
* `retryOnConflict(runDecider(...))`, wrapping the whole cycle so a fresh read
|
|
@@ -152,7 +152,7 @@ export interface Decider<
|
|
|
152
152
|
* unioning them. Against the shaped target `E` therefore came out as whichever
|
|
153
153
|
* branch won, and every other branch was then rejected against it. Inference to
|
|
154
154
|
* a NAKED type variable takes the union whole, which is why `Eff` is the
|
|
155
|
-
* parameter and `Effect.
|
|
155
|
+
* parameter and `Effect.Error` / `Effect.Services` recover the two
|
|
156
156
|
* channels afterwards: those do distribute across a union of effects.
|
|
157
157
|
*
|
|
158
158
|
* The constraint on `Eff` is load-bearing twice over. It is what still refuses a
|
|
@@ -190,9 +190,9 @@ export interface Decider<
|
|
|
190
190
|
* them in would state the same requirement twice and make an ordinary decider
|
|
191
191
|
* read as though it carried an extra one, though the set `runDecider` ends up
|
|
192
192
|
* asking for is identical either way. The exclusion cannot swallow a caller's
|
|
193
|
-
* own service by accident: a `Context.
|
|
194
|
-
* a literal `
|
|
195
|
-
* `@kairos-es/codec/Serializer` matches — and a
|
|
193
|
+
* own service by accident: a `Context.Service` class's requirement type carries
|
|
194
|
+
* its key as a literal `key` field, so only a service declared under `@kairos-es/codec/Uuid` or
|
|
195
|
+
* `@kairos-es/codec/Serializer` matches — and a service under that key IS that
|
|
196
196
|
* service, context being keyed by the same string at runtime.
|
|
197
197
|
*/
|
|
198
198
|
export function decider<
|
|
@@ -209,8 +209,8 @@ export function decider<
|
|
|
209
209
|
): Decider<
|
|
210
210
|
P,
|
|
211
211
|
Command,
|
|
212
|
-
Effect.
|
|
213
|
-
Exclude<Effect.
|
|
212
|
+
Effect.Error<Eff>,
|
|
213
|
+
Exclude<Effect.Services<Eff>, Serializer | Uuid>
|
|
214
214
|
>
|
|
215
215
|
export function decider<
|
|
216
216
|
P extends Record<string, SliceProjection>,
|
|
@@ -222,8 +222,8 @@ export function decider<
|
|
|
222
222
|
): Decider<
|
|
223
223
|
P,
|
|
224
224
|
Command,
|
|
225
|
-
Effect.
|
|
226
|
-
Exclude<Effect.
|
|
225
|
+
Effect.Error<Eff>,
|
|
226
|
+
Exclude<Effect.Services<Eff>, Serializer | Uuid>,
|
|
227
227
|
DecisionOutput
|
|
228
228
|
>
|
|
229
229
|
export function decider<P extends Record<string, SliceProjection>, Command>(
|
package/src/decision.ts
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
* channels; an overloaded step would lose both to `unknown`.
|
|
67
67
|
*
|
|
68
68
|
* `decider(…)` cannot be served by a conditional at all. Its `O` is derived from
|
|
69
|
-
* the SUCCESS of an effect type variable, and `Effect.
|
|
69
|
+
* the SUCCESS of an effect type variable, and `Effect.Success` of a type
|
|
70
70
|
* variable is itself deferred, so a wrapper that copies `decider`'s own generics
|
|
71
71
|
* would get a `Decider` whose `O` nothing can resolve, and a runner result that
|
|
72
72
|
* is not `Position`. So `decider` is declared TWICE, which asks the question by
|
package/src/decisionModel.ts
CHANGED
|
@@ -152,7 +152,7 @@ export const modelAtHead = <T extends Record<string, SliceProjection>>(
|
|
|
152
152
|
|
|
153
153
|
const state = (yield* Stream.runFold(
|
|
154
154
|
decoded,
|
|
155
|
-
composite.initialState,
|
|
155
|
+
() => composite.initialState,
|
|
156
156
|
(acc, event) => composite.evolve(acc, event),
|
|
157
157
|
)) as CompositeState<T>
|
|
158
158
|
|
package/src/decode.ts
CHANGED
|
@@ -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
|
|
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
|
|
26
|
-
*
|
|
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)
|
|
@@ -84,9 +84,9 @@ import { Serializer } from './Serializer'
|
|
|
84
84
|
* last, an ordering the record does not express and its author never chose.
|
|
85
85
|
* Every event of that type is then decoded against the wrong def for one of the
|
|
86
86
|
* slices, and where the two shapes overlap that failure is SILENT rather than a
|
|
87
|
-
* `CodecError`: `Schema.
|
|
88
|
-
* (`effect@
|
|
89
|
-
* `'error'`
|
|
87
|
+
* `CodecError`: `Schema.decodeUnknownEffect` defaults `onExcessProperty` to
|
|
88
|
+
* `'ignore'` (`effect@4`'s `SchemaAST.ts` runs its excess-key loop only under
|
|
89
|
+
* `'error'`), so a field the other def declared is dropped, not
|
|
90
90
|
* reported, and the fold downstream is handed a payload quietly missing it.
|
|
91
91
|
*
|
|
92
92
|
* **Why a throw, and why here rather than at the read side's wiring gate.**
|
|
@@ -100,8 +100,8 @@ import { Serializer } from './Serializer'
|
|
|
100
100
|
* the write path merges before its first `store.read`, and the read side
|
|
101
101
|
* merges after that gate and before it forks the pipeline — and inside
|
|
102
102
|
* their `Effect.gen`s a throw becomes a DEFECT rather than an escaping exception
|
|
103
|
-
* (`effect@
|
|
104
|
-
* `
|
|
103
|
+
* (`effect@4`'s fibre run loop catches a thrown value and converts it with
|
|
104
|
+
* `exitDie`), which is the classification a mis-wiring already has on both
|
|
105
105
|
* sides of the library.
|
|
106
106
|
*
|
|
107
107
|
* The sentence names BOTH slices. The two halves of this mistake are in
|
|
@@ -120,11 +120,8 @@ import { Serializer } from './Serializer'
|
|
|
120
120
|
*/
|
|
121
121
|
const mergeSliceSchemas = <T extends Record<string, SliceProjection>>(
|
|
122
122
|
projections: T,
|
|
123
|
-
): ReadonlyMap<string, Schema.
|
|
124
|
-
const schemas = new Map<
|
|
125
|
-
string,
|
|
126
|
-
Schema.Schema<unknown, unknown, RequirementOf<T>>
|
|
127
|
-
>()
|
|
123
|
+
): ReadonlyMap<string, Schema.Decoder<unknown, RequirementOf<T>>> => {
|
|
124
|
+
const schemas = new Map<string, Schema.Decoder<unknown, RequirementOf<T>>>()
|
|
128
125
|
// Which slice contributed each entry, kept in lockstep with `schemas` purely
|
|
129
126
|
// so the refusal can name both sides of a collision. Its presence is also what
|
|
130
127
|
// the check below reads, rather than a second `schemas.has`, so the narrowing
|
|
@@ -142,10 +139,7 @@ const mergeSliceSchemas = <T extends Record<string, SliceProjection>>(
|
|
|
142
139
|
'only by sharing one EventDef.',
|
|
143
140
|
)
|
|
144
141
|
}
|
|
145
|
-
schemas.set(
|
|
146
|
-
type,
|
|
147
|
-
schema as Schema.Schema<unknown, unknown, RequirementOf<T>>,
|
|
148
|
-
)
|
|
142
|
+
schemas.set(type, schema as Schema.Decoder<unknown, RequirementOf<T>>)
|
|
149
143
|
contributedBy.set(type, key)
|
|
150
144
|
}
|
|
151
145
|
}
|
|
@@ -181,7 +175,7 @@ const mergeSliceSchemas = <T extends Record<string, SliceProjection>>(
|
|
|
181
175
|
* "build the lookup once, reuse the stage" property explicit in the types.
|
|
182
176
|
*/
|
|
183
177
|
const decodeEvents =
|
|
184
|
-
<RS>(schemas: ReadonlyMap<string, Schema.
|
|
178
|
+
<RS>(schemas: ReadonlyMap<string, Schema.Decoder<unknown, RS>>) =>
|
|
185
179
|
<E, R>(
|
|
186
180
|
events: Stream.Stream<SequencedEvent, E, R>,
|
|
187
181
|
): Stream.Stream<DecodedEvent, E | CodecError, R | RS | Serializer> =>
|
|
@@ -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.
|
|
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.
|
|
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
|
|
@@ -60,8 +60,8 @@ import { CodecError } from './errors'
|
|
|
60
60
|
import type { Serializer } from './Serializer'
|
|
61
61
|
|
|
62
62
|
export const deserialiseThenDecode = <R>(
|
|
63
|
-
serializer: Context.
|
|
64
|
-
schema: Schema.
|
|
63
|
+
serializer: Context.Service.Shape<typeof Serializer>,
|
|
64
|
+
schema: Schema.Decoder<unknown, R>,
|
|
65
65
|
bytes: Uint8Array,
|
|
66
66
|
): Effect.Effect<unknown, CodecError, R> =>
|
|
67
67
|
Effect.try({
|
|
@@ -69,7 +69,7 @@ export const deserialiseThenDecode = <R>(
|
|
|
69
69
|
catch: (cause) => new CodecError({ reason: 'deserialise', cause }),
|
|
70
70
|
}).pipe(
|
|
71
71
|
Effect.flatMap((raw) =>
|
|
72
|
-
Schema.
|
|
72
|
+
Schema.decodeUnknownEffect(schema)(raw).pipe(
|
|
73
73
|
Effect.mapError((cause) => new CodecError({ reason: 'decode', cause })),
|
|
74
74
|
),
|
|
75
75
|
),
|
package/src/errors.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* never defects.
|
|
4
4
|
*
|
|
5
5
|
* `CodecError` covers every serialisation/`Schema` failure on the codec path
|
|
6
|
-
* (deserialise threw, `Schema.
|
|
6
|
+
* (deserialise threw, `Schema.decodeUnknownEffect`/`encodeEffect` produced a
|
|
7
|
+
* `SchemaError`, a
|
|
7
8
|
* wrong/absent encryption key surfaced through a `Schema` transform, or a
|
|
8
9
|
* `tagsFor` mapper threw while deriving an event's tags). It carries a
|
|
9
10
|
* human-readable `reason` and the underlying `cause` (exact-optional).
|
|
@@ -42,9 +43,10 @@ export class CodecError extends Data.TaggedError('CodecError')<{
|
|
|
42
43
|
*
|
|
43
44
|
* A GETTER rather than a second field, so `reason` stays the single declaration.
|
|
44
45
|
* It is visible because `Data.TaggedError`'s constructor is
|
|
45
|
-
* `super(args?.message, …)` followed by
|
|
46
|
-
* against `effect@
|
|
47
|
-
* nothing shadows this prototype accessor
|
|
46
|
+
* `super(args?.message, …)` followed by copying the args' own enumerable keys
|
|
47
|
+
* onto the instance (verified against `effect@4`'s `internal/core.ts`): the
|
|
48
|
+
* args above carry no `message`, so nothing shadows this prototype accessor
|
|
49
|
+
* with an own property.
|
|
48
50
|
*/
|
|
49
51
|
override get message(): string {
|
|
50
52
|
return this.reason
|
package/src/event.ts
CHANGED
|
@@ -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
|
*
|
|
@@ -42,22 +42,32 @@ export type TagsFor<A> = (payload: A) => Arr.NonEmptyReadonlyArray<Tag>
|
|
|
42
42
|
/**
|
|
43
43
|
* An event definition: its branded `type`, the `Schema` mapping its typed
|
|
44
44
|
* payload `A` to its wire encoding `I` (requiring `R`), and the `tagsFor` mapper
|
|
45
|
-
* that derives the event's tags from a decoded payload.
|
|
46
|
-
*
|
|
45
|
+
* that derives the event's tags from a decoded payload.
|
|
46
|
+
*
|
|
47
|
+
* `R` is ONE requirement for both directions, which is why the schema is a
|
|
48
|
+
* `Schema.Codec<A, I, R, R>` rather than leaving decoding and encoding services
|
|
49
|
+
* apart. A def is decoded on the read path and encoded by `toEvent`, so a
|
|
50
|
+
* consumer providing a def's services provides them for both; an application
|
|
51
|
+
* encryption transform needs its key either way. A struct whose two directions
|
|
52
|
+
* differ still fits, the codec being covariant in both, and `R` is then their
|
|
53
|
+
* union.
|
|
54
|
+
*
|
|
55
|
+
* `tagsFor` CONSUMES an `A`, so `EventDef` is invariant in `A` whatever the
|
|
56
|
+
* schema's own variance, and is therefore not declared `out A`.
|
|
47
57
|
*/
|
|
48
58
|
export interface EventDef<A = unknown, I = unknown, R = never> {
|
|
49
59
|
readonly type: EventType
|
|
50
|
-
readonly schema: Schema.
|
|
60
|
+
readonly schema: Schema.Codec<A, I, R, R>
|
|
51
61
|
readonly tagsFor: TagsFor<A>
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
/**
|
|
55
|
-
* The heterogeneous bound
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
65
|
+
* The heterogeneous bound for arrays/records of mixed defs, where the precise
|
|
66
|
+
* `A`/`I` differ per element. `tagsFor` erases to `(a: any) => …`, which is
|
|
67
|
+
* harmless: only the write path (`toEvent`) calls it, and the registry/decode
|
|
68
|
+
* path never does (stored events already carry tags).
|
|
59
69
|
*/
|
|
60
|
-
// biome-ignore lint/suspicious/noExplicitAny: the sanctioned heterogeneous bound
|
|
70
|
+
// biome-ignore lint/suspicious/noExplicitAny: the sanctioned heterogeneous bound; A/I differ per element and tagsFor consumes A, so any is the only sound erasure.
|
|
61
71
|
export type EventDefAny = EventDef<any, any, unknown>
|
|
62
72
|
|
|
63
73
|
/**
|
package/src/precondition.ts
CHANGED
|
@@ -148,7 +148,7 @@ import type { Uuid } from './Uuid'
|
|
|
148
148
|
* path meant to deny the input cheaply. Wrap such work in `Effect.suspend`.
|
|
149
149
|
*/
|
|
150
150
|
export interface Precondition<Id, Service, E, R> {
|
|
151
|
-
readonly tag: Context.
|
|
151
|
+
readonly tag: Context.Key<Id, Service>
|
|
152
152
|
readonly evaluate: Effect.Effect<Service, E, R>
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -243,7 +243,7 @@ export const decideOnly = <
|
|
|
243
243
|
* condition here. If that turns up in practice, a composing override is the
|
|
244
244
|
* additive answer and this hatch is not it.
|
|
245
245
|
*
|
|
246
|
-
* `Effect.
|
|
246
|
+
* `Effect.updateContext` over
|
|
247
247
|
* `Context.omit(AppendIsOwned)` is what lets it through the store's ownership
|
|
248
248
|
* refusal — the one route, and `AppendIsOwned.ts` owns why removing the marker is
|
|
249
249
|
* the shape rather than a second tag or a sanctioning flag.
|
|
@@ -275,7 +275,7 @@ export const unsafeAppend = (
|
|
|
275
275
|
// channel), so nothing here will fail to compile if this is deleted — what
|
|
276
276
|
// catches it is `test/appendOwnership.test.ts` in the source repository, not the
|
|
277
277
|
// type checker.
|
|
278
|
-
Effect.
|
|
278
|
+
Effect.updateContext(
|
|
279
279
|
store.append(events),
|
|
280
280
|
(context: Context.Context<never>) => Context.omit(AppendIsOwned)(context),
|
|
281
281
|
),
|
package/src/projection.ts
CHANGED
|
@@ -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,
|
|
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.
|
|
@@ -35,7 +35,7 @@ import type { EventDef } from './event'
|
|
|
35
35
|
*/
|
|
36
36
|
export interface SliceProjection<out S = unknown, out R = unknown>
|
|
37
37
|
extends AnyProjection<S> {
|
|
38
|
-
readonly schemas: ReadonlyMap<string, Schema.
|
|
38
|
+
readonly schemas: ReadonlyMap<string, Schema.Decoder<unknown, R>>
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** The fluent builder: accumulate `.on(def, fold)` steps, then `.build()`. */
|
|
@@ -75,7 +75,7 @@ export const projection = <S>(initialState: S): ProjectionBuilder<S, never> => {
|
|
|
75
75
|
// threading `R` means the implementation states the same widening the
|
|
76
76
|
// `ProjectionBuilder` interface promises, and `on` returns without a cast.
|
|
77
77
|
const make = <R>(
|
|
78
|
-
schemas: ReadonlyMap<string, Schema.
|
|
78
|
+
schemas: ReadonlyMap<string, Schema.Decoder<unknown, R>>,
|
|
79
79
|
folds: ReadonlyMap<string, (state: S, payload: unknown) => S>,
|
|
80
80
|
): ProjectionBuilder<S, R> => ({
|
|
81
81
|
on: <A, I, R2>(
|
|
@@ -101,25 +101,20 @@ export const projection = <S>(initialState: S): ProjectionBuilder<S, never> => {
|
|
|
101
101
|
// The entry type is annotated `R | R2` rather than inferred, and that
|
|
102
102
|
// annotation is what carries the requirement forward — `build` reads `R`
|
|
103
103
|
// straight off this map, so `RequirementOf` ultimately reads it from here.
|
|
104
|
-
// Widening the copied `R` entries into it costs nothing: `Schema`
|
|
105
|
-
// declared `<
|
|
104
|
+
// Widening the copied `R` entries into it costs nothing: `Schema.Decoder`
|
|
105
|
+
// is declared `<out T, out RD>` upstream, hence covariant in its
|
|
106
106
|
// requirement.
|
|
107
|
-
const nextSchemas = new Map<
|
|
108
|
-
|
|
109
|
-
Schema.Schema<unknown, unknown, R | R2>
|
|
110
|
-
>(schemas)
|
|
111
|
-
// Erasing `A`/`I` is the one unavoidable cast, and `as unknown as` is what
|
|
112
|
-
// it takes: `Schema` is INVARIANT in both, so `Schema<A, I, R2>` and
|
|
113
|
-
// `Schema<unknown, unknown, R2>` are unrelated in either direction. It is
|
|
114
|
-
// sound because the payload is only ever read back through `evolve`, which
|
|
115
|
-
// re-narrows by event type via the matching `fold`. The target names `R2`
|
|
116
|
-
// and not `never` because `R2` is what the def actually requires — an
|
|
117
|
-
// `Encrypted` field's `CipherKey` is not nothing — so the cast erases only
|
|
118
|
-
// what it has to and states the rest truthfully.
|
|
119
|
-
nextSchemas.set(
|
|
120
|
-
def.type,
|
|
121
|
-
def.schema as unknown as Schema.Schema<unknown, unknown, R2>,
|
|
107
|
+
const nextSchemas = new Map<string, Schema.Decoder<unknown, R | R2>>(
|
|
108
|
+
schemas,
|
|
122
109
|
)
|
|
110
|
+
// Erasing `A`/`I` needs no cast: a `Schema.Codec` is covariant in both, so
|
|
111
|
+
// `Codec<A, I, R2, R2>` is already a `Decoder<unknown, R2>`. The erasure is
|
|
112
|
+
// sound because the payload is only ever read back through `evolve`, which
|
|
113
|
+
// re-narrows by event type via the matching `fold`. What survives it is
|
|
114
|
+
// `R2`, the def's DECODING requirement — an `Encrypted` field's `CipherKey`
|
|
115
|
+
// is not nothing — and that is the half a slice ever spends, since a slice
|
|
116
|
+
// decodes and never encodes.
|
|
117
|
+
nextSchemas.set(def.type, def.schema)
|
|
123
118
|
const nextFolds = new Map(folds)
|
|
124
119
|
// Contravariance in the payload parameter, so this one is a cast too: the
|
|
125
120
|
// map holds folds over `unknown`, and `evolve` supplies the payload the
|