@kairos-es/core 1.0.0-alpha.3 → 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.
Files changed (120) 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 +13 -4
  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 +87 -11
  11. package/dist/cjs/Event.js.map +1 -1
  12. package/dist/cjs/Projection.js +15 -9
  13. package/dist/cjs/Projection.js.map +1 -1
  14. package/dist/cjs/Query.js +59 -3
  15. package/dist/cjs/Query.js.map +1 -1
  16. package/dist/cjs/SubscribeMachine.js +20 -22
  17. package/dist/cjs/SubscribeMachine.js.map +1 -1
  18. package/dist/cjs/inMemory.js +113 -43
  19. package/dist/cjs/inMemory.js.map +1 -1
  20. package/dist/cjs/retryOnConflict.js +4 -10
  21. package/dist/cjs/retryOnConflict.js.map +1 -1
  22. package/dist/cjs/testing.js +2 -2
  23. package/dist/cjs/testing.js.map +1 -1
  24. package/dist/{dts → dts-cjs}/AppendCondition.d.ts +5 -7
  25. package/dist/{dts → dts-cjs}/AppendCondition.d.ts.map +1 -1
  26. package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts +6 -6
  27. package/dist/{dts → dts-cjs}/AppendIsOwned.d.ts.map +1 -1
  28. package/dist/{dts → dts-cjs}/ContractStore.d.ts +7 -4
  29. package/dist/dts-cjs/ContractStore.d.ts.map +1 -0
  30. package/dist/{dts → dts-cjs}/DcbEventStore.d.ts +2 -2
  31. package/dist/{dts → dts-cjs}/DcbEventStore.d.ts.map +1 -1
  32. package/dist/dts-cjs/Event.d.ts +174 -0
  33. package/dist/dts-cjs/Event.d.ts.map +1 -0
  34. package/dist/{dts → dts-cjs}/Projection.d.ts +1 -1
  35. package/dist/{dts → dts-cjs}/Projection.d.ts.map +1 -1
  36. package/dist/{dts → dts-cjs}/Query.d.ts +19 -5
  37. package/dist/dts-cjs/Query.d.ts.map +1 -0
  38. package/dist/{dts → dts-cjs}/SubscribeMachine.d.ts +11 -15
  39. package/dist/dts-cjs/SubscribeMachine.d.ts.map +1 -0
  40. package/dist/{dts → dts-cjs}/inMemory.d.ts.map +1 -1
  41. package/dist/{dts → dts-cjs}/index.d.ts +1 -1
  42. package/dist/dts-cjs/package.json +3 -0
  43. package/dist/{dts → dts-cjs}/retryOnConflict.d.ts +1 -7
  44. package/dist/dts-cjs/retryOnConflict.d.ts.map +1 -0
  45. package/dist/{dts → dts-cjs}/testing.d.ts +1 -1
  46. package/dist/dts-esm/AppendCondition.d.ts +21 -0
  47. package/dist/dts-esm/AppendCondition.d.ts.map +1 -0
  48. package/dist/dts-esm/AppendIsOwned.d.ts +78 -0
  49. package/dist/dts-esm/AppendIsOwned.d.ts.map +1 -0
  50. package/dist/dts-esm/ContractStore.d.ts +62 -0
  51. package/dist/dts-esm/ContractStore.d.ts.map +1 -0
  52. package/dist/dts-esm/DcbEventStore.d.ts +64 -0
  53. package/dist/dts-esm/DcbEventStore.d.ts.map +1 -0
  54. package/dist/dts-esm/Event.d.ts +174 -0
  55. package/dist/dts-esm/Event.d.ts.map +1 -0
  56. package/dist/dts-esm/Projection.d.ts +124 -0
  57. package/dist/dts-esm/Projection.d.ts.map +1 -0
  58. package/dist/dts-esm/Query.d.ts +180 -0
  59. package/dist/dts-esm/Query.d.ts.map +1 -0
  60. package/dist/dts-esm/SubscribeMachine.d.ts +175 -0
  61. package/dist/dts-esm/SubscribeMachine.d.ts.map +1 -0
  62. package/dist/dts-esm/errors.d.ts +17 -0
  63. package/dist/dts-esm/errors.d.ts.map +1 -0
  64. package/dist/dts-esm/inMemory.d.ts +76 -0
  65. package/dist/dts-esm/inMemory.d.ts.map +1 -0
  66. package/dist/dts-esm/index.d.ts +40 -0
  67. package/dist/dts-esm/index.d.ts.map +1 -0
  68. package/dist/dts-esm/package.json +3 -0
  69. package/dist/dts-esm/retryOnConflict.d.ts +64 -0
  70. package/dist/dts-esm/retryOnConflict.d.ts.map +1 -0
  71. package/dist/dts-esm/testing.d.ts +39 -0
  72. package/dist/dts-esm/testing.d.ts.map +1 -0
  73. package/dist/esm/AppendCondition.js +1 -3
  74. package/dist/esm/AppendCondition.js.map +1 -1
  75. package/dist/esm/AppendIsOwned.js +6 -6
  76. package/dist/esm/AppendIsOwned.js.map +1 -1
  77. package/dist/esm/ContractStore.js +13 -4
  78. package/dist/esm/ContractStore.js.map +1 -1
  79. package/dist/esm/DcbEventStore.js +1 -1
  80. package/dist/esm/DcbEventStore.js.map +1 -1
  81. package/dist/esm/Event.js +87 -11
  82. package/dist/esm/Event.js.map +1 -1
  83. package/dist/esm/Projection.js +15 -9
  84. package/dist/esm/Projection.js.map +1 -1
  85. package/dist/esm/Query.js +56 -1
  86. package/dist/esm/Query.js.map +1 -1
  87. package/dist/esm/SubscribeMachine.js +21 -23
  88. package/dist/esm/SubscribeMachine.js.map +1 -1
  89. package/dist/esm/inMemory.js +114 -44
  90. package/dist/esm/inMemory.js.map +1 -1
  91. package/dist/esm/index.js +1 -1
  92. package/dist/esm/retryOnConflict.js +4 -10
  93. package/dist/esm/retryOnConflict.js.map +1 -1
  94. package/dist/esm/testing.js +2 -2
  95. package/dist/esm/testing.js.map +1 -1
  96. package/package.json +21 -11
  97. package/src/AppendCondition.ts +1 -1
  98. package/src/AppendIsOwned.ts +7 -7
  99. package/src/ContractStore.ts +25 -8
  100. package/src/DcbEventStore.ts +3 -3
  101. package/src/Event.ts +108 -11
  102. package/src/Projection.ts +19 -8
  103. package/src/Query.ts +74 -1
  104. package/src/SubscribeMachine.ts +38 -31
  105. package/src/inMemory.ts +123 -51
  106. package/src/index.ts +1 -1
  107. package/src/retryOnConflict.ts +6 -11
  108. package/src/testing.ts +2 -2
  109. package/testing/package.json +1 -1
  110. package/dist/dts/ContractStore.d.ts.map +0 -1
  111. package/dist/dts/Event.d.ts +0 -104
  112. package/dist/dts/Event.d.ts.map +0 -1
  113. package/dist/dts/Query.d.ts.map +0 -1
  114. package/dist/dts/SubscribeMachine.d.ts.map +0 -1
  115. package/dist/dts/retryOnConflict.d.ts.map +0 -1
  116. /package/dist/{dts → dts-cjs}/errors.d.ts +0 -0
  117. /package/dist/{dts → dts-cjs}/errors.d.ts.map +0 -0
  118. /package/dist/{dts → dts-cjs}/inMemory.d.ts +0 -0
  119. /package/dist/{dts → dts-cjs}/index.d.ts.map +0 -0
  120. /package/dist/{dts → dts-cjs}/testing.d.ts.map +0 -0
package/src/inMemory.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * The log is a `Ref<ReadonlyArray<SequencedEvent>>` in ascending position
6
6
  * order. The whole check-then-append is run inside a single
7
- * `Effect.makeSemaphore(1)`+`withPermits(1)` critical section: the conditional
7
+ * `Semaphore.make(1)`+`withPermits(1)` critical section: the conditional
8
8
  * read and the commit must not be separable, and that atomicity is the entire
9
9
  * concurrency guarantee (exactly-one-wins under a race). Positions come from a
10
10
  * monotonic counter starting at 1n (contiguous here; the contract only promises
@@ -25,7 +25,7 @@
25
25
  * discharges the ascending-commit-order precondition `SubscribeMachine.ts` states.
26
26
  */
27
27
  import type { Array as Arr, Scope } from 'effect'
28
- import { Effect, Layer, PubSub, Ref, Stream } from 'effect'
28
+ import { DateTime, Effect, Layer, PubSub, Ref, Semaphore, Stream } from 'effect'
29
29
  import type { AppendCondition } from './AppendCondition'
30
30
  import { makeContractStore, type RawDcbEventStore } from './ContractStore'
31
31
  import type { ReadOptions, ReadResponse } from './DcbEventStore'
@@ -41,6 +41,68 @@ import {
41
41
  subscribeStream,
42
42
  } from './SubscribeMachine'
43
43
 
44
+ /**
45
+ * A copy of `event` that shares no mutable structure with it: fresh `data` bytes, a
46
+ * fresh `tags` array, a fresh `metadata` bag and a fresh `occurredAt`. Only `type`
47
+ * and `uuid`, which are strings, are carried as they are.
48
+ *
49
+ * Each copy is chosen for what it does on EVERY input the type admits, not on the
50
+ * common one. `data` is copied through the `Uint8Array` constructor and not with
51
+ * `slice`, because `DcbEvent` admits any `Uint8Array` subclass and a subclass may
52
+ * answer `slice` with a VIEW of the same memory — Node's `Buffer` does. A
53
+ * `DateTime.Utc` is an ordinary object whose fields can be written past its
54
+ * `readonly` type, so `occurredAt` is rebuilt from its instant rather than shared.
55
+ *
56
+ * ## Why the oracle copies at BOTH edges
57
+ *
58
+ * This store is the reference the SQL engines are judged against, and a SQL engine
59
+ * shares nothing with its caller: it serialises on the way in and builds fresh objects
60
+ * on the way out. A store that kept the caller's objects instead would let a caller
61
+ * rewrite the log AFTER the append — mutate a `Uint8Array`, push to a `tags` array,
62
+ * assign into a `metadata` bag — and every later read would see the rewritten event
63
+ * with no append, no position and no wake behind it. A reference that can be edited
64
+ * after the fact judges nothing.
65
+ *
66
+ * So `append` stores a copy (the log never holds a caller's object) and every read
67
+ * path hands out a copy (a reader cannot reach the log through what it was given).
68
+ * Copying on the way in alone would close the first route and leave the second open:
69
+ * the same object would then be shared by every reader of the log.
70
+ */
71
+ const copyEvent = (event: DcbEvent): DcbEvent => ({
72
+ type: event.type,
73
+ data: new Uint8Array(event.data),
74
+ tags: [...event.tags],
75
+ uuid: event.uuid,
76
+ occurredAt: DateTime.makeUnsafe(DateTime.toEpochMillis(event.occurredAt)),
77
+ metadata: { ...event.metadata },
78
+ })
79
+
80
+ /**
81
+ * A copy of `query` that shares no array with it, taking only the keys the grammar
82
+ * defines.
83
+ *
84
+ * `subscribe` is the one verb that holds a query beyond its own call: the fetch seam
85
+ * judges it again on every page for as long as the subscription runs. Each SQL engine
86
+ * compiles its plan once, when the subscription starts, so an edit the caller makes
87
+ * to its own object afterwards reaches nothing there. The oracle has to answer the
88
+ * same, for the reason it copies events (above): a reference that the caller can
89
+ * change mid-stream judges nothing. Only `types` and `tags` are carried because they
90
+ * are all `matchesQueryItem` reads, and a key the grammar does not define was
91
+ * already refused at the contract decorator before this runs.
92
+ */
93
+ const copyQuery = (query: Query): Query => ({
94
+ items: query.items.map((item) => ({
95
+ types: [...item.types],
96
+ tags: [...item.tags],
97
+ })),
98
+ })
99
+
100
+ /** A `SequencedEvent` whose event is a `copyEvent` of the stored one. */
101
+ const copySequenced = (sequenced: SequencedEvent): SequencedEvent => ({
102
+ event: copyEvent(sequenced.event),
103
+ position: sequenced.position,
104
+ })
105
+
44
106
  /** Filter a snapshot by `query` and `after` (strict `position > after`). */
45
107
  const filterLog = (
46
108
  log: ReadonlyArray<SequencedEvent>,
@@ -80,7 +142,7 @@ const readSnapshot = (
80
142
  ? lastPosition(log)
81
143
  : lastPosition(limited)) ?? ORIGIN
82
144
 
83
- return { events: Stream.fromIterable(limited), head }
145
+ return { events: Stream.fromIterable(limited.map(copySequenced)), head }
84
146
  }
85
147
 
86
148
  /**
@@ -144,7 +206,7 @@ const fetchPage = (
144
206
  ) {
145
207
  const sequenced = log[index]
146
208
  if (matchesSequenced(sequenced, query)) {
147
- page.push(sequenced)
209
+ page.push(copySequenced(sequenced))
148
210
  }
149
211
  }
150
212
  return page
@@ -226,7 +288,7 @@ const make = (
226
288
  options?.catchUpPageSize ?? DEFAULT_CATCH_UP_PAGE_SIZE
227
289
  const pollInterval = options?.pollInterval ?? DEFAULT_POLL_INTERVAL_MILLIS
228
290
  const log = yield* Ref.make<ReadonlyArray<SequencedEvent>>([])
229
- const mutex = yield* Effect.makeSemaphore(1)
291
+ const mutex = yield* Semaphore.make(1)
230
292
  const hub = yield* PubSub.unbounded<SequencedEvent>()
231
293
  const nextPosition = yield* Ref.make<bigint>(1n)
232
294
 
@@ -247,53 +309,60 @@ const make = (
247
309
  events: Arr.NonEmptyReadonlyArray<DcbEvent>,
248
310
  condition?: AppendCondition,
249
311
  ): Effect.Effect<Position, AppendConditionFailed> =>
250
- // Critical section: check + commit are atomic (the exactly-one-wins guarantee).
251
- mutex.withPermits(1)(
252
- Effect.gen(function* () {
253
- const snapshot = yield* Ref.get(log)
312
+ Effect.suspend(() => {
313
+ // The events are copied when the append STARTS, before it waits for the
314
+ // permit, as each SQL engine serialises them before its first suspension:
315
+ // an edit the caller makes while this append is queued must not reach the
316
+ // log here when it could not reach theirs.
317
+ const owned = events.map(copyEvent)
318
+ // Critical section: check + commit are atomic (the exactly-one-wins guarantee).
319
+ return mutex.withPermits(1)(
320
+ Effect.gen(function* () {
321
+ const snapshot = yield* Ref.get(log)
254
322
 
255
- if (condition !== undefined) {
256
- const conflicts = filterLog(
257
- snapshot,
258
- condition.failIfEventsMatch,
259
- condition.after,
260
- )
261
- // Detect by presence: any matching event after `condition.after`
262
- // fails the append. The error carries only the condition (see
263
- // `AppendConditionFailed`); a correct retry re-reads to the new head.
264
- if (conflicts.length > 0) {
265
- return yield* new AppendConditionFailed({ condition })
323
+ if (condition !== undefined) {
324
+ const conflicts = filterLog(
325
+ snapshot,
326
+ condition.failIfEventsMatch,
327
+ condition.after,
328
+ )
329
+ // Detect by presence: any matching event after `condition.after`
330
+ // fails the append. The error carries only the condition (see
331
+ // `AppendConditionFailed`); a correct retry re-reads to the new head.
332
+ if (conflicts.length > 0) {
333
+ return yield* new AppendConditionFailed({ condition })
334
+ }
266
335
  }
267
- }
268
336
 
269
- // Optional test seam between the conflict-check and the commit (see
270
- // `InMemoryStoreOptions.beforeCommit`). Defaults to `Effect.void`, a
271
- // synchronous no-op, so the shipped critical section stays atomic by
272
- // construction; the concurrency contract test injects `Effect.yieldNow()`
273
- // here to make the exactly-one-wins guard genuinely depend on the mutex.
274
- yield* beforeCommit
337
+ // Optional test seam between the conflict-check and the commit (see
338
+ // `InMemoryStoreOptions.beforeCommit`). Defaults to `Effect.void`, a
339
+ // synchronous no-op, so the shipped critical section stays atomic by
340
+ // construction; the concurrency contract test injects `Effect.yieldNow()`
341
+ // here to make the exactly-one-wins guard genuinely depend on the mutex.
342
+ yield* beforeCommit
275
343
 
276
- const start = yield* Ref.get(nextPosition)
277
- const appended: Array<SequencedEvent> = events.map(
278
- (event, index) => ({
279
- event,
280
- position: (start + BigInt(index)) as Position,
281
- }),
282
- )
283
- const end = start + BigInt(events.length)
284
- yield* Ref.set(log, [...snapshot, ...appended])
285
- yield* Ref.set(nextPosition, end)
286
- // The hub is a WAKE SOURCE and nothing else: the subscribe machine never
287
- // reads what it carries, and its poll delivers with or without one. That
288
- // is why suppressing the publish is a legitimate test seam rather than a
289
- // broken store (see `InMemoryStoreOptions.suppressWake`).
290
- if (!suppressWake) {
291
- yield* PubSub.publishAll(hub, appended)
292
- }
293
- // `events` is non-empty, so the last new position is `end - 1`.
294
- return (end - 1n) as Position
295
- }),
296
- )
344
+ const start = yield* Ref.get(nextPosition)
345
+ const appended: Array<SequencedEvent> = owned.map(
346
+ (event, index) => ({
347
+ event,
348
+ position: (start + BigInt(index)) as Position,
349
+ }),
350
+ )
351
+ const end = start + BigInt(events.length)
352
+ yield* Ref.set(log, [...snapshot, ...appended])
353
+ yield* Ref.set(nextPosition, end)
354
+ // The hub is a WAKE SOURCE and nothing else: the subscribe machine never
355
+ // reads what it carries, and its poll delivers with or without one. That
356
+ // is why suppressing the publish is a legitimate test seam rather than a
357
+ // broken store (see `InMemoryStoreOptions.suppressWake`).
358
+ if (!suppressWake) {
359
+ yield* PubSub.publishAll(hub, appended)
360
+ }
361
+ // `events` is non-empty, so the last new position is `end - 1`.
362
+ return (end - 1n) as Position
363
+ }),
364
+ )
365
+ })
297
366
 
298
367
  const subscribe = (
299
368
  query: Query,
@@ -312,16 +381,19 @@ const make = (
312
381
  // exclusive cursor is what makes the catch-up/live seam exactly-once, so there
313
382
  // is nothing left here for a critical section to protect. `append` keeps its
314
383
  // permit, which is the whole exactly-one-wins guarantee.
315
- Stream.unwrapScoped(
384
+ Stream.unwrap(
316
385
  Effect.gen(function* () {
386
+ // Taken when the subscription starts, as the SQL engines compile theirs
387
+ // (see `copyQuery`).
388
+ const judged = copyQuery(query)
317
389
  const wakes = yield* PubSub.subscribe(hub)
318
390
  return subscribeStream<never>(
319
391
  {
320
392
  fetch: (from, limit) =>
321
393
  Effect.map(Ref.get(log), (snapshot) =>
322
- fetchPage(snapshot, query, from, limit),
394
+ fetchPage(snapshot, judged, from, limit),
323
395
  ),
324
- listen: Stream.fromQueue(wakes),
396
+ listen: Stream.fromSubscription(wakes),
325
397
  pollInterval,
326
398
  catchUpPageSize,
327
399
  },
package/src/index.ts 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,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, Predicate, Schedule } from 'effect'
46
40
  import type { AppendConditionFailed } from './errors'
@@ -49,9 +43,9 @@ import type { AppendConditionFailed } from './errors'
49
43
  * The default conflict backoff: exponential from 20ms, jittered, capped at five
50
44
  * retries.
51
45
  *
52
- * `Schedule.intersect` continues only while BOTH schedules continue, so the
53
- * `recurs(5)` arm is what bounds the attempts and the exponential arm is what
54
- * spaces them. Jitter matters more here than in a typical backoff: contending
46
+ * `Schedule.max` continues only while BOTH schedules continue, waiting the longer
47
+ * of their two delays, so the `recurs(5)` arm is what bounds the attempts and the
48
+ * exponential arm is what spaces them. Jitter matters more here than in a typical backoff: contending
55
49
  * deciders conflict precisely because they read the same boundary at the same
56
50
  * time, so an unjittered backoff would re-synchronise them into the same conflict
57
51
  * on every round. The figures are the conventional starting point (Emmett,
@@ -59,10 +53,10 @@ import type { AppendConditionFailed } from './errors'
59
53
  * command with a tighter latency budget, or one contending harder, should pass its
60
54
  * own schedule.
61
55
  */
62
- const conflictBackoff = Schedule.intersect(
56
+ const conflictBackoff = Schedule.max([
63
57
  Schedule.jittered(Schedule.exponential('20 millis', 2)),
64
58
  Schedule.recurs(5),
65
- )
59
+ ])
66
60
 
67
61
  /**
68
62
  * Retry `command` while — and only while — it fails `AppendConditionFailed`.
@@ -91,6 +85,7 @@ export const retryOnConflict = <A, E, R>(
91
85
  schedule: Schedule.Schedule<
92
86
  unknown,
93
87
  AppendConditionFailed | E,
88
+ never,
94
89
  R
95
90
  > = conflictBackoff,
96
91
  ): Effect.Effect<A, AppendConditionFailed | E, R> =>
package/src/testing.ts CHANGED
@@ -21,10 +21,10 @@ import { DateTime } from 'effect'
21
21
  *
22
22
  * Ordering in the log is by `position` alone, so an event's `occurredAt` is
23
23
  * informational; pinning it to the epoch keeps serialised bytes and comparisons
24
- * stable across runs. Built via `DateTime.unsafeMake(0)` (the value is a
24
+ * stable across runs. Built via `DateTime.makeUnsafe(0)` (the value is a
25
25
  * compile-time constant, not read from the host clock).
26
26
  */
27
- export const EPOCH = DateTime.unsafeMake(0)
27
+ export const EPOCH = DateTime.makeUnsafe(0)
28
28
 
29
29
  /**
30
30
  * Build a fresh, deterministic uuid generator: a zero-based counter producing
@@ -2,5 +2,5 @@
2
2
  "sideEffects": [],
3
3
  "main": "../dist/cjs/testing.js",
4
4
  "module": "../dist/esm/testing.js",
5
- "types": "../dist/dts/testing.d.ts"
5
+ "types": "../dist/dts-cjs/testing.d.ts"
6
6
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"ContractStore.d.ts","sourceRoot":"","sources":["../../src/ContractStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;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,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,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,MAAM,CAsFrB,CAAA"}
@@ -1,104 +0,0 @@
1
- /**
2
- * Core domain types for the DCB event log: branded scalars and the wire
3
- * `DcbEvent`/`SequencedEvent` shapes.
4
- *
5
- * `data` is opaque bytes at the store layer; the codec (`@kairos-es/codec`) turns typed
6
- * payloads into these bytes. Ordering is by `position` alone; `occurredAt` is
7
- * producer-supplied domain time and is informational only.
8
- */
9
- import { Schema } from 'effect';
10
- /**
11
- * A position in the single global event log: a branded, non-negative `bigint`.
12
- *
13
- * The log is 64-bit (`bigserial` in Postgres) and exceeds JS `number` safety at
14
- * 2^53, so positions are a `bigint`. They are compared, never arithmetic'd.
15
- * `Schema.BigInt` encodes to a decimal string (JSON-safe) and decodes to
16
- * `bigint`. `0n` is the "before the first event" sentinel used by `after` and by
17
- * an empty store's head.
18
- */
19
- export declare const Position: Schema.brand<Schema.filter<typeof Schema.BigInt>, "Position">;
20
- export type Position = typeof Position.Type;
21
- /** The sentinel position meaning "before the first event". */
22
- export declare const ORIGIN: Position;
23
- /**
24
- * A business identifier attached to an event, following the `key:value`
25
- * convention (e.g. `student:s1`). Tags replace the per-stream id of classic
26
- * event sourcing; a query matches an event when the event carries all of an
27
- * item's tags (superset test).
28
- */
29
- export declare const Tag: Schema.brand<Schema.filter<typeof Schema.String>, "Tag">;
30
- export type Tag = typeof Tag.Type;
31
- /**
32
- * A reusable tag identity: a `key` plus a `.make(value)` that composes the
33
- * branded `Tag` `` `${key}:${value}` `` through core's `Tag` schema. Define an
34
- * identity once (`const CourseId = tagIdentity('course')`) and reuse
35
- * `CourseId.make(id)` everywhere that entity is tagged. The `key` is exposed for
36
- * key-aware tooling (e.g. a tag-vocabulary index, a future retag pass).
37
- *
38
- * The same constructor authors an event's tags (in a codec `tagsFor` mapper,
39
- * ADR-0006) and a query's tags, so the `key:value` string a mapper writes and
40
- * the string a query matches are produced by one function and cannot drift. It
41
- * lives here beside `Tag` — pure (no clock, no RNG, no effect) — so it is
42
- * reachable from every tag-authoring site, including core's own query
43
- * constructors.
44
- *
45
- * `key` and `value` are each a single colon-free atom: the `key:value` grammar
46
- * splits on the first colon, so both are validated to be non-empty and contain
47
- * no `:` — `key` once at construction, `value` on each `make`. This keeps
48
- * composition unambiguous and catches the double-prefix footgun loudly:
49
- * `CourseId.make('course:123')` throws rather than silently yielding
50
- * `course:course:123`. Raw `Tag.make` remains the escape hatch for a value that
51
- * must itself contain a colon.
52
- */
53
- export interface TagIdentity {
54
- readonly key: string;
55
- readonly make: (value: string) => Tag;
56
- }
57
- export declare const tagIdentity: (key: string) => TagIdentity;
58
- /**
59
- * A read cap: a branded non-negative integer bounding how many events a `read`
60
- * returns. `0` returns none; an absent limit returns all matching events.
61
- *
62
- * The bound lives in the type, not merely in prose: a negative or non-integer
63
- * limit is a programming error, so it is a DEFECT at the store boundary — the
64
- * store validates through this schema and dies rather than surfacing it on the
65
- * error channel (`read` keeps `E = never`). Constructed at call sites with
66
- * `ReadLimit.make(n)`.
67
- */
68
- export declare const ReadLimit: Schema.brand<Schema.filter<typeof Schema.Int>, "ReadLimit">;
69
- export type ReadLimit = typeof ReadLimit.Type;
70
- /**
71
- * An event type name, a branded non-empty string. Versioning is by convention
72
- * in the name (e.g. `course-registered.v2`); only non-emptiness is enforced.
73
- */
74
- export declare const EventType: Schema.brand<Schema.filter<typeof Schema.String>, "EventType">;
75
- export type EventType = typeof EventType.Type;
76
- /**
77
- * An event as stored: an opaque payload plus its type, tags, a
78
- * producer-supplied `uuid`, and producer-supplied `occurredAt` domain time.
79
- *
80
- * `data` is `Uint8Array` (opaque bytes); the store does not interpret it.
81
- * `uuid` is producer-supplied to keep `core` deterministic (no RNG in core).
82
- * `occurredAt` is informational only; ordering is by position alone.
83
- */
84
- export declare const DcbEvent: Schema.Struct<{
85
- type: Schema.brand<Schema.filter<typeof Schema.String>, "EventType">;
86
- data: typeof Schema.Uint8ArrayFromSelf;
87
- tags: Schema.Array$<Schema.brand<Schema.filter<typeof Schema.String>, "Tag">>;
88
- uuid: typeof Schema.UUID;
89
- occurredAt: typeof Schema.DateTimeUtc;
90
- }>;
91
- export type DcbEvent = typeof DcbEvent.Type;
92
- /** A persisted event: the event together with the position it was written at. */
93
- export declare const SequencedEvent: Schema.Struct<{
94
- event: Schema.Struct<{
95
- type: Schema.brand<Schema.filter<typeof Schema.String>, "EventType">;
96
- data: typeof Schema.Uint8ArrayFromSelf;
97
- tags: Schema.Array$<Schema.brand<Schema.filter<typeof Schema.String>, "Tag">>;
98
- uuid: typeof Schema.UUID;
99
- occurredAt: typeof Schema.DateTimeUtc;
100
- }>;
101
- position: Schema.brand<Schema.filter<typeof Schema.BigInt>, "Position">;
102
- }>;
103
- export type SequencedEvent = typeof SequencedEvent.Type;
104
- //# sourceMappingURL=Event.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Event.d.ts","sourceRoot":"","sources":["../../src/Event.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,+DAGpB,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,0DAGf,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,6DAGrB,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,SAAS,gEAGrB,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ;;;;;;EAMnB,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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../src/Query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAE5E;;;GAGG;AACH,eAAO,MAAM,SAAS;;;EAGpB,CAAA;AACF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAE7C,iEAAiE;AACjE,eAAO,MAAM,KAAK;;;;;EAEhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAErC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,QAAQ,EAAE,MAAM,SAAS,KAAG,OAOnE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,QAAQ,EAAE,OAAO,KAAK,KAAG,OAK5D,CAAA;AAED,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,GAC3B,WAAW,cAAc,EACzB,OAAO,KAAK,KACX,OAA+C,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,KAAK,KAAG,IAKlD,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,MAAM,GAAG,SAkB1D,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAC7B;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACrD,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,KAAK,KAAG,kBAWpD,CAAA;AAoDD,iDAAiD;AACjD,eAAO,MAAM,KAAK;wBAlCF,KAAK;4BATC;QACpB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;QACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;KAC1C,KAAG,SAAS;yBAkCJ,SAAS,CAAC,SAAS,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,KACvD,KAAK;0BAtBA,SAAS,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,UACnC,aAAa,CAAC,SAAS,CAAC,KAC/B,KAAK;4BAUC,SAAS,CAAC,SAAS,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,KACvD,KAAK;CAoBE,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"SubscribeMachine.d.ts","sourceRoot":"","sources":["../../src/SubscribeMachine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,OAAO,EAEL,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;;;;;;;CAQ3B,CAAA;AAcV;;;;;;;;;;;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,CAyG5C,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"retryOnConflict.d.ts","sourceRoot":"","sources":["../../src/retryOnConflict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;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,CAAC,CACgB,KAClB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,qBAAqB,GAAG,CAAC,EAAE,CAAC,CAI5C,CAAA"}
File without changes
File without changes
File without changes
File without changes
File without changes