@kairos-es/core 1.0.0-alpha.4 → 1.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/cjs/AppendCondition.js +1 -3
- package/dist/cjs/AppendCondition.js.map +1 -1
- package/dist/cjs/AppendIsOwned.js +6 -6
- package/dist/cjs/AppendIsOwned.js.map +1 -1
- package/dist/cjs/ContractStore.js +2 -2
- package/dist/cjs/ContractStore.js.map +1 -1
- package/dist/cjs/DcbEventStore.js +1 -1
- package/dist/cjs/DcbEventStore.js.map +1 -1
- package/dist/cjs/Event.js +29 -13
- package/dist/cjs/Event.js.map +1 -1
- package/dist/cjs/Query.js +1 -1
- package/dist/cjs/Query.js.map +1 -1
- package/dist/cjs/SubscribeMachine.js +20 -22
- package/dist/cjs/SubscribeMachine.js.map +1 -1
- package/dist/cjs/inMemory.js +4 -4
- package/dist/cjs/inMemory.js.map +1 -1
- package/dist/cjs/retryOnConflict.js +4 -10
- package/dist/cjs/retryOnConflict.js.map +1 -1
- package/dist/cjs/testing.js +2 -2
- package/dist/cjs/testing.js.map +1 -1
- package/dist/{dts → dts-cjs}/AppendCondition.d.ts +5 -7
- package/dist/{dts → dts-cjs}/AppendCondition.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts +6 -6
- package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/ContractStore.d.ts +3 -2
- package/dist/dts-cjs/ContractStore.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/DcbEventStore.d.ts +2 -2
- package/dist/{dts → dts-cjs}/DcbEventStore.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/Event.d.ts +31 -20
- package/dist/dts-cjs/Event.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/Query.d.ts +5 -5
- package/dist/{dts → dts-cjs}/SubscribeMachine.d.ts +11 -15
- package/dist/dts-cjs/SubscribeMachine.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/inMemory.d.ts.map +1 -1
- package/dist/{dts → dts-cjs}/index.d.ts +1 -1
- package/dist/dts-cjs/package.json +3 -0
- package/dist/{dts → dts-cjs}/retryOnConflict.d.ts +1 -7
- package/dist/dts-cjs/retryOnConflict.d.ts.map +1 -0
- package/dist/{dts → dts-cjs}/testing.d.ts +1 -1
- package/dist/dts-esm/AppendCondition.d.ts +21 -0
- package/dist/dts-esm/AppendCondition.d.ts.map +1 -0
- package/dist/dts-esm/AppendIsOwned.d.ts +78 -0
- package/dist/dts-esm/AppendIsOwned.d.ts.map +1 -0
- package/dist/dts-esm/ContractStore.d.ts +62 -0
- package/dist/dts-esm/ContractStore.d.ts.map +1 -0
- package/dist/dts-esm/DcbEventStore.d.ts +64 -0
- package/dist/dts-esm/DcbEventStore.d.ts.map +1 -0
- package/dist/dts-esm/Event.d.ts +174 -0
- package/dist/dts-esm/Event.d.ts.map +1 -0
- package/dist/dts-esm/Projection.d.ts +124 -0
- package/dist/dts-esm/Projection.d.ts.map +1 -0
- package/dist/dts-esm/Query.d.ts +180 -0
- package/dist/dts-esm/Query.d.ts.map +1 -0
- package/dist/dts-esm/SubscribeMachine.d.ts +175 -0
- package/dist/dts-esm/SubscribeMachine.d.ts.map +1 -0
- package/dist/dts-esm/errors.d.ts +17 -0
- package/dist/dts-esm/errors.d.ts.map +1 -0
- package/dist/dts-esm/inMemory.d.ts +76 -0
- package/dist/dts-esm/inMemory.d.ts.map +1 -0
- package/dist/dts-esm/index.d.ts +40 -0
- package/dist/dts-esm/index.d.ts.map +1 -0
- package/dist/dts-esm/package.json +3 -0
- package/dist/dts-esm/retryOnConflict.d.ts +64 -0
- package/dist/dts-esm/retryOnConflict.d.ts.map +1 -0
- package/dist/dts-esm/testing.d.ts +39 -0
- package/dist/dts-esm/testing.d.ts.map +1 -0
- package/dist/esm/AppendCondition.js +1 -3
- package/dist/esm/AppendCondition.js.map +1 -1
- package/dist/esm/AppendIsOwned.js +6 -6
- package/dist/esm/AppendIsOwned.js.map +1 -1
- package/dist/esm/ContractStore.js +2 -2
- package/dist/esm/ContractStore.js.map +1 -1
- package/dist/esm/DcbEventStore.js +1 -1
- package/dist/esm/DcbEventStore.js.map +1 -1
- package/dist/esm/Event.js +30 -14
- package/dist/esm/Event.js.map +1 -1
- package/dist/esm/Query.js +1 -1
- package/dist/esm/Query.js.map +1 -1
- package/dist/esm/SubscribeMachine.js +21 -23
- package/dist/esm/SubscribeMachine.js.map +1 -1
- package/dist/esm/inMemory.js +5 -5
- package/dist/esm/inMemory.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/retryOnConflict.js +4 -10
- package/dist/esm/retryOnConflict.js.map +1 -1
- package/dist/esm/testing.js +2 -2
- package/dist/esm/testing.js.map +1 -1
- package/package.json +21 -11
- package/src/AppendCondition.ts +1 -1
- package/src/AppendIsOwned.ts +7 -7
- package/src/ContractStore.ts +5 -4
- package/src/DcbEventStore.ts +3 -3
- package/src/Event.ts +49 -14
- package/src/Query.ts +1 -1
- package/src/SubscribeMachine.ts +38 -31
- package/src/inMemory.ts +6 -6
- package/src/index.ts +1 -1
- package/src/retryOnConflict.ts +6 -11
- package/src/testing.ts +2 -2
- package/testing/package.json +1 -1
- package/dist/dts/ContractStore.d.ts.map +0 -1
- package/dist/dts/Event.d.ts.map +0 -1
- package/dist/dts/SubscribeMachine.d.ts.map +0 -1
- package/dist/dts/retryOnConflict.d.ts.map +0 -1
- /package/dist/{dts → dts-cjs}/Projection.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/Projection.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/Query.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/errors.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/errors.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/inMemory.d.ts +0 -0
- /package/dist/{dts → dts-cjs}/index.d.ts.map +0 -0
- /package/dist/{dts → dts-cjs}/testing.d.ts.map +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppendCondition.d.ts","sourceRoot":"","sources":["../../src/AppendCondition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI/B,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"AppendCondition.d.ts","sourceRoot":"","sources":["../../src/AppendCondition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI/B,eAAO,MAAM,eAAe;;;;;;;;EAG1B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA"}
|
|
@@ -30,21 +30,21 @@
|
|
|
30
30
|
*
|
|
31
31
|
* ## Present means refused, so a sanctioned append REMOVES the marker
|
|
32
32
|
*
|
|
33
|
-
* The check reads the
|
|
33
|
+
* The check reads the service through `Effect.serviceOption`, so its ABSENCE is the
|
|
34
34
|
* normal case and costs the `append` signature nothing — `DcbEventStore.append`
|
|
35
35
|
* keeps `R = never` and no caller provides anything. Presence is what refuses.
|
|
36
36
|
*
|
|
37
37
|
* That shape decides how the two legitimate appends inside a bracket get through,
|
|
38
38
|
* and there is only one route: run with the marker STRIPPED from the context
|
|
39
|
-
* (`Effect.
|
|
39
|
+
* (`Effect.updateContext` over `Context.omit(AppendIsOwned)`). The bracket's own
|
|
40
40
|
* closing append is issued outside the scope it provided the marker in, and the
|
|
41
|
-
* codec's escape hatch strips it explicitly. Neither needs a second
|
|
41
|
+
* codec's escape hatch strips it explicitly. Neither needs a second service, a
|
|
42
42
|
* sanctioning flag or a mutable cell, and there is no way to be exempt by
|
|
43
43
|
* accident: an append is either lexically outside the marked region or it says in
|
|
44
44
|
* as many words that it is removing the marker.
|
|
45
45
|
*/
|
|
46
46
|
import { Context, Effect } from 'effect';
|
|
47
|
-
declare const AppendIsOwned_base: Context.
|
|
47
|
+
declare const AppendIsOwned_base: Context.ServiceClass<AppendIsOwned, "@kairos-es/core/AppendIsOwned", {
|
|
48
48
|
readonly by: string;
|
|
49
49
|
}>;
|
|
50
50
|
/**
|
|
@@ -52,7 +52,7 @@ declare const AppendIsOwned_base: Context.TagClass<AppendIsOwned, "@kairos-es/co
|
|
|
52
52
|
* owns it.
|
|
53
53
|
*
|
|
54
54
|
* `by` is a human-readable owner name and exists for the defect message alone —
|
|
55
|
-
* the refusal is decided by the
|
|
55
|
+
* the refusal is decided by the service's PRESENCE, never by this value, so nothing
|
|
56
56
|
* branches on it and no caller need agree on a vocabulary for it.
|
|
57
57
|
*/
|
|
58
58
|
export declare class AppendIsOwned extends AppendIsOwned_base {
|
|
@@ -69,7 +69,7 @@ export declare class AppendIsOwned extends AppendIsOwned_base {
|
|
|
69
69
|
* its escape hatch for a deliberate second append — which is what makes a defect
|
|
70
70
|
* affordable here.
|
|
71
71
|
*
|
|
72
|
-
* `Effect.serviceOption` is what keeps this free: it reads the
|
|
72
|
+
* `Effect.serviceOption` is what keeps this free: it reads the service if present and
|
|
73
73
|
* adds NOTHING to the requirement channel, so every existing append is unchanged
|
|
74
74
|
* and unprovisioned.
|
|
75
75
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppendIsOwned.d.ts","sourceRoot":"","sources":["../../src/AppendIsOwned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;;iBAYvB,MAAM;;AAVvB;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,
|
|
1
|
+
{"version":3,"file":"AppendIsOwned.d.ts","sourceRoot":"","sources":["../../src/AppendIsOwned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;;iBAYvB,MAAM;;AAVvB;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,kBAGC;CAAG;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAepD,CAAA"}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* channel (`never` for the pure in-memory engine; `SqlError` for either SQL one).
|
|
9
9
|
* The decorator wraps those mechanics with the policy the contract demands — the
|
|
10
10
|
* policy the first two engines hand-duplicated, with the Postgres one even
|
|
11
|
-
* needing a bespoke `catchAll`/`instanceof
|
|
11
|
+
* needing a bespoke `catchAll`/`instanceof` (Effect 3's `catchAll`, which Effect 4
|
|
12
|
+
* names `catch`):
|
|
12
13
|
*
|
|
13
14
|
* - `assertServableQuery` at every verb's entry (read, the append condition's
|
|
14
15
|
* guard query, subscribe) — a non-servable query, or one carrying a key the
|
|
@@ -57,5 +58,5 @@ export interface RawDcbEventStore<E> {
|
|
|
57
58
|
* Wrap a raw engine's mechanics with the shared contract-enforcement policy,
|
|
58
59
|
* producing a full `DcbEventStore` service value.
|
|
59
60
|
*/
|
|
60
|
-
export declare const makeContractStore: <E>(raw: RawDcbEventStore<E>) => DcbEventStore["
|
|
61
|
+
export declare const makeContractStore: <E>(raw: RawDcbEventStore<E>) => DcbEventStore["Service"];
|
|
61
62
|
//# sourceMappingURL=ContractStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContractStore.d.ts","sourceRoot":"","sources":["../../src/ContractStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,MAAM,EAAqB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAKzD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,CACb,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,WAAW,KAClB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,CACf,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAC3C,SAAS,CAAC,EAAE,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,GAAG,CAAC,CAAC,CAAA;IACvD,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,KAAK,EACZ,KAAK,CAAC,EAAE,QAAQ,KACb,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CACnD;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,KAAK,gBAAgB,CAAC,CAAC,CAAC,KACvB,aAAa,CAAC,SAAS,CAoGxB,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `DcbEventStore` contract: a `Context.
|
|
2
|
+
* The `DcbEventStore` contract: a `Context.Service` with no bundled implementation.
|
|
3
3
|
* Consumers supply a `Layer` (the in-memory one lives in this package; each SQL
|
|
4
4
|
* engine is a package of its own — `@kairos-es/store-postgres` and
|
|
5
5
|
* `@kairos-es/store-sqlite`).
|
|
@@ -39,7 +39,7 @@ export interface ReadResponse {
|
|
|
39
39
|
readonly events: Stream.Stream<SequencedEvent>;
|
|
40
40
|
readonly head: Position;
|
|
41
41
|
}
|
|
42
|
-
declare const DcbEventStore_base: Context.
|
|
42
|
+
declare const DcbEventStore_base: Context.ServiceClass<DcbEventStore, "@kairos-es/core/DcbEventStore", {
|
|
43
43
|
/**
|
|
44
44
|
* Read events matching `query` (empty query = all), optionally bounded by
|
|
45
45
|
* `after`/`limit`. See head semantics in the module docs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DcbEventStore.d.ts","sourceRoot":"","sources":["../../src/DcbEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC9C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CACxB;;IAKG;;;OAGG;mBACY,CACb,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,WAAW,KAClB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;IAEhC;;;;OAIG;qBACc,CACf,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAC3C,SAAS,CAAC,EAAE,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IAEnD;;;;OAIG;wBACiB,CAClB,KAAK,EAAE,KAAK,EACZ,KAAK,CAAC,EAAE,QAAQ,KACb,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AA9B1D,qBAAa,aAAc,SAAQ,
|
|
1
|
+
{"version":3,"file":"DcbEventStore.d.ts","sourceRoot":"","sources":["../../src/DcbEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC9C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CACxB;;IAKG;;;OAGG;mBACY,CACb,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,WAAW,KAClB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;IAEhC;;;;OAIG;qBACc,CACf,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAC3C,SAAS,CAAC,EAAE,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IAEnD;;;;OAIG;wBACiB,CAClB,KAAK,EAAE,KAAK,EACZ,KAAK,CAAC,EAAE,QAAQ,KACb,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AA9B1D,qBAAa,aAAc,SAAQ,kBAgCC;CAAG"}
|
|
@@ -12,11 +12,20 @@ import { Schema } from 'effect';
|
|
|
12
12
|
*
|
|
13
13
|
* The log is 64-bit (`bigserial` in Postgres) and exceeds JS `number` safety at
|
|
14
14
|
* 2^53, so positions are a `bigint`. They are compared, never arithmetic'd.
|
|
15
|
-
*
|
|
15
|
+
* Encoded, a position is a decimal string (JSON-safe, `String(b)`); decoded, a
|
|
16
16
|
* `bigint`. `0n` is the "before the first event" sentinel used by `after` and by
|
|
17
17
|
* an empty store's head.
|
|
18
|
+
*
|
|
19
|
+
* The string-to-`bigint` step is hand-built rather than Effect 4's
|
|
20
|
+
* `Schema.BigIntFromString`, because that schema accepts only `^-?\d+$` and so
|
|
21
|
+
* refuses inputs the encoded side has always admitted — `" 5"`, `"+5"`,
|
|
22
|
+
* `"0x10"`. The decode here is the global `BigInt(s)` behind a blank-string
|
|
23
|
+
* refusal, which is `BigInt.fromString` and is exactly what Effect 3's
|
|
24
|
+
* `Schema.BigInt` ran, so a position string any earlier release decoded still
|
|
25
|
+
* decodes to the same value. The non-negative check then runs on the `bigint`,
|
|
26
|
+
* as it always did.
|
|
18
27
|
*/
|
|
19
|
-
export declare const Position: Schema.brand<Schema.
|
|
28
|
+
export declare const Position: Schema.brand<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>, "Position">;
|
|
20
29
|
export type Position = typeof Position.Type;
|
|
21
30
|
/** The sentinel position meaning "before the first event". */
|
|
22
31
|
export declare const ORIGIN: Position;
|
|
@@ -26,7 +35,7 @@ export declare const ORIGIN: Position;
|
|
|
26
35
|
* event sourcing; a query matches an event when the event carries all of an
|
|
27
36
|
* item's tags (superset test).
|
|
28
37
|
*/
|
|
29
|
-
export declare const Tag: Schema.brand<Schema.
|
|
38
|
+
export declare const Tag: Schema.brand<Schema.String, "Tag">;
|
|
30
39
|
export type Tag = typeof Tag.Type;
|
|
31
40
|
/**
|
|
32
41
|
* A reusable tag identity: a `key` plus a `.make(value)` that composes the
|
|
@@ -65,13 +74,13 @@ export declare const tagIdentity: (key: string) => TagIdentity;
|
|
|
65
74
|
* error channel (`read` keeps `E = never`). Constructed at call sites with
|
|
66
75
|
* `ReadLimit.make(n)`.
|
|
67
76
|
*/
|
|
68
|
-
export declare const ReadLimit: Schema.brand<Schema.
|
|
77
|
+
export declare const ReadLimit: Schema.brand<Schema.Int, "ReadLimit">;
|
|
69
78
|
export type ReadLimit = typeof ReadLimit.Type;
|
|
70
79
|
/**
|
|
71
80
|
* An event type name, a branded non-empty string. Versioning is by convention
|
|
72
81
|
* in the name (e.g. `course-registered.v2`); only non-emptiness is enforced.
|
|
73
82
|
*/
|
|
74
|
-
export declare const EventType: Schema.brand<Schema.
|
|
83
|
+
export declare const EventType: Schema.brand<Schema.String, "EventType">;
|
|
75
84
|
export type EventType = typeof EventType.Type;
|
|
76
85
|
/**
|
|
77
86
|
* An event's metadata: a flat bag of strings carrying the circumstances under
|
|
@@ -122,7 +131,7 @@ export type EventType = typeof EventType.Type;
|
|
|
122
131
|
* alone: it would make an event the store accepted unreadable for ever, so a
|
|
123
132
|
* value check belongs at write or nowhere.
|
|
124
133
|
*/
|
|
125
|
-
export declare const Metadata: Schema
|
|
134
|
+
export declare const Metadata: Schema.$Record<Schema.String, Schema.String>;
|
|
126
135
|
export type Metadata = typeof Metadata.Type;
|
|
127
136
|
/**
|
|
128
137
|
* An event as stored: an opaque payload plus its type, tags, a
|
|
@@ -131,6 +140,8 @@ export type Metadata = typeof Metadata.Type;
|
|
|
131
140
|
*
|
|
132
141
|
* `data` is `Uint8Array` (opaque bytes); the store does not interpret it.
|
|
133
142
|
* `uuid` is producer-supplied to keep `core` deterministic (no RNG in core).
|
|
143
|
+
* It is checked for UUID SHAPE only (`isGUID`), not for a version nibble: a
|
|
144
|
+
* stricter check would refuse ids an existing log already holds.
|
|
134
145
|
* `occurredAt` is informational only; ordering is by position alone.
|
|
135
146
|
* `metadata` mirrors `tags` rather than `data`: REQUIRED, with an empty bag
|
|
136
147
|
* legal. Required because an absent-versus-empty divergence between engines is
|
|
@@ -139,25 +150,25 @@ export type Metadata = typeof Metadata.Type;
|
|
|
139
150
|
* Core only carries it; the codec's `toEvent` is where it is resolved.
|
|
140
151
|
*/
|
|
141
152
|
export declare const DcbEvent: Schema.Struct<{
|
|
142
|
-
type: Schema.brand<Schema.
|
|
143
|
-
data:
|
|
144
|
-
tags: Schema
|
|
145
|
-
uuid:
|
|
146
|
-
occurredAt:
|
|
147
|
-
metadata: Schema
|
|
153
|
+
readonly type: Schema.brand<Schema.String, "EventType">;
|
|
154
|
+
readonly data: Schema.Uint8Array;
|
|
155
|
+
readonly tags: Schema.$Array<Schema.brand<Schema.String, "Tag">>;
|
|
156
|
+
readonly uuid: Schema.String;
|
|
157
|
+
readonly occurredAt: Schema.DateTimeUtcFromString;
|
|
158
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.String>;
|
|
148
159
|
}>;
|
|
149
160
|
export type DcbEvent = typeof DcbEvent.Type;
|
|
150
161
|
/** A persisted event: the event together with the position it was written at. */
|
|
151
162
|
export declare const SequencedEvent: Schema.Struct<{
|
|
152
|
-
event: Schema.Struct<{
|
|
153
|
-
type: Schema.brand<Schema.
|
|
154
|
-
data:
|
|
155
|
-
tags: Schema
|
|
156
|
-
uuid:
|
|
157
|
-
occurredAt:
|
|
158
|
-
metadata: Schema
|
|
163
|
+
readonly event: Schema.Struct<{
|
|
164
|
+
readonly type: Schema.brand<Schema.String, "EventType">;
|
|
165
|
+
readonly data: Schema.Uint8Array;
|
|
166
|
+
readonly tags: Schema.$Array<Schema.brand<Schema.String, "Tag">>;
|
|
167
|
+
readonly uuid: Schema.String;
|
|
168
|
+
readonly occurredAt: Schema.DateTimeUtcFromString;
|
|
169
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.String>;
|
|
159
170
|
}>;
|
|
160
|
-
position: Schema.brand<Schema.
|
|
171
|
+
readonly position: Schema.brand<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>, "Position">;
|
|
161
172
|
}>;
|
|
162
173
|
export type SequencedEvent = typeof SequencedEvent.Type;
|
|
163
174
|
//# sourceMappingURL=Event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Event.d.ts","sourceRoot":"","sources":["../../src/Event.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAIL,MAAM,EAGP,MAAM,QAAQ,CAAA;AAEf;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,QAAQ,uFAuBpB,CAAA;AACD,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C,8DAA8D;AAC9D,eAAO,MAAM,MAAM,EAAE,QAA4B,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,GAAG,oCAGf,CAAA;AACD,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,IAAI,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CACtC;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,WAiBzC,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,uCAGrB,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,SAAS,0CAGrB,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,QAAQ,8CAA8C,CAAA;AACnE,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ;;;;;;;EAOnB,CAAA;AACF,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C,iFAAiF;AACjF,eAAO,MAAM,cAAc;;;;;;;;;;EAGzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA"}
|
|
@@ -29,15 +29,15 @@ import { type DcbEvent, EventType, type SequencedEvent, Tag } from './Event.js';
|
|
|
29
29
|
* (superset test, empty = no tag constraint).
|
|
30
30
|
*/
|
|
31
31
|
export declare const QueryItem: Schema.Struct<{
|
|
32
|
-
types: Schema
|
|
33
|
-
tags: Schema
|
|
32
|
+
readonly types: Schema.$Array<Schema.brand<Schema.String, "EventType">>;
|
|
33
|
+
readonly tags: Schema.$Array<Schema.brand<Schema.String, "Tag">>;
|
|
34
34
|
}>;
|
|
35
35
|
export type QueryItem = typeof QueryItem.Type;
|
|
36
36
|
/** A query: an OR of items. Empty `items` matches everything. */
|
|
37
37
|
export declare const Query: Schema.Struct<{
|
|
38
|
-
items: Schema
|
|
39
|
-
types: Schema
|
|
40
|
-
tags: Schema
|
|
38
|
+
readonly items: Schema.$Array<Schema.Struct<{
|
|
39
|
+
readonly types: Schema.$Array<Schema.brand<Schema.String, "EventType">>;
|
|
40
|
+
readonly tags: Schema.$Array<Schema.brand<Schema.String, "Tag">>;
|
|
41
41
|
}>>;
|
|
42
42
|
}>;
|
|
43
43
|
export type Query = typeof Query.Type;
|
|
@@ -108,12 +108,12 @@ export declare const DEFAULT_POLL_INTERVAL_MILLIS = 1000;
|
|
|
108
108
|
* the key NAME, the VALIDATION and the DEFAULT from one place, so a caller who has
|
|
109
109
|
* tuned one engine's subscribe reads another's without translating, and the two
|
|
110
110
|
* cannot drift in what they ACCEPT any more than in what they assume. Two engines
|
|
111
|
-
* hand-authoring the identical `Schema.
|
|
111
|
+
* hand-authoring the identical `Schema.optionalKey(…)` twice were identical only
|
|
112
112
|
* by inspection.
|
|
113
113
|
*
|
|
114
114
|
* The bounds differ between the two because the quantities do. `pollInterval` is a
|
|
115
|
-
* duration, so a fraction of a millisecond is meaningful and only `
|
|
116
|
-
* `
|
|
115
|
+
* duration, so a fraction of a millisecond is meaningful and only `isGreaterThan(0)`
|
|
116
|
+
* and `isFinite` matter: at zero or below the loop would spin without ever waiting for a
|
|
117
117
|
* wake, and at `Infinity` the periodic re-read — the half that carries delivery —
|
|
118
118
|
* would never come, which silently converts the wake source from an optimisation
|
|
119
119
|
* into the guarantee. `catchUpPageSize` is a COUNT, so it must be an integer
|
|
@@ -121,17 +121,13 @@ export declare const DEFAULT_POLL_INTERVAL_MILLIS = 1000;
|
|
|
121
121
|
* length against it to decide the tail is drained, and a page of zero would report
|
|
122
122
|
* "drained" forever without reading anything.
|
|
123
123
|
*
|
|
124
|
-
* `
|
|
124
|
+
* `optionalKey` on both keeps the decoded type at `key?: T` rather than
|
|
125
125
|
* `T | undefined`, matching the repo's `exactOptionalPropertyTypes` discipline — an
|
|
126
126
|
* absent key, never an explicit `undefined`.
|
|
127
127
|
*/
|
|
128
128
|
export declare const subscriptionTuningFields: {
|
|
129
|
-
readonly pollInterval: Schema.
|
|
130
|
-
|
|
131
|
-
}>;
|
|
132
|
-
readonly catchUpPageSize: Schema.optionalWith<Schema.filter<typeof Schema.Int>, {
|
|
133
|
-
exact: true;
|
|
134
|
-
}>;
|
|
129
|
+
readonly pollInterval: Schema.optionalKey<Schema.Number>;
|
|
130
|
+
readonly catchUpPageSize: Schema.optionalKey<Schema.Int>;
|
|
135
131
|
};
|
|
136
132
|
/**
|
|
137
133
|
* The two seams the subscribe machine runs over, plus the two tuning knobs. `E` is
|
|
@@ -140,7 +136,7 @@ export declare const subscriptionTuningFields: {
|
|
|
140
136
|
*
|
|
141
137
|
* ONE type parameter and not two, deliberately: a wake source with an error type of
|
|
142
138
|
* its own is `Stream.orDie`d by the caller, yielding a `Stream<unknown, never>`
|
|
143
|
-
* that is assignable here under Effect
|
|
139
|
+
* that is assignable here under Effect's covariant error channel. A second
|
|
144
140
|
* parameter would buy nothing and would have to be spelled at every call site. Nor
|
|
145
141
|
* is there an `R`: neither seam contributes a requirement, and unused generality is
|
|
146
142
|
* not free.
|
|
@@ -169,10 +165,10 @@ export interface SubscriptionDeps<E> {
|
|
|
169
165
|
}
|
|
170
166
|
/**
|
|
171
167
|
* Build the subscription `Stream`: catch up from `after`, then track the live tail.
|
|
172
|
-
* The cursor threads through the `
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* on close. An `E` mid-stream stays on the channel; `makeContractStore` dies it
|
|
168
|
+
* The cursor threads through the `Stream.paginate` state, starting at `after` and
|
|
169
|
+
* advancing to the last delivered position each batch; the stream never completes
|
|
170
|
+
* on its own (the next state is always `Option.some`), so the enclosing scope
|
|
171
|
+
* interrupts it on close. An `E` mid-stream stays on the channel; `makeContractStore` dies it
|
|
176
172
|
* (subscribe is `E = never` on the contract).
|
|
177
173
|
*/
|
|
178
174
|
export declare const subscribeStream: <E>(deps: SubscriptionDeps<E>, after: Position | undefined) => Stream.Stream<SequencedEvent, E, Scope.Scope>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscribeMachine.d.ts","sourceRoot":"","sources":["../../src/SubscribeMachine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,OAAO,EACL,MAAM,EAIN,MAAM,EACN,KAAK,KAAK,EACV,MAAM,EACP,MAAM,QAAQ,CAAA;AACf,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAU,SAAS,EAAE,MAAM,SAAS,CAAA;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,MAAM,CAAA;AAE7C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,OAAO,CAAA;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,wBAAwB;;;CAO3B,CAAA;AAiBV;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,CACd,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,SAAS,KACb,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAA;IACpD;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IAC3C,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAC/B,MAAM,gBAAgB,CAAC,CAAC,CAAC,EACzB,OAAO,QAAQ,GAAG,SAAS,KAC1B,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CA+G5C,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inMemory.d.ts","sourceRoot":"","sources":["../../src/inMemory.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAY,MAAM,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"inMemory.d.ts","sourceRoot":"","sources":["../../src/inMemory.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAY,MAAM,EAAE,KAAK,EAAkC,MAAM,QAAQ,CAAA;AAIhF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAuL/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAC/B;AAuID,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAG5D,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAChC,SAAS,oBAAoB,KAC5B,KAAK,CAAC,KAAK,CAAC,aAAa,CAC+C,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @kairos-es/core: DCB-first event-sourcing contract and in-memory store for
|
|
3
|
-
* Effect
|
|
3
|
+
* Effect.
|
|
4
4
|
*
|
|
5
5
|
* Exposes the domain types (`DcbEvent`, `SequencedEvent`, `Position`, `Tag`,
|
|
6
6
|
* `EventType`), the selection language (`Query`, `QueryItem`, the pure match
|
|
@@ -35,12 +35,6 @@
|
|
|
35
35
|
* jitter draws from `Random.next`, a default service on the same footing as the
|
|
36
36
|
* clock rather than a host `Math.random`. No `node:*`, no wall-clock reading, no
|
|
37
37
|
* ungoverned RNG.
|
|
38
|
-
*
|
|
39
|
-
* Effect v3 caveat: the `Schedule` API below is the THREE-type-parameter
|
|
40
|
-
* `Schedule<Out, In, R>` that `effect@3` exports, with `Schedule.intersect`. The
|
|
41
|
-
* currently-published docs show a newer four-type-parameter `Schedule` without
|
|
42
|
-
* `intersect` — do not copy them; this file is written against the installed
|
|
43
|
-
* `effect@3` type definitions.
|
|
44
38
|
*/
|
|
45
39
|
import { Effect, Schedule } from 'effect';
|
|
46
40
|
import type { AppendConditionFailed } from './errors.js';
|
|
@@ -66,5 +60,5 @@ import type { AppendConditionFailed } from './errors.js';
|
|
|
66
60
|
* error when a consumer's graph loads both builds — a conflict would then escape
|
|
67
61
|
* unretried and silently.
|
|
68
62
|
*/
|
|
69
|
-
export declare const retryOnConflict: <A, E, R>(command: Effect.Effect<A, AppendConditionFailed | E, R>, schedule?: Schedule.Schedule<unknown, AppendConditionFailed | E, R>) => Effect.Effect<A, AppendConditionFailed | E, R>;
|
|
63
|
+
export declare const retryOnConflict: <A, E, R>(command: Effect.Effect<A, AppendConditionFailed | E, R>, schedule?: Schedule.Schedule<unknown, AppendConditionFailed | E, never, R>) => Effect.Effect<A, AppendConditionFailed | E, R>;
|
|
70
64
|
//# sourceMappingURL=retryOnConflict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryOnConflict.d.ts","sourceRoot":"","sources":["../../src/retryOnConflict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,MAAM,EAAa,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAqBrD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EACrC,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,qBAAqB,GAAG,CAAC,EAAE,CAAC,CAAC,EACvD,WAAU,QAAQ,CAAC,QAAQ,CACzB,OAAO,EACP,qBAAqB,GAAG,CAAC,EACzB,KAAK,EACL,CAAC,CACgB,KAClB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,qBAAqB,GAAG,CAAC,EAAE,CAAC,CAI5C,CAAA"}
|
|
@@ -20,7 +20,7 @@ import { DateTime } from 'effect';
|
|
|
20
20
|
*
|
|
21
21
|
* Ordering in the log is by `position` alone, so an event's `occurredAt` is
|
|
22
22
|
* informational; pinning it to the epoch keeps serialised bytes and comparisons
|
|
23
|
-
* stable across runs. Built via `DateTime.
|
|
23
|
+
* stable across runs. Built via `DateTime.makeUnsafe(0)` (the value is a
|
|
24
24
|
* compile-time constant, not read from the host clock).
|
|
25
25
|
*/
|
|
26
26
|
export declare const EPOCH: DateTime.Utc;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The optimistic-concurrency guard for `append`. The append fails if any event
|
|
3
|
+
* matching `failIfEventsMatch` exists strictly after `after`. This is the whole
|
|
4
|
+
* DCB consistency mechanism: "fail if anything I based my decision on has
|
|
5
|
+
* changed since I read it."
|
|
6
|
+
*
|
|
7
|
+
* `after` is exact-optional (absent, never `undefined`) per
|
|
8
|
+
* `exactOptionalPropertyTypes`. Absent means "scan the whole log".
|
|
9
|
+
*/
|
|
10
|
+
import { Schema } from 'effect';
|
|
11
|
+
export declare const AppendCondition: Schema.Struct<{
|
|
12
|
+
readonly failIfEventsMatch: Schema.Struct<{
|
|
13
|
+
readonly items: Schema.$Array<Schema.Struct<{
|
|
14
|
+
readonly types: Schema.$Array<Schema.brand<Schema.String, "EventType">>;
|
|
15
|
+
readonly tags: Schema.$Array<Schema.brand<Schema.String, "Tag">>;
|
|
16
|
+
}>>;
|
|
17
|
+
}>;
|
|
18
|
+
readonly after: Schema.optionalKey<Schema.brand<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>, "Position">>;
|
|
19
|
+
}>;
|
|
20
|
+
export type AppendCondition = typeof AppendCondition.Type;
|
|
21
|
+
//# sourceMappingURL=AppendCondition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppendCondition.d.ts","sourceRoot":"","sources":["../../src/AppendCondition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI/B,eAAO,MAAM,eAAe;;;;;;;;EAG1B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AppendIsOwned` — the marker saying *"an append is already owned here"*, and the
|
|
3
|
+
* check that refuses a second one.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a write-side concept core does not need for its own job lives in core
|
|
6
|
+
*
|
|
7
|
+
* A bracket that derives one `AppendCondition` from every read its body performed
|
|
8
|
+
* (`@kairos-es/codec`'s `transact`) owns exactly one append: the one it issues at
|
|
9
|
+
* close, under that derived condition. Any OTHER append inside that body is a
|
|
10
|
+
* wiring mistake, and the dangerous case is not the one that looks dangerous. A
|
|
11
|
+
* command runner appending mid-body usually writes into the very slice the body
|
|
12
|
+
* read, so its events match the union the bracket is about to guard on — and the
|
|
13
|
+
* bracket's own closing append is then refused by a condition its own body
|
|
14
|
+
* invalidated. The failure arrives at the wrong line, describing a conflict that
|
|
15
|
+
* was self-inflicted.
|
|
16
|
+
*
|
|
17
|
+
* The refusal therefore has to catch a RAW `store.append` and not merely a nested
|
|
18
|
+
* bracket, which is what puts it here rather than in the codec. Enforcing it one
|
|
19
|
+
* layer up would catch a nested bracket and a command runner and miss a direct
|
|
20
|
+
* store call — and a syntactic lint rule cannot close that gap either, having no
|
|
21
|
+
* call graph, so an append one function away in a helper is invisible to both.
|
|
22
|
+
* `makeContractStore` is the one seam every engine's append already passes
|
|
23
|
+
* through, so the check is written once and inherited whole, exactly as
|
|
24
|
+
* `assertServableQuery` is.
|
|
25
|
+
*
|
|
26
|
+
* The cost is real and is accepted: core learns a concept it does not need for its
|
|
27
|
+
* own job. It is affordable because core already owns the write contract, and
|
|
28
|
+
* *"an append is already owned"* is a write-side fact about that contract rather
|
|
29
|
+
* than a fact about the codec.
|
|
30
|
+
*
|
|
31
|
+
* ## Present means refused, so a sanctioned append REMOVES the marker
|
|
32
|
+
*
|
|
33
|
+
* The check reads the service through `Effect.serviceOption`, so its ABSENCE is the
|
|
34
|
+
* normal case and costs the `append` signature nothing — `DcbEventStore.append`
|
|
35
|
+
* keeps `R = never` and no caller provides anything. Presence is what refuses.
|
|
36
|
+
*
|
|
37
|
+
* That shape decides how the two legitimate appends inside a bracket get through,
|
|
38
|
+
* and there is only one route: run with the marker STRIPPED from the context
|
|
39
|
+
* (`Effect.updateContext` over `Context.omit(AppendIsOwned)`). The bracket's own
|
|
40
|
+
* closing append is issued outside the scope it provided the marker in, and the
|
|
41
|
+
* codec's escape hatch strips it explicitly. Neither needs a second service, a
|
|
42
|
+
* sanctioning flag or a mutable cell, and there is no way to be exempt by
|
|
43
|
+
* accident: an append is either lexically outside the marked region or it says in
|
|
44
|
+
* as many words that it is removing the marker.
|
|
45
|
+
*/
|
|
46
|
+
import { Context, Effect } from 'effect';
|
|
47
|
+
declare const AppendIsOwned_base: Context.ServiceClass<AppendIsOwned, "@kairos-es/core/AppendIsOwned", {
|
|
48
|
+
readonly by: string;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Marks that an append is already owned by an enclosing bracket, and names what
|
|
52
|
+
* owns it.
|
|
53
|
+
*
|
|
54
|
+
* `by` is a human-readable owner name and exists for the defect message alone —
|
|
55
|
+
* the refusal is decided by the service's PRESENCE, never by this value, so nothing
|
|
56
|
+
* branches on it and no caller need agree on a vocabulary for it.
|
|
57
|
+
*/
|
|
58
|
+
export declare class AppendIsOwned extends AppendIsOwned_base {
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Die if an append is already owned here; do nothing otherwise.
|
|
62
|
+
*
|
|
63
|
+
* A DEFECT and not an error-channel value, deliberately. There is no
|
|
64
|
+
* data-dependent recovery from it: the events this append would have written
|
|
65
|
+
* belong to a bracket that is going to write its own, so no caller could sensibly
|
|
66
|
+
* catch it and carry on. It is the same class of fault as a non-servable query,
|
|
67
|
+
* and it is refused in the same place and in the same way. The remedy is one
|
|
68
|
+
* identifier away in every case — the codec's `decideOnly` for a command runner,
|
|
69
|
+
* its escape hatch for a deliberate second append — which is what makes a defect
|
|
70
|
+
* affordable here.
|
|
71
|
+
*
|
|
72
|
+
* `Effect.serviceOption` is what keeps this free: it reads the service if present and
|
|
73
|
+
* adds NOTHING to the requirement channel, so every existing append is unchanged
|
|
74
|
+
* and unprovisioned.
|
|
75
|
+
*/
|
|
76
|
+
export declare const assertAppendNotOwned: Effect.Effect<void>;
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=AppendIsOwned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppendIsOwned.d.ts","sourceRoot":"","sources":["../../src/AppendIsOwned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;;iBAYvB,MAAM;;AAVvB;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,kBAGC;CAAG;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAepD,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `makeContractStore` — the shared contract-enforcement POLICY every
|
|
3
|
+
* `DcbEventStore` engine wears, factored out of the engines so the policy is
|
|
4
|
+
* DEFINITIONALLY identical across backends rather than identical by inspection.
|
|
5
|
+
*
|
|
6
|
+
* Each engine implements only the MECHANICS (`RawDcbEventStore`): the actual
|
|
7
|
+
* read/append/subscribe, free to surface infrastructure faults on the error
|
|
8
|
+
* channel (`never` for the pure in-memory engine; `SqlError` for either SQL one).
|
|
9
|
+
* The decorator wraps those mechanics with the policy the contract demands — the
|
|
10
|
+
* policy the first two engines hand-duplicated, with the Postgres one even
|
|
11
|
+
* needing a bespoke `catchAll`/`instanceof` (Effect 3's `catchAll`, which Effect 4
|
|
12
|
+
* names `catch`):
|
|
13
|
+
*
|
|
14
|
+
* - `assertServableQuery` at every verb's entry (read, the append condition's
|
|
15
|
+
* guard query, subscribe) — a non-servable query, or one carrying a key the
|
|
16
|
+
* grammar does not define, is a DEFECT in every engine, and an append condition
|
|
17
|
+
* carrying a key `AppendCondition` does not define is refused alongside it;
|
|
18
|
+
* - `ReadLimit` decode on `read`'s `limit` — a negative/non-integer limit is a
|
|
19
|
+
* DEFECT (so `read` keeps `E = never`), validated through the branded schema
|
|
20
|
+
* even at an untyped boundary that reaches the store as `unknown`;
|
|
21
|
+
* - `orDie` on read/subscribe infrastructure errors — `read`/`subscribe` are
|
|
22
|
+
* `E = never` on the contract, so a raw fault is a defect, not a channel value;
|
|
23
|
+
* - the `AppendConditionFailed`-else-die classification on append, matched by
|
|
24
|
+
* `_tag` and never by class identity — ONLY the contract conflict rides the
|
|
25
|
+
* error channel; every other fault is a defect;
|
|
26
|
+
* - `assertAppendNotOwned` on append — an append inside a bracket that already
|
|
27
|
+
* owns one is a DEFECT. Read `AppendIsOwned.ts` for the rule and for why a
|
|
28
|
+
* write-side concept core does not need for its own job is enforced here.
|
|
29
|
+
*
|
|
30
|
+
* The throws are deferred into the returned Effect/Stream (via `Effect.suspend`
|
|
31
|
+
* / `Effect.sync`), so a validation failure surfaces as a DEFECT WHEN THE EFFECT
|
|
32
|
+
* RUNS — never as a synchronous throw at the call site. This gives the contract
|
|
33
|
+
* suite a single trusted choke point and makes a further backend impossible to get
|
|
34
|
+
* subtly wrong: it supplies mechanics, the policy is inherited whole. That is how
|
|
35
|
+
* the third engine, `@kairos-es/store-sqlite`, acquired the policy — it writes not
|
|
36
|
+
* a line of it.
|
|
37
|
+
*/
|
|
38
|
+
import type { Array as Arr, Scope } from 'effect';
|
|
39
|
+
import { Effect, Stream } from 'effect';
|
|
40
|
+
import { AppendCondition } from './AppendCondition.js';
|
|
41
|
+
import type { DcbEventStore, ReadOptions, ReadResponse } from './DcbEventStore.js';
|
|
42
|
+
import type { DcbEvent, Position, SequencedEvent } from './Event.js';
|
|
43
|
+
import type { AppendConditionFailed } from './errors.js';
|
|
44
|
+
import { type Query } from './Query.js';
|
|
45
|
+
/**
|
|
46
|
+
* The MECHANICS half of a store: the same three verbs as the `DcbEventStore`
|
|
47
|
+
* contract, but free to surface infrastructure faults (`E`) on the error
|
|
48
|
+
* channel. `E` is `never` for a pure engine (in-memory) and e.g. `SqlError` for
|
|
49
|
+
* a database engine. `append` may additionally fail with the contract's
|
|
50
|
+
* `AppendConditionFailed`. `makeContractStore` turns this into the contract.
|
|
51
|
+
*/
|
|
52
|
+
export interface RawDcbEventStore<E> {
|
|
53
|
+
readonly read: (query: Query, options?: ReadOptions) => Effect.Effect<ReadResponse, E>;
|
|
54
|
+
readonly append: (events: Arr.NonEmptyReadonlyArray<DcbEvent>, condition?: AppendCondition) => Effect.Effect<Position, AppendConditionFailed | E>;
|
|
55
|
+
readonly subscribe: (query: Query, after?: Position) => Stream.Stream<SequencedEvent, E, Scope.Scope>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wrap a raw engine's mechanics with the shared contract-enforcement policy,
|
|
59
|
+
* producing a full `DcbEventStore` service value.
|
|
60
|
+
*/
|
|
61
|
+
export declare const makeContractStore: <E>(raw: RawDcbEventStore<E>) => DcbEventStore["Service"];
|
|
62
|
+
//# sourceMappingURL=ContractStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContractStore.d.ts","sourceRoot":"","sources":["../../src/ContractStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,MAAM,EAAqB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAKzD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,CACb,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,WAAW,KAClB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,CACf,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAC3C,SAAS,CAAC,EAAE,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,GAAG,CAAC,CAAC,CAAA;IACvD,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,KAAK,EACZ,KAAK,CAAC,EAAE,QAAQ,KACb,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CACnD;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,KAAK,gBAAgB,CAAC,CAAC,CAAC,KACvB,aAAa,CAAC,SAAS,CAoGxB,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `DcbEventStore` contract: a `Context.Service` with no bundled implementation.
|
|
3
|
+
* Consumers supply a `Layer` (the in-memory one lives in this package; each SQL
|
|
4
|
+
* engine is a package of its own — `@kairos-es/store-postgres` and
|
|
5
|
+
* `@kairos-es/store-sqlite`).
|
|
6
|
+
*
|
|
7
|
+
* Head semantics (ported from `popo.py:62-65`):
|
|
8
|
+
* - `read` with no `limit` => `head` = the global last position (ignoring the
|
|
9
|
+
* query filter) if the store is non-empty, else `ORIGIN` (0n).
|
|
10
|
+
* - `read` with a `limit` => `head` = the last *returned* event's position
|
|
11
|
+
* (post-filter, post-limit), or `ORIGIN` if none returned.
|
|
12
|
+
*
|
|
13
|
+
* `append` returns the last new position (read-your-writes). `subscribe` is
|
|
14
|
+
* catch-up then live and requires a `Scope` so the live subscription is cleaned
|
|
15
|
+
* up on scope close.
|
|
16
|
+
*/
|
|
17
|
+
import type { Array as Arr, Effect, Scope, Stream } from 'effect';
|
|
18
|
+
import { Context } from 'effect';
|
|
19
|
+
import type { AppendCondition } from './AppendCondition.js';
|
|
20
|
+
import type { DcbEvent, Position, ReadLimit, SequencedEvent } from './Event.js';
|
|
21
|
+
import type { AppendConditionFailed } from './errors.js';
|
|
22
|
+
import type { Query } from './Query.js';
|
|
23
|
+
/** Options for a read: a lower position bound and/or a maximum count. */
|
|
24
|
+
export interface ReadOptions {
|
|
25
|
+
/** Only events strictly after this position (exclusive). Absent = from the start. */
|
|
26
|
+
readonly after?: Position;
|
|
27
|
+
/**
|
|
28
|
+
* Cap the number of events returned (a branded non-negative integer). `0`
|
|
29
|
+
* returns none; absent = all matching events. A negative/non-integer value is
|
|
30
|
+
* a defect at the store boundary — see `ReadLimit`.
|
|
31
|
+
*/
|
|
32
|
+
readonly limit?: ReadLimit;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The result of a read: a stream of matching events (ascending by position)
|
|
36
|
+
* plus the consistency `head`.
|
|
37
|
+
*/
|
|
38
|
+
export interface ReadResponse {
|
|
39
|
+
readonly events: Stream.Stream<SequencedEvent>;
|
|
40
|
+
readonly head: Position;
|
|
41
|
+
}
|
|
42
|
+
declare const DcbEventStore_base: Context.ServiceClass<DcbEventStore, "@kairos-es/core/DcbEventStore", {
|
|
43
|
+
/**
|
|
44
|
+
* Read events matching `query` (empty query = all), optionally bounded by
|
|
45
|
+
* `after`/`limit`. See head semantics in the module docs.
|
|
46
|
+
*/
|
|
47
|
+
readonly read: (query: Query, options?: ReadOptions) => Effect.Effect<ReadResponse>;
|
|
48
|
+
/**
|
|
49
|
+
* Append one or more events atomically. If `condition` is given, the append
|
|
50
|
+
* fails with `AppendConditionFailed` when its query matches any event after
|
|
51
|
+
* `condition.after`. Returns the last new position.
|
|
52
|
+
*/
|
|
53
|
+
readonly append: (events: Arr.NonEmptyReadonlyArray<DcbEvent>, condition?: AppendCondition) => Effect.Effect<Position, AppendConditionFailed>;
|
|
54
|
+
/**
|
|
55
|
+
* Subscribe to matching events: first the backlog after `after` (catch-up),
|
|
56
|
+
* then live events as they are appended. Scoped: the live subscription is
|
|
57
|
+
* released when the scope closes.
|
|
58
|
+
*/
|
|
59
|
+
readonly subscribe: (query: Query, after?: Position) => Stream.Stream<SequencedEvent, never, Scope.Scope>;
|
|
60
|
+
}>;
|
|
61
|
+
export declare class DcbEventStore extends DcbEventStore_base {
|
|
62
|
+
}
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=DcbEventStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DcbEventStore.d.ts","sourceRoot":"","sources":["../../src/DcbEventStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC9C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CACxB;;IAKG;;;OAGG;mBACY,CACb,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,WAAW,KAClB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;IAEhC;;;;OAIG;qBACc,CACf,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAC3C,SAAS,CAAC,EAAE,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IAEnD;;;;OAIG;wBACiB,CAClB,KAAK,EAAE,KAAK,EACZ,KAAK,CAAC,EAAE,QAAQ,KACb,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;;AA9B1D,qBAAa,aAAc,SAAQ,kBAgCC;CAAG"}
|