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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/AppendCondition.js +1 -3
  3. package/dist/cjs/AppendCondition.js.map +1 -1
  4. package/dist/cjs/AppendIsOwned.js +6 -6
  5. package/dist/cjs/AppendIsOwned.js.map +1 -1
  6. package/dist/cjs/ContractStore.js +2 -2
  7. package/dist/cjs/ContractStore.js.map +1 -1
  8. package/dist/cjs/DcbEventStore.js +1 -1
  9. package/dist/cjs/DcbEventStore.js.map +1 -1
  10. package/dist/cjs/Event.js +29 -13
  11. package/dist/cjs/Event.js.map +1 -1
  12. package/dist/cjs/Query.js +1 -1
  13. package/dist/cjs/Query.js.map +1 -1
  14. package/dist/cjs/SubscribeMachine.js +158 -67
  15. package/dist/cjs/SubscribeMachine.js.map +1 -1
  16. package/dist/cjs/inMemory.js +4 -4
  17. package/dist/cjs/inMemory.js.map +1 -1
  18. package/dist/cjs/retryOnConflict.js +4 -10
  19. package/dist/cjs/retryOnConflict.js.map +1 -1
  20. package/dist/cjs/testing.js +2 -2
  21. package/dist/cjs/testing.js.map +1 -1
  22. package/dist/{dts → dts-cjs}/AppendCondition.d.ts +5 -7
  23. package/dist/{dts → dts-cjs}/AppendCondition.d.ts.map +1 -1
  24. package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts +6 -6
  25. package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts.map +1 -1
  26. package/dist/{dts → dts-cjs}/ContractStore.d.ts +3 -2
  27. package/dist/dts-cjs/ContractStore.d.ts.map +1 -0
  28. package/dist/{dts → dts-cjs}/DcbEventStore.d.ts +2 -2
  29. package/dist/{dts → dts-cjs}/DcbEventStore.d.ts.map +1 -1
  30. package/dist/{dts → dts-cjs}/Event.d.ts +31 -20
  31. package/dist/dts-cjs/Event.d.ts.map +1 -0
  32. package/dist/{dts → dts-cjs}/Query.d.ts +5 -5
  33. package/dist/dts-cjs/SubscribeMachine.d.ts +289 -0
  34. package/dist/dts-cjs/SubscribeMachine.d.ts.map +1 -0
  35. package/dist/{dts → dts-cjs}/inMemory.d.ts.map +1 -1
  36. package/dist/{dts → dts-cjs}/index.d.ts +1 -1
  37. package/dist/dts-cjs/package.json +3 -0
  38. package/dist/{dts → dts-cjs}/retryOnConflict.d.ts +1 -7
  39. package/dist/dts-cjs/retryOnConflict.d.ts.map +1 -0
  40. package/dist/{dts → dts-cjs}/testing.d.ts +1 -1
  41. package/dist/dts-esm/AppendCondition.d.ts +21 -0
  42. package/dist/dts-esm/AppendCondition.d.ts.map +1 -0
  43. package/dist/dts-esm/AppendIsOwned.d.ts +78 -0
  44. package/dist/dts-esm/AppendIsOwned.d.ts.map +1 -0
  45. package/dist/dts-esm/ContractStore.d.ts +62 -0
  46. package/dist/dts-esm/ContractStore.d.ts.map +1 -0
  47. package/dist/dts-esm/DcbEventStore.d.ts +64 -0
  48. package/dist/dts-esm/DcbEventStore.d.ts.map +1 -0
  49. package/dist/dts-esm/Event.d.ts +174 -0
  50. package/dist/dts-esm/Event.d.ts.map +1 -0
  51. package/dist/dts-esm/Projection.d.ts +124 -0
  52. package/dist/dts-esm/Projection.d.ts.map +1 -0
  53. package/dist/dts-esm/Query.d.ts +180 -0
  54. package/dist/dts-esm/Query.d.ts.map +1 -0
  55. package/dist/dts-esm/SubscribeMachine.d.ts +289 -0
  56. package/dist/dts-esm/SubscribeMachine.d.ts.map +1 -0
  57. package/dist/dts-esm/errors.d.ts +17 -0
  58. package/dist/dts-esm/errors.d.ts.map +1 -0
  59. package/dist/dts-esm/inMemory.d.ts +76 -0
  60. package/dist/dts-esm/inMemory.d.ts.map +1 -0
  61. package/dist/dts-esm/index.d.ts +40 -0
  62. package/dist/dts-esm/index.d.ts.map +1 -0
  63. package/dist/dts-esm/package.json +3 -0
  64. package/dist/dts-esm/retryOnConflict.d.ts +64 -0
  65. package/dist/dts-esm/retryOnConflict.d.ts.map +1 -0
  66. package/dist/dts-esm/testing.d.ts +39 -0
  67. package/dist/dts-esm/testing.d.ts.map +1 -0
  68. package/dist/esm/AppendCondition.js +1 -3
  69. package/dist/esm/AppendCondition.js.map +1 -1
  70. package/dist/esm/AppendIsOwned.js +6 -6
  71. package/dist/esm/AppendIsOwned.js.map +1 -1
  72. package/dist/esm/ContractStore.js +2 -2
  73. package/dist/esm/ContractStore.js.map +1 -1
  74. package/dist/esm/DcbEventStore.js +1 -1
  75. package/dist/esm/DcbEventStore.js.map +1 -1
  76. package/dist/esm/Event.js +30 -14
  77. package/dist/esm/Event.js.map +1 -1
  78. package/dist/esm/Query.js +1 -1
  79. package/dist/esm/Query.js.map +1 -1
  80. package/dist/esm/SubscribeMachine.js +157 -67
  81. package/dist/esm/SubscribeMachine.js.map +1 -1
  82. package/dist/esm/inMemory.js +5 -5
  83. package/dist/esm/inMemory.js.map +1 -1
  84. package/dist/esm/index.js +1 -1
  85. package/dist/esm/retryOnConflict.js +4 -10
  86. package/dist/esm/retryOnConflict.js.map +1 -1
  87. package/dist/esm/testing.js +2 -2
  88. package/dist/esm/testing.js.map +1 -1
  89. package/package.json +21 -11
  90. package/src/AppendCondition.ts +1 -1
  91. package/src/AppendIsOwned.ts +7 -7
  92. package/src/ContractStore.ts +5 -4
  93. package/src/DcbEventStore.ts +3 -3
  94. package/src/Event.ts +49 -14
  95. package/src/Query.ts +1 -1
  96. package/src/SubscribeMachine.ts +278 -96
  97. package/src/inMemory.ts +6 -6
  98. package/src/index.ts +1 -1
  99. package/src/retryOnConflict.ts +6 -11
  100. package/src/testing.ts +2 -2
  101. package/testing/package.json +1 -1
  102. package/dist/dts/ContractStore.d.ts.map +0 -1
  103. package/dist/dts/Event.d.ts.map +0 -1
  104. package/dist/dts/SubscribeMachine.d.ts +0 -179
  105. package/dist/dts/SubscribeMachine.d.ts.map +0 -1
  106. package/dist/dts/retryOnConflict.d.ts.map +0 -1
  107. /package/dist/{dts → dts-cjs}/Projection.d.ts +0 -0
  108. /package/dist/{dts → dts-cjs}/Projection.d.ts.map +0 -0
  109. /package/dist/{dts → dts-cjs}/Query.d.ts.map +0 -0
  110. /package/dist/{dts → dts-cjs}/errors.d.ts +0 -0
  111. /package/dist/{dts → dts-cjs}/errors.d.ts.map +0 -0
  112. /package/dist/{dts → dts-cjs}/inMemory.d.ts +0 -0
  113. /package/dist/{dts → dts-cjs}/index.d.ts.map +0 -0
  114. /package/dist/{dts → dts-cjs}/testing.d.ts.map +0 -0
@@ -5,6 +5,15 @@
5
5
  * the cursor's exclusive lower bound) and the poll loop that together turn a paged
6
6
  * read into a live subscription.
7
7
  *
8
+ * The algorithm is `subscribeItems`, generic over the item `A` it delivers and the
9
+ * cursor `C` it resumes from, because nothing in it is about an event: any source
10
+ * that can page-read strictly after a cursor and name the cursor of what it
11
+ * returned is subscribable by the same loop. `subscribeStream` is the event-store
12
+ * shape — `SequencedEvent` ordered by `Position` — over the same loop, and it is
13
+ * what every engine calls, unchanged by the generalisation. A second kind of
14
+ * source reuses the loop rather than growing a second one, for the reason the next
15
+ * paragraph gives.
16
+ *
8
17
  * It lives in core because delivery semantics are contract semantics. An engine
9
18
  * supplies TRANSPORT through two STUBBABLE seams — `fetch`, a paged read strictly
10
19
  * after a cursor, and `listen`, an optional wake source — and inherits the delivery
@@ -15,48 +24,52 @@
15
24
  * Both seams take plain in-memory values in a test, so the wake/poll/de-dup logic
16
25
  * is exercisable with no live backend at all.
17
26
  *
18
- * All THREE are the callers, and the count matters to a reader here: it means there
19
- * is exactly ONE delivery algorithm in this repo, and it is the code below. The
27
+ * All THREE engines are callers, and the count matters to a reader here: it means
28
+ * there is exactly ONE delivery algorithm in this repo, and it is the code below. The
20
29
  * in-memory store is a caller like the rest — it hands in a `fetch` over its log
21
30
  * `Ref` and its append `PubSub` as a wake source and keeps no delivery logic of its
22
31
  * own — which is what makes the shared contract suite's subscribe cases a comparison
23
32
  * of two BACKENDS rather than of two delivery algorithms.
24
33
  *
25
- * Correctness rests on the periodic position-based reconcile — a re-read from the
34
+ * Correctness rests on the periodic cursor-based reconcile — a re-read from the
26
35
  * cursor every poll interval — and NEVER on the wake source, which only lowers
27
36
  * delivery latency below that interval. A subscription with no wake source at all
28
37
  * is therefore complete and correct, merely slower, which is why `listen` is
29
38
  * optional in the TYPE rather than by the convention of passing `Stream.never`:
30
39
  * poll-only delivery is a supported shape, not a degraded one.
31
40
  *
32
- * ## The precondition every engine inherits: ASCENDING COMMIT ORDER
41
+ * ## The precondition every caller inherits: ASCENDING COMMIT ORDER
33
42
  *
34
- * A position that is committed and VISIBLE must never be below one already
35
- * delivered. Gaps are fine: the cursor is an ascending exclusive lower bound, so a
36
- * number that is allocated and never committed, or never allocated at all, is
37
- * simply a number the machine never sees. Out-of-order commits are not fine. If one
43
+ * It binds EVERY caller, over whatever cursor it chose — an engine's `Position`, or
44
+ * any other `C` handed to `subscribeItems` — and the example below is written in
45
+ * positions only because the engines are the callers it was first written for. A
46
+ * cursor that is committed and VISIBLE must never be below one already delivered.
47
+ * Gaps are fine: the cursor is an ascending exclusive lower bound, so a number
48
+ * that is allocated and never committed, or never allocated at all, is simply a
49
+ * number the machine never sees. Out-of-order commits are not fine. If one
38
50
  * writer allocates position 5 and another allocates 6, and 6 commits first, a poll
39
51
  * landing between the two commits delivers 6 and advances the cursor past it — and
40
52
  * 5 is then lost forever, because no later read looks below the cursor and nothing
41
- * anywhere notices the hole. An engine whose concurrent writers can commit out of
53
+ * anywhere notices the hole. A caller whose concurrent writers can commit out of
42
54
  * order MUST serialise them, or this machine will silently skip. An engine that
43
55
  * takes an exclusive lock on both of its append paths discharges the obligation
44
56
  * that way; an engine whose append is a single statement discharges it
45
57
  * structurally.
46
58
  *
47
59
  * The obligation is written down HERE, in the algorithm that depends on it, rather
48
- * than in whichever engine happens to satisfy it. It is a property of this delivery
49
- * loop and of nothing else, so an engine author reading only their own source has
60
+ * than in whichever caller happens to satisfy it. It is a property of this delivery
61
+ * loop and of nothing else, so an author reading only their own source has
50
62
  * no way to discover that anything downstream needs it — and the failure mode is
51
63
  * the worst kind there is: no error, no defect, no failing test, just an event that
52
64
  * a subscriber never receives. A single engine owning both its append path and its
53
65
  * own wake loop can leave the assumption implicit; a shared machine cannot.
54
66
  *
55
- * ## `catchUpPageSize` bounds the READ, not the emission
67
+ * ## `catchUpPageSize` bounds the READ, not the emission — unless `emit: 'page'`
56
68
  *
57
- * `drainFrom` below PAGES the catch-up read — `catchUpPageSize` bounds each
58
- * `fetch` — but it COLLECTS every page into one array, which is emitted as a SINGLE
59
- * chunk. So peak memory at subscription start is O(backlog) rather than O(page): a
69
+ * Under the default `emit: 'backlog'`, which is what `subscribeStream` and so every
70
+ * engine uses, `drainFrom` below PAGES the catch-up read — `catchUpPageSize` bounds
71
+ * each `fetch` — but it COLLECTS every page into one array, which is emitted as a
72
+ * SINGLE chunk. So peak memory at subscription start is O(backlog) rather than O(page): a
60
73
  * subscriber joining behind a large log materialises the whole backlog before its
61
74
  * consumer sees the first element.
62
75
  *
@@ -67,8 +80,21 @@
67
80
  * stay small even against a one-chunk catch-up. The cost therefore lands on backlog
68
81
  * memory alone, and it lands hardest on the durable-log-with-in-memory-view mode,
69
82
  * where an ephemeral view re-catches-up the entire log on every boot.
83
+ *
84
+ * `emit: 'page'` changes exactly that and nothing else. Each fetched page is
85
+ * emitted as its own chunk and the cursor advances past it before the next read, so
86
+ * peak memory is O(page) and the consumer sees the first item after ONE read rather
87
+ * than after the whole backlog. Delivery is unchanged: the same items in the same
88
+ * order, the same de-dup, the same wake and poll. What a caller gives up is the
89
+ * one-chunk catch-up, so it must not read meaning into chunk boundaries under
90
+ * either mode. It is for a consumer that does NOT re-chunk downstream and whose
91
+ * catch-up can be the whole of a large source — a full resync of a table, say —
92
+ * where holding the backlog would be the cost the paging was meant to avoid. The
93
+ * engines keep `'backlog'` because the read side's re-chunking already bounds what
94
+ * they commit, and changing their emission would move a behaviour nobody asked to
95
+ * move.
70
96
  */
71
- import { Chunk, Effect, Option, Queue, Schedule, Schema, Stream } from 'effect';
97
+ import { Effect, Option, Queue, Schedule, Schema, Stream } from 'effect';
72
98
  import { ORIGIN, ReadLimit } from "./Event.js";
73
99
  /**
74
100
  * A short catch-up page size default for the reconcile loop. Reads page by page
@@ -95,6 +121,10 @@ export const DEFAULT_CATCH_UP_PAGE_SIZE = 512;
95
121
  * one-second fallback poll (`conn.wait(..., interval=1)`).
96
122
  */
97
123
  export const DEFAULT_POLL_INTERVAL_MILLIS = 1000;
124
+ /** A usable `pollInterval`: see `subscriptionTuningFields` for the bounds' argument. */
125
+ const PollIntervalMillis = /*#__PURE__*/Schema.Number.check(/*#__PURE__*/Schema.isGreaterThan(0), /*#__PURE__*/Schema.isFinite());
126
+ /** A usable `catchUpPageSize`: see `subscriptionTuningFields` for the bounds' argument. */
127
+ const CatchUpPageSize = /*#__PURE__*/Schema.Int.check(/*#__PURE__*/Schema.isGreaterThan(0));
98
128
  /**
99
129
  * The two subscribe-tuning config FIELDS, for an engine whose config is a `Schema`
100
130
  * to spread into its own struct.
@@ -107,12 +137,12 @@ export const DEFAULT_POLL_INTERVAL_MILLIS = 1000;
107
137
  * the key NAME, the VALIDATION and the DEFAULT from one place, so a caller who has
108
138
  * tuned one engine's subscribe reads another's without translating, and the two
109
139
  * cannot drift in what they ACCEPT any more than in what they assume. Two engines
110
- * hand-authoring the identical `Schema.optionalWith(…)` twice were identical only
140
+ * hand-authoring the identical `Schema.optionalKey(…)` twice were identical only
111
141
  * by inspection.
112
142
  *
113
143
  * The bounds differ between the two because the quantities do. `pollInterval` is a
114
- * duration, so a fraction of a millisecond is meaningful and only `positive` and
115
- * `finite` matter: at zero or below the loop would spin without ever waiting for a
144
+ * duration, so a fraction of a millisecond is meaningful and only `isGreaterThan(0)`
145
+ * and `isFinite` matter: at zero or below the loop would spin without ever waiting for a
116
146
  * wake, and at `Infinity` the periodic re-read — the half that carries delivery —
117
147
  * would never come, which silently converts the wake source from an optimisation
118
148
  * into the guarantee. `catchUpPageSize` is a COUNT, so it must be an integer
@@ -120,17 +150,29 @@ export const DEFAULT_POLL_INTERVAL_MILLIS = 1000;
120
150
  * length against it to decide the tail is drained, and a page of zero would report
121
151
  * "drained" forever without reading anything.
122
152
  *
123
- * `exact: true` on both keeps the decoded type at `key?: T` rather than
153
+ * `optionalKey` on both keeps the decoded type at `key?: T` rather than
124
154
  * `T | undefined`, matching the repo's `exactOptionalPropertyTypes` discipline — an
125
155
  * absent key, never an explicit `undefined`.
126
156
  */
127
157
  export const subscriptionTuningFields = {
128
- pollInterval: /*#__PURE__*/Schema.optionalWith(/*#__PURE__*/Schema.Number.pipe(/*#__PURE__*/Schema.positive(), /*#__PURE__*/Schema.finite()), {
129
- exact: true
130
- }),
131
- catchUpPageSize: /*#__PURE__*/Schema.optionalWith(/*#__PURE__*/Schema.Int.pipe(/*#__PURE__*/Schema.positive()), {
132
- exact: true
133
- })
158
+ pollInterval: /*#__PURE__*/Schema.optionalKey(PollIntervalMillis),
159
+ catchUpPageSize: /*#__PURE__*/Schema.optionalKey(CatchUpPageSize)
160
+ };
161
+ /**
162
+ * Why a caller-supplied tuning knob is unusable, naming the field and the value, or
163
+ * `undefined` when both are usable or absent. It judges with the SAME two schemas
164
+ * the config fields are built from, so `subscribeItems`, whose caller may have no
165
+ * config to decode, accepts exactly what an engine's config accepts and the bounds
166
+ * have one home.
167
+ */
168
+ const tuningFault = deps => {
169
+ if (deps.pollInterval !== undefined && !Schema.is(PollIntervalMillis)(deps.pollInterval)) {
170
+ return `subscribeItems: pollInterval must be a finite number of milliseconds greater than 0, got ${deps.pollInterval}`;
171
+ }
172
+ if (deps.catchUpPageSize !== undefined && !Schema.is(CatchUpPageSize)(deps.catchUpPageSize)) {
173
+ return `subscribeItems: catchUpPageSize must be an integer greater than 0, got ${deps.catchUpPageSize}`;
174
+ }
175
+ return undefined;
134
176
  };
135
177
  /**
136
178
  * Retry a TRANSIENT poll fault (an `E` from one reconcile read) on a capped
@@ -139,16 +181,41 @@ export const subscriptionTuningFields = {
139
181
  * past the cap propagates (the decorator dies it) — infrastructure stays off the
140
182
  * contract channel while the stream survives ordinary transients.
141
183
  */
142
- const POLL_RETRY_SCHEDULE = /*#__PURE__*/Schedule.exponential('100 millis', 2).pipe(/*#__PURE__*/Schedule.union(/*#__PURE__*/Schedule.spaced('2 seconds')), /*#__PURE__*/Schedule.intersect(/*#__PURE__*/Schedule.recurs(20)));
184
+ const POLL_RETRY_SCHEDULE = /*#__PURE__*/Schedule.max([/*#__PURE__*/Schedule.min([/*#__PURE__*/Schedule.exponential('100 millis', 2), /*#__PURE__*/Schedule.spaced('2 seconds')]), /*#__PURE__*/Schedule.recurs(20)]);
185
+ /**
186
+ * Build a subscription `Stream` over any ascending-cursor source: catch up from
187
+ * `initial`, then track the live tail. The cursor threads through the
188
+ * `Stream.paginate` state, starting at `initial` and advancing to the cursor of the
189
+ * last delivered item each batch; the stream never completes on its own (the next
190
+ * state is always `Option.some`), so the enclosing scope interrupts it on close. An
191
+ * `E` mid-stream stays on the channel, for the caller to die or to supervise.
192
+ *
193
+ * This is THE delivery algorithm, and `subscribeStream` runs the same machine. Under
194
+ * `emit: 'backlog'` a batch is everything a drain to the tail returned; under
195
+ * `'page'` it is one fetched page, so the paginate step and the page coincide and a
196
+ * full page is followed at once by the next read rather than by a wait.
197
+ *
198
+ * A `pollInterval` or `catchUpPageSize` the config fields would refuse is a DEFECT
199
+ * here, raised by the stream before it reads or forks anything, with a message
200
+ * naming the field. This caller may have no config whose decode would have caught
201
+ * it, and unchecked the two failures are silent or late: a page size of 0 gives a
202
+ * stream that never emits and never fails, and 1.5 dies only at the first read,
203
+ * inside `ReadLimit`, in words that name neither knob.
204
+ */
205
+ export const subscribeItems = deps => {
206
+ const fault = tuningFault(deps);
207
+ return fault === undefined ? machine(deps) : Stream.die(new Error(fault));
208
+ };
143
209
  /**
144
- * Build the subscription `Stream`: catch up from `after`, then track the live tail.
145
- * The cursor threads through the `unfoldChunkEffect` unfold state, starting at
146
- * `after` and advancing to the last delivered position each batch; the stream never
147
- * completes on its own (always `Option.some`), so the enclosing scope interrupts it
148
- * on close. An `E` mid-stream stays on the channel; `makeContractStore` dies it
149
- * (subscribe is `E = never` on the contract).
210
+ * The machine itself, with no check of its tuning. `subscribeStream` runs it
211
+ * directly, and deliberately: the event path stays exactly as it was, with no
212
+ * second check of figures each SQL engine has already decoded from its config
213
+ * through the same bounds, and the in-memory store's are a test's own options.
150
214
  */
151
- export const subscribeStream = (deps, after) => Stream.unwrapScoped(Effect.gen(function* () {
215
+ const machine = deps => Stream.unwrap(Effect.gen(function* () {
216
+ const pageSize = deps.catchUpPageSize ?? DEFAULT_CATCH_UP_PAGE_SIZE;
217
+ const pollInterval = deps.pollInterval ?? DEFAULT_POLL_INTERVAL_MILLIS;
218
+ const limit = ReadLimit.make(pageSize);
152
219
  // The wake primitive: a sliding(1) queue holding at most one pending
153
220
  // signal. The wake source `offer`s an opaque wake on every notification;
154
221
  // the poll loop `take`s (with a timeout). The lost-wakeup guard is
@@ -164,64 +231,87 @@ export const subscribeStream = (deps, after) => Stream.unwrapScoped(Effect.gen(f
164
231
  // silently-dropped (and later re-established) wake source loses no
165
232
  // positions. Absent a wake source entirely, `Stream.never` makes this a
166
233
  // fibre that parks forever and delivery falls to the poll alone.
167
- const listener = (deps.listen ?? Stream.never).pipe(Stream.tap(() => Queue.offer(wake, undefined)), Stream.retry(Schedule.exponential('50 millis').pipe(Schedule.union(Schedule.spaced('1 seconds')))));
234
+ const listener = (deps.listen ?? Stream.never).pipe(Stream.tap(() => Queue.offer(wake, undefined)), Stream.retry(Schedule.min([Schedule.exponential('50 millis'), Schedule.spaced('1 seconds')])));
168
235
  // Drain the wake source into the wake queue on a background fibre; the
169
236
  // scope releases it. We never read its elements directly — every
170
237
  // notification is an opaque wake signal.
171
238
  yield* listener.pipe(Stream.runDrain, Effect.forkScoped);
239
+ // One page strictly after `from`: the step `drainFrom` loops, and the whole
240
+ // of a `'page'` read.
241
+ const fetchPage = from => deps.fetch(from, limit);
172
242
  // Reconcile: page-read from `from` until a short page, advancing to the last
173
- // delivered position. Retries a TRANSIENT poll fault on a capped schedule so
243
+ // delivered cursor. Retries a TRANSIENT poll fault on a capped schedule so
174
244
  // a single connection blip does not kill a days-long subscription; a
175
- // persistent fault propagates and dies.
245
+ // persistent fault propagates. The retry wraps the WHOLE drain, so a fault on
246
+ // page three re-reads pages one and two: nothing has been emitted yet, so
247
+ // that costs reads and never a duplicate.
176
248
  const drainFrom = from => Effect.gen(function* () {
177
249
  const collected = [];
178
250
  let cursor = from;
179
251
  // Loop pages until a short page signals the tail is drained.
180
252
  while (true) {
181
- const events = yield* deps.fetch(cursor, ReadLimit.make(deps.catchUpPageSize));
182
- for (const event of events) {
183
- collected.push(event);
253
+ const items = yield* fetchPage(cursor);
254
+ for (const item of items) {
255
+ collected.push(item);
184
256
  }
185
- const lastEvent = events.at(-1);
186
- if (lastEvent === undefined || events.length < deps.catchUpPageSize) {
257
+ const lastItem = items.at(-1);
258
+ if (lastItem === undefined || items.length < pageSize) {
187
259
  break;
188
260
  }
189
- cursor = lastEvent.position;
261
+ cursor = deps.cursorOf(lastItem);
190
262
  }
191
- const last = collected.at(-1)?.position ?? from;
192
- return {
193
- events: collected,
194
- last
195
- };
263
+ return collected;
196
264
  }).pipe(Effect.retry(POLL_RETRY_SCHEDULE));
265
+ // The read one paginate step performs, by emission mode. Under `'page'` the
266
+ // retry wraps the single page, which is the whole of what is unemitted.
267
+ const read = (deps.emit ?? 'backlog') === 'page' ? from => fetchPage(from).pipe(Effect.retry(POLL_RETRY_SCHEDULE)) : drainFrom;
197
268
  /**
198
- * Produce the NEXT non-empty batch from a cursor position, together with
199
- * the advanced cursor — a pure `Position → Effect<[Chunk, next]>`. The
200
- * `> boundary` de-dup is enforced by `fetch`'s exclusive lower bound, so a
201
- * live re-read after a wake never re-emits an already-delivered position.
269
+ * Produce the NEXT non-empty batch from a cursor, together with the advanced
270
+ * cursor — a pure `C → Effect<[items, next]>`. The `> boundary` de-dup is
271
+ * enforced by `fetch`'s exclusive lower bound, so a live re-read after a wake
272
+ * never re-emits an already-delivered item.
202
273
  *
203
- * Drain the wake queue BEFORE reading (lost-wakeup guard), then drain from
204
- * the cursor. If a drain yields nothing, wait for a wake but only up to the
205
- * poll interval, then loop and re-read ANYWAY — the periodic position-based
206
- * poll that makes delivery correct independently of any wake. This effect
207
- * only completes by returning a non-empty chunk; the scope interrupts it on
208
- * close.
274
+ * Drain the wake queue BEFORE reading (lost-wakeup guard), then read from the
275
+ * cursor. If a read yields nothing, wait for a wake but only up to the poll
276
+ * interval, then loop and re-read ANYWAY — the periodic cursor-based poll that
277
+ * makes delivery correct independently of any wake. This effect only
278
+ * completes by returning a non-empty batch; the scope interrupts it on close.
209
279
  */
210
280
  const nextBatch = from => Effect.gen(function* () {
211
281
  while (true) {
212
- yield* Queue.takeAll(wake);
213
- const {
214
- events,
215
- last
216
- } = yield* drainFrom(from);
217
- if (events.length > 0) {
218
- return [Chunk.fromIterable(events), last];
282
+ // `Queue.clear` and not `Queue.takeAll`: the drain must NOT wait, and
283
+ // `takeAll` suspends until at least one signal is present.
284
+ yield* Queue.clear(wake);
285
+ const items = yield* read(from);
286
+ const last = items.at(-1);
287
+ if (last !== undefined) {
288
+ return [items, deps.cursorOf(last)];
219
289
  }
220
290
  // Nothing new: block on a wake, but only up to the poll interval — on
221
291
  // timeout we fall through and the loop re-reads regardless.
222
- yield* Effect.ignore(Effect.timeout(Queue.take(wake), deps.pollInterval));
292
+ yield* Effect.ignore(Effect.timeout(Queue.take(wake), pollInterval));
223
293
  }
224
294
  });
225
- return Stream.unfoldChunkEffect(after ?? ORIGIN, from => Effect.map(nextBatch(from), Option.some));
295
+ return Stream.paginate(deps.initial, from => Effect.map(nextBatch(from), ([items, next]) => [items, Option.some(next)]));
226
296
  }));
297
+ /**
298
+ * Build the event subscription `Stream`: catch up from `after`, then track the live
299
+ * tail. A THIN wrapper over the machine `subscribeItems` runs, fixing the item to
300
+ * `SequencedEvent`, the cursor to its `position`, the start to `ORIGIN` when `after`
301
+ * is absent, and the emission to the default `'backlog'` — so every engine's call
302
+ * site, and every figure it delivers, is what it was before the machine became
303
+ * generic. It skips `subscribeItems`' tuning check, for the reason on `machine`. An `E`
304
+ * mid-stream stays on the channel; `makeContractStore` dies it (subscribe is
305
+ * `E = never` on the contract).
306
+ */
307
+ export const subscribeStream = (deps, after) => machine({
308
+ fetch: deps.fetch,
309
+ cursorOf: event => event.position,
310
+ initial: after ?? ORIGIN,
311
+ ...(deps.listen === undefined ? {} : {
312
+ listen: deps.listen
313
+ }),
314
+ pollInterval: deps.pollInterval,
315
+ catchUpPageSize: deps.catchUpPageSize
316
+ });
227
317
  //# sourceMappingURL=SubscribeMachine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SubscribeMachine.js","names":["Chunk","Effect","Option","Queue","Schedule","Schema","Stream","ORIGIN","ReadLimit","DEFAULT_CATCH_UP_PAGE_SIZE","DEFAULT_POLL_INTERVAL_MILLIS","subscriptionTuningFields","pollInterval","optionalWith","Number","pipe","positive","finite","exact","catchUpPageSize","Int","POLL_RETRY_SCHEDULE","exponential","union","spaced","intersect","recurs","subscribeStream","deps","after","unwrapScoped","gen","wake","sliding","listener","listen","never","tap","offer","undefined","retry","runDrain","forkScoped","drainFrom","from","collected","cursor","events","fetch","make","event","push","lastEvent","at","length","position","last","nextBatch","takeAll","fromIterable","ignore","timeout","take","unfoldChunkEffect","map","some"],"sources":["../../src/SubscribeMachine.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"SubscribeMachine.js","names":["Effect","Option","Queue","Schedule","Schema","Stream","ORIGIN","ReadLimit","DEFAULT_CATCH_UP_PAGE_SIZE","DEFAULT_POLL_INTERVAL_MILLIS","PollIntervalMillis","Number","check","isGreaterThan","isFinite","CatchUpPageSize","Int","subscriptionTuningFields","pollInterval","optionalKey","catchUpPageSize","tuningFault","deps","undefined","is","POLL_RETRY_SCHEDULE","max","min","exponential","spaced","recurs","subscribeItems","fault","machine","die","Error","unwrap","gen","pageSize","limit","make","wake","sliding","listener","listen","never","pipe","tap","offer","retry","runDrain","forkScoped","fetchPage","from","fetch","drainFrom","collected","cursor","items","item","push","lastItem","at","length","cursorOf","read","emit","nextBatch","clear","last","ignore","timeout","take","paginate","initial","map","next","some","subscribeStream","after","event","position"],"sources":["../../src/SubscribeMachine.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgGA,SACEA,MAAM,EACNC,MAAM,EACNC,KAAK,EACLC,QAAQ,EACRC,MAAM,EAENC,MAAM,QACD,QAAQ;AAEf,SAASC,MAAM,EAAEC,SAAS,QAAQ,YAAS;AAE3C;;;;;;;AAOA,OAAO,MAAMC,0BAA0B,GAAG,GAAG;AAE7C;;;;;;;;;;;;;;;;AAgBA,OAAO,MAAMC,4BAA4B,GAAG,IAAI;AAEhD;AACA,MAAMC,kBAAkB,gBAAGN,MAAM,CAACO,MAAM,CAACC,KAAK,cAC5CR,MAAM,CAACS,aAAa,CAAC,CAAC,CAAC,eACvBT,MAAM,CAACU,QAAQ,EAAE,CAClB;AAED;AACA,MAAMC,eAAe,gBAAGX,MAAM,CAACY,GAAG,CAACJ,KAAK,cAACR,MAAM,CAACS,aAAa,CAAC,CAAC,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,OAAO,MAAMI,wBAAwB,GAAG;EACtCC,YAAY,eAAEd,MAAM,CAACe,WAAW,CAACT,kBAAkB,CAAC;EACpDU,eAAe,eAAEhB,MAAM,CAACe,WAAW,CAACJ,eAAe;CAC3C;AAEV;;;;;;;AAOA,MAAMM,WAAW,GAAIC,IAGpB,IAAwB;EACvB,IACEA,IAAI,CAACJ,YAAY,KAAKK,SAAS,IAC/B,CAACnB,MAAM,CAACoB,EAAE,CAACd,kBAAkB,CAAC,CAACY,IAAI,CAACJ,YAAY,CAAC,EACjD;IACA,OAAO,4FAA4FI,IAAI,CAACJ,YAAY,EAAE;EACxH;EACA,IACEI,IAAI,CAACF,eAAe,KAAKG,SAAS,IAClC,CAACnB,MAAM,CAACoB,EAAE,CAACT,eAAe,CAAC,CAACO,IAAI,CAACF,eAAe,CAAC,EACjD;IACA,OAAO,0EAA0EE,IAAI,CAACF,eAAe,EAAE;EACzG;EACA,OAAOG,SAAS;AAClB,CAAC;AAED;;;;;;;AAOA,MAAME,mBAAmB,gBAAGtB,QAAQ,CAACuB,GAAG,CAAC,cACvCvB,QAAQ,CAACwB,GAAG,CAAC,cACXxB,QAAQ,CAACyB,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,eACrCzB,QAAQ,CAAC0B,MAAM,CAAC,WAAW,CAAC,CAC7B,CAAC,eACF1B,QAAQ,CAAC2B,MAAM,CAAC,EAAE,CAAC,CACpB,CAAC;AA8GF;;;;;;;;;;;;;;;;;;;;AAoBA,OAAO,MAAMC,cAAc,GACzBT,IAAmC,IACC;EACpC,MAAMU,KAAK,GAAGX,WAAW,CAACC,IAAI,CAAC;EAC/B,OAAOU,KAAK,KAAKT,SAAS,GAAGU,OAAO,CAACX,IAAI,CAAC,GAAGjB,MAAM,CAAC6B,GAAG,CAAC,IAAIC,KAAK,CAACH,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;AAMA,MAAMC,OAAO,GACXX,IAAmC,IAEnCjB,MAAM,CAAC+B,MAAM,CACXpC,MAAM,CAACqC,GAAG,CAAC,aAAS;EAClB,MAAMC,QAAQ,GAAGhB,IAAI,CAACF,eAAe,IAAIZ,0BAA0B;EACnE,MAAMU,YAAY,GAAGI,IAAI,CAACJ,YAAY,IAAIT,4BAA4B;EACtE,MAAM8B,KAAK,GAAGhC,SAAS,CAACiC,IAAI,CAACF,QAAQ,CAAC;EAEtC;EACA;EACA;EACA;EACA;EACA;EACA,MAAMG,IAAI,GAAG,OAAOvC,KAAK,CAACwC,OAAO,CAAO,CAAC,CAAC;EAE1C;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,QAAQ,GAAG,CAACrB,IAAI,CAACsB,MAAM,IAAIvC,MAAM,CAACwC,KAAK,EAAEC,IAAI,CACjDzC,MAAM,CAAC0C,GAAG,CAAC,MAAM7C,KAAK,CAAC8C,KAAK,CAACP,IAAI,EAAElB,SAAS,CAAC,CAAC,EAC9ClB,MAAM,CAAC4C,KAAK,CACV9C,QAAQ,CAACwB,GAAG,CAAC,CACXxB,QAAQ,CAACyB,WAAW,CAAC,WAAW,CAAC,EACjCzB,QAAQ,CAAC0B,MAAM,CAAC,WAAW,CAAC,CAC7B,CAAC,CACH,CACF;EACD;EACA;EACA;EACA,OAAOc,QAAQ,CAACG,IAAI,CAACzC,MAAM,CAAC6C,QAAQ,EAAElD,MAAM,CAACmD,UAAU,CAAC;EAExD;EACA;EACA,MAAMC,SAAS,GAAIC,IAAO,IACxB/B,IAAI,CAACgC,KAAK,CAACD,IAAI,EAAEd,KAAK,CAAC;EAEzB;EACA;EACA;EACA;EACA;EACA;EACA,MAAMgB,SAAS,GAAIF,IAAO,IACxBrD,MAAM,CAACqC,GAAG,CAAC,aAAS;IAClB,MAAMmB,SAAS,GAAa,EAAE;IAC9B,IAAIC,MAAM,GAAGJ,IAAI;IACjB;IACA,OAAO,IAAI,EAAE;MACX,MAAMK,KAAK,GAAG,OAAON,SAAS,CAACK,MAAM,CAAC;MACtC,KAAK,MAAME,IAAI,IAAID,KAAK,EAAE;QACxBF,SAAS,CAACI,IAAI,CAACD,IAAI,CAAC;MACtB;MACA,MAAME,QAAQ,GAAGH,KAAK,CAACI,EAAE,CAAC,CAAC,CAAC,CAAC;MAC7B,IAAID,QAAQ,KAAKtC,SAAS,IAAImC,KAAK,CAACK,MAAM,GAAGzB,QAAQ,EAAE;QACrD;MACF;MACAmB,MAAM,GAAGnC,IAAI,CAAC0C,QAAQ,CAACH,QAAQ,CAAC;IAClC;IACA,OAAOL,SAAS;EAClB,CAAC,CAAC,CAACV,IAAI,CAAC9C,MAAM,CAACiD,KAAK,CAACxB,mBAAmB,CAAC,CAAC;EAE5C;EACA;EACA,MAAMwC,IAAI,GACR,CAAC3C,IAAI,CAAC4C,IAAI,IAAI,SAAS,MAAM,MAAM,GAC9Bb,IAAO,IAAKD,SAAS,CAACC,IAAI,CAAC,CAACP,IAAI,CAAC9C,MAAM,CAACiD,KAAK,CAACxB,mBAAmB,CAAC,CAAC,GACpE8B,SAAS;EAEf;;;;;;;;;;;;EAYA,MAAMY,SAAS,GACbd,IAAO,IAEPrD,MAAM,CAACqC,GAAG,CAAC,aAAS;IAClB,OAAO,IAAI,EAAE;MACX;MACA;MACA,OAAOnC,KAAK,CAACkE,KAAK,CAAC3B,IAAI,CAAC;MACxB,MAAMiB,KAAK,GAAG,OAAOO,IAAI,CAACZ,IAAI,CAAC;MAC/B,MAAMgB,IAAI,GAAGX,KAAK,CAACI,EAAE,CAAC,CAAC,CAAC,CAAC;MACzB,IAAIO,IAAI,KAAK9C,SAAS,EAAE;QACtB,OAAO,CAACmC,KAAK,EAAEpC,IAAI,CAAC0C,QAAQ,CAACK,IAAI,CAAC,CAAU;MAC9C;MACA;MACA;MACA,OAAOrE,MAAM,CAACsE,MAAM,CAACtE,MAAM,CAACuE,OAAO,CAACrE,KAAK,CAACsE,IAAI,CAAC/B,IAAI,CAAC,EAAEvB,YAAY,CAAC,CAAC;IACtE;EACF,CAAC,CAAC;EAEJ,OAAOb,MAAM,CAACoE,QAAQ,CAACnD,IAAI,CAACoD,OAAO,EAAGrB,IAAI,IACxCrD,MAAM,CAAC2E,GAAG,CACRR,SAAS,CAACd,IAAI,CAAC,EACf,CAAC,CAACK,KAAK,EAAEkB,IAAI,CAAC,KAAK,CAAClB,KAAK,EAAEzD,MAAM,CAAC4E,IAAI,CAACD,IAAI,CAAC,CAAU,CACvD,CACF;AACH,CAAC,CAAC,CACH;AAEH;;;;;;;;;;AAUA,OAAO,MAAME,eAAe,GAAGA,CAC7BxD,IAAyB,EACzByD,KAA2B,KAE3B9C,OAAO,CAA8B;EACnCqB,KAAK,EAAEhC,IAAI,CAACgC,KAAK;EACjBU,QAAQ,EAAGgB,KAAK,IAAKA,KAAK,CAACC,QAAQ;EACnCP,OAAO,EAAEK,KAAK,IAAIzE,MAAM;EACxB,IAAIgB,IAAI,CAACsB,MAAM,KAAKrB,SAAS,GAAG,EAAE,GAAG;IAAEqB,MAAM,EAAEtB,IAAI,CAACsB;EAAM,CAAE,CAAC;EAC7D1B,YAAY,EAAEI,IAAI,CAACJ,YAAY;EAC/BE,eAAe,EAAEE,IAAI,CAACF;CACvB,CAAC","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import { DateTime, Effect, Layer, PubSub, Ref, Stream } from 'effect';
1
+ import { DateTime, Effect, Layer, PubSub, Ref, Semaphore, Stream } from 'effect';
2
2
  import { makeContractStore } from "./ContractStore.js";
3
3
  import { DcbEventStore } from "./DcbEventStore.js";
4
4
  import { ORIGIN } from "./Event.js";
@@ -37,7 +37,7 @@ const copyEvent = event => ({
37
37
  data: new Uint8Array(event.data),
38
38
  tags: [...event.tags],
39
39
  uuid: event.uuid,
40
- occurredAt: DateTime.unsafeMake(DateTime.toEpochMillis(event.occurredAt)),
40
+ occurredAt: DateTime.makeUnsafe(DateTime.toEpochMillis(event.occurredAt)),
41
41
  metadata: {
42
42
  ...event.metadata
43
43
  }
@@ -152,7 +152,7 @@ const make = options => Effect.gen(function* () {
152
152
  const catchUpPageSize = options?.catchUpPageSize ?? DEFAULT_CATCH_UP_PAGE_SIZE;
153
153
  const pollInterval = options?.pollInterval ?? DEFAULT_POLL_INTERVAL_MILLIS;
154
154
  const log = yield* Ref.make([]);
155
- const mutex = yield* Effect.makeSemaphore(1);
155
+ const mutex = yield* Semaphore.make(1);
156
156
  const hub = yield* PubSub.unbounded();
157
157
  const nextPosition = yield* Ref.make(1n);
158
158
  const read = (query, options) =>
@@ -219,14 +219,14 @@ const make = options => Effect.gen(function* () {
219
219
  // exclusive cursor is what makes the catch-up/live seam exactly-once, so there
220
220
  // is nothing left here for a critical section to protect. `append` keeps its
221
221
  // permit, which is the whole exactly-one-wins guarantee.
222
- Stream.unwrapScoped(Effect.gen(function* () {
222
+ Stream.unwrap(Effect.gen(function* () {
223
223
  // Taken when the subscription starts, as the SQL engines compile theirs
224
224
  // (see `copyQuery`).
225
225
  const judged = copyQuery(query);
226
226
  const wakes = yield* PubSub.subscribe(hub);
227
227
  return subscribeStream({
228
228
  fetch: (from, limit) => Effect.map(Ref.get(log), snapshot => fetchPage(snapshot, judged, from, limit)),
229
- listen: Stream.fromQueue(wakes),
229
+ listen: Stream.fromSubscription(wakes),
230
230
  pollInterval,
231
231
  catchUpPageSize
232
232
  }, after);
@@ -1 +1 @@
1
- {"version":3,"file":"inMemory.js","names":["DateTime","Effect","Layer","PubSub","Ref","Stream","makeContractStore","DcbEventStore","ORIGIN","AppendConditionFailed","matchesSequenced","DEFAULT_CATCH_UP_PAGE_SIZE","DEFAULT_POLL_INTERVAL_MILLIS","subscribeStream","copyEvent","event","type","data","Uint8Array","tags","uuid","occurredAt","unsafeMake","toEpochMillis","metadata","copyQuery","query","items","map","item","types","copySequenced","sequenced","position","filterLog","log","after","filter","undefined","lastPosition","events","at","readSnapshot","options","matched","limited","limit","slice","head","fromIterable","firstIndexAfter","low","high","length","mid","fetchPage","from","page","index","push","make","gen","beforeCommit","void","suppressWake","catchUpPageSize","pollInterval","mutex","makeSemaphore","hub","unbounded","nextPosition","read","withPermits","get","snapshot","append","condition","suspend","owned","conflicts","failIfEventsMatch","start","appended","BigInt","end","set","publishAll","subscribe","unwrapScoped","judged","wakes","fetch","listen","fromQueue","DcbEventStoreInMemory","effect","makeInMemoryTestLayer"],"sources":["../../src/inMemory.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"inMemory.js","names":["DateTime","Effect","Layer","PubSub","Ref","Semaphore","Stream","makeContractStore","DcbEventStore","ORIGIN","AppendConditionFailed","matchesSequenced","DEFAULT_CATCH_UP_PAGE_SIZE","DEFAULT_POLL_INTERVAL_MILLIS","subscribeStream","copyEvent","event","type","data","Uint8Array","tags","uuid","occurredAt","makeUnsafe","toEpochMillis","metadata","copyQuery","query","items","map","item","types","copySequenced","sequenced","position","filterLog","log","after","filter","undefined","lastPosition","events","at","readSnapshot","options","matched","limited","limit","slice","head","fromIterable","firstIndexAfter","low","high","length","mid","fetchPage","from","page","index","push","make","gen","beforeCommit","void","suppressWake","catchUpPageSize","pollInterval","mutex","hub","unbounded","nextPosition","read","withPermits","get","snapshot","append","condition","suspend","owned","conflicts","failIfEventsMatch","start","appended","BigInt","end","set","publishAll","subscribe","unwrap","judged","wakes","fetch","listen","fromSubscription","DcbEventStoreInMemory","effect","makeInMemoryTestLayer"],"sources":["../../src/inMemory.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @kairos-es/core: DCB-first event-sourcing contract and in-memory store for
3
- * Effect v3.
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,21 +35,15 @@
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, Predicate, Schedule } from 'effect';
46
40
  /**
47
41
  * The default conflict backoff: exponential from 20ms, jittered, capped at five
48
42
  * retries.
49
43
  *
50
- * `Schedule.intersect` continues only while BOTH schedules continue, so the
51
- * `recurs(5)` arm is what bounds the attempts and the exponential arm is what
52
- * spaces them. Jitter matters more here than in a typical backoff: contending
44
+ * `Schedule.max` continues only while BOTH schedules continue, waiting the longer
45
+ * of their two delays, so the `recurs(5)` arm is what bounds the attempts and the
46
+ * exponential arm is what spaces them. Jitter matters more here than in a typical backoff: contending
53
47
  * deciders conflict precisely because they read the same boundary at the same
54
48
  * time, so an unjittered backoff would re-synchronise them into the same conflict
55
49
  * on every round. The figures are the conventional starting point (Emmett,
@@ -57,7 +51,7 @@ import { Effect, Predicate, Schedule } from 'effect';
57
51
  * command with a tighter latency budget, or one contending harder, should pass its
58
52
  * own schedule.
59
53
  */
60
- const conflictBackoff = /*#__PURE__*/Schedule.intersect(/*#__PURE__*/Schedule.jittered(/*#__PURE__*/Schedule.exponential('20 millis', 2)), /*#__PURE__*/Schedule.recurs(5));
54
+ const conflictBackoff = /*#__PURE__*/Schedule.max([/*#__PURE__*/Schedule.jittered(/*#__PURE__*/Schedule.exponential('20 millis', 2)), /*#__PURE__*/Schedule.recurs(5)]);
61
55
  /**
62
56
  * Retry `command` while — and only while — it fails `AppendConditionFailed`.
63
57
  *
@@ -1 +1 @@
1
- {"version":3,"file":"retryOnConflict.js","names":["Effect","Predicate","Schedule","conflictBackoff","intersect","jittered","exponential","recurs","retryOnConflict","command","schedule","retry","while","isTagged"],"sources":["../../src/retryOnConflict.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAASA,MAAM,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAGpD;;;;;;;;;;;;;;AAcA,MAAMC,eAAe,gBAAGD,QAAQ,CAACE,SAAS,cACxCF,QAAQ,CAACG,QAAQ,cAACH,QAAQ,CAACI,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,eACvDJ,QAAQ,CAACK,MAAM,CAAC,CAAC,CAAC,CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAO,MAAMC,eAAe,GAAGA,CAC7BC,OAAuD,EACvDC,QAAA,GAIIP,eAAe,KAEnBH,MAAM,CAACW,KAAK,CAACF,OAAO,EAAE;EACpBC,QAAQ;EACRE,KAAK,EAAEX,SAAS,CAACY,QAAQ,CAAC,uBAAuB;CAClD,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"retryOnConflict.js","names":["Effect","Predicate","Schedule","conflictBackoff","max","jittered","exponential","recurs","retryOnConflict","command","schedule","retry","while","isTagged"],"sources":["../../src/retryOnConflict.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAASA,MAAM,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAGpD;;;;;;;;;;;;;;AAcA,MAAMC,eAAe,gBAAGD,QAAQ,CAACE,GAAG,CAAC,cACnCF,QAAQ,CAACG,QAAQ,cAACH,QAAQ,CAACI,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,eACvDJ,QAAQ,CAACK,MAAM,CAAC,CAAC,CAAC,CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAO,MAAMC,eAAe,GAAGA,CAC7BC,OAAuD,EACvDC,QAAA,GAKIP,eAAe,KAEnBH,MAAM,CAACW,KAAK,CAACF,OAAO,EAAE;EACpBC,QAAQ;EACRE,KAAK,EAAEX,SAAS,CAACY,QAAQ,CAAC,uBAAuB;CAClD,CAAC","ignoreList":[]}
@@ -20,10 +20,10 @@ 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.unsafeMake(0)` (the value is a
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
- export const EPOCH = /*#__PURE__*/DateTime.unsafeMake(0);
26
+ export const EPOCH = /*#__PURE__*/DateTime.makeUnsafe(0);
27
27
  /**
28
28
  * Build a fresh, deterministic uuid generator: a zero-based counter producing
29
29
  * RFC-4122 v4-shaped ids `00000000-0000-4000-8000-<counter as 12 hex digits>`,
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","names":["DateTime","EPOCH","unsafeMake","makeSequentialUuid","counter","suffix","toString","padStart"],"sources":["../../src/testing.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;AAgBA,SAASA,QAAQ,QAAQ,QAAQ;AAEjC;;;;;;;;AAQA,OAAO,MAAMC,KAAK,gBAAGD,QAAQ,CAACE,UAAU,CAAC,CAAC,CAAC;AAE3C;;;;;;;;;;;AAWA,OAAO,MAAMC,kBAAkB,GAAGA,CAAA,KAAqB;EACrD,IAAIC,OAAO,GAAG,CAAC;EACf,OAAO,MAAK;IACV,MAAMC,MAAM,GAAGD,OAAO,CAACE,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACrDH,OAAO,IAAI,CAAC;IACZ,OAAO,2BAA2BC,MAAM,EAAE;EAC5C,CAAC;AACH,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"testing.js","names":["DateTime","EPOCH","makeUnsafe","makeSequentialUuid","counter","suffix","toString","padStart"],"sources":["../../src/testing.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;AAgBA,SAASA,QAAQ,QAAQ,QAAQ;AAEjC;;;;;;;;AAQA,OAAO,MAAMC,KAAK,gBAAGD,QAAQ,CAACE,UAAU,CAAC,CAAC,CAAC;AAE3C;;;;;;;;;;;AAWA,OAAO,MAAMC,kBAAkB,GAAGA,CAAA,KAAqB;EACrD,IAAIC,OAAO,GAAG,CAAC;EACf,OAAO,MAAK;IACV,MAAMC,MAAM,GAAGD,OAAO,CAACE,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACrDH,OAAO,IAAI,CAAC;IACZ,OAAO,2BAA2BC,MAAM,EAAE;EAC5C,CAAC;AACH,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kairos-es/core",
3
- "version": "1.0.0-alpha.4",
4
- "description": "DCB-first event-sourcing contract and in-memory store for Effect v3",
3
+ "version": "1.0.0-alpha.6",
4
+ "description": "DCB-first event-sourcing contract and in-memory store for Effect 4",
5
5
  "license": "BSD-3-Clause",
6
6
  "repository": {
7
7
  "type": "git",
@@ -11,28 +11,38 @@
11
11
  "sideEffects": [],
12
12
  "homepage": "https://github.com/neverbland/kairos-es",
13
13
  "peerDependencies": {
14
- "effect": "^3.22.0"
14
+ "effect": "^4.0.5"
15
15
  },
16
16
  "main": "./dist/cjs/index.js",
17
17
  "module": "./dist/esm/index.js",
18
- "types": "./dist/dts/index.d.ts",
18
+ "types": "./dist/dts-cjs/index.d.ts",
19
19
  "exports": {
20
20
  ".": {
21
- "types": "./dist/dts/index.d.ts",
22
- "import": "./dist/esm/index.js",
23
- "default": "./dist/cjs/index.js"
21
+ "import": {
22
+ "types": "./dist/dts-esm/index.d.ts",
23
+ "default": "./dist/esm/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/dts-cjs/index.d.ts",
27
+ "default": "./dist/cjs/index.js"
28
+ }
24
29
  },
25
30
  "./testing": {
26
- "types": "./dist/dts/testing.d.ts",
27
- "import": "./dist/esm/testing.js",
28
- "default": "./dist/cjs/testing.js"
31
+ "import": {
32
+ "types": "./dist/dts-esm/testing.d.ts",
33
+ "default": "./dist/esm/testing.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/dts-cjs/testing.d.ts",
37
+ "default": "./dist/cjs/testing.js"
38
+ }
29
39
  },
30
40
  "./package.json": "./package.json"
31
41
  },
32
42
  "typesVersions": {
33
43
  "*": {
34
44
  "testing": [
35
- "./dist/dts/testing.d.ts"
45
+ "./dist/dts-cjs/testing.d.ts"
36
46
  ]
37
47
  }
38
48
  }
@@ -13,6 +13,6 @@ import { Query } from './Query'
13
13
 
14
14
  export const AppendCondition = Schema.Struct({
15
15
  failIfEventsMatch: Query,
16
- after: Schema.optionalWith(Position, { exact: true }),
16
+ after: Schema.optionalKey(Position),
17
17
  })
18
18
  export type AppendCondition = typeof AppendCondition.Type