@kronos-ts/axon-server 0.3.2 → 0.4.0

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 (57) hide show
  1. package/dist/axon-server-event-store.d.ts +9 -5
  2. package/dist/axon-server-event-store.d.ts.map +1 -1
  3. package/dist/axon-server-event-store.js +38 -30
  4. package/dist/axon-server-event-store.js.map +1 -1
  5. package/dist/axon-server-snapshot-store.d.ts +8 -8
  6. package/dist/axon-server-snapshot-store.d.ts.map +1 -1
  7. package/dist/axon-server-snapshot-store.js +8 -14
  8. package/dist/axon-server-snapshot-store.js.map +1 -1
  9. package/dist/axon-server.d.ts +97 -186
  10. package/dist/axon-server.d.ts.map +1 -1
  11. package/dist/axon-server.js +217 -318
  12. package/dist/axon-server.js.map +1 -1
  13. package/dist/connection.d.ts +128 -0
  14. package/dist/connection.d.ts.map +1 -1
  15. package/dist/connection.js +134 -10
  16. package/dist/connection.js.map +1 -1
  17. package/dist/context-view.d.ts +30 -0
  18. package/dist/context-view.d.ts.map +1 -0
  19. package/dist/context-view.js +19 -0
  20. package/dist/context-view.js.map +1 -0
  21. package/dist/control-plane.d.ts +14 -13
  22. package/dist/control-plane.d.ts.map +1 -1
  23. package/dist/control-plane.js +8 -6
  24. package/dist/control-plane.js.map +1 -1
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js.map +1 -1
  27. package/dist/flow-controlled-sender.js.map +1 -1
  28. package/dist/generated/command.d.ts.map +1 -1
  29. package/dist/generated/command.js.map +1 -1
  30. package/dist/generated/common.js.map +1 -1
  31. package/dist/generated/control.d.ts.map +1 -1
  32. package/dist/generated/control.js.map +1 -1
  33. package/dist/generated/dcb.d.ts.map +1 -1
  34. package/dist/generated/dcb.js.map +1 -1
  35. package/dist/generated/event.d.ts.map +1 -1
  36. package/dist/generated/event.js.map +1 -1
  37. package/dist/generated/google/protobuf/empty.js.map +1 -1
  38. package/dist/generated/query.d.ts.map +1 -1
  39. package/dist/generated/query.js.map +1 -1
  40. package/dist/index.d.ts +4 -6
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +4 -5
  43. package/dist/index.js.map +1 -1
  44. package/dist/message-size.d.ts.map +1 -1
  45. package/dist/metadata-conversion.d.ts +1 -1
  46. package/dist/metadata-conversion.d.ts.map +1 -1
  47. package/dist/shutdown-latch.d.ts.map +1 -1
  48. package/dist/shutdown-latch.js.map +1 -1
  49. package/package.json +4 -8
  50. package/src/axon-server-event-store.ts +51 -43
  51. package/src/axon-server-snapshot-store.ts +17 -25
  52. package/src/axon-server.ts +358 -512
  53. package/src/connection.ts +270 -18
  54. package/src/context-view.ts +46 -0
  55. package/src/control-plane.ts +17 -17
  56. package/src/index.ts +12 -18
  57. package/src/metadata-conversion.ts +1 -1
@@ -3,15 +3,15 @@ import {
3
3
  qualifiedNameFromString,
4
4
  type Tag,
5
5
  type Serializer,
6
- } from "@kronos-ts/common"
6
+ } from "@kronos-ts/core"
7
7
  import type {
8
8
  EventCriteria,
9
9
  EventMessage,
10
10
  MessageStream,
11
11
  SequencedEvent,
12
12
  StreamingCondition,
13
- } from "@kronos-ts/messaging"
14
- import { messageStream } from "@kronos-ts/messaging"
13
+ } from "@kronos-ts/core"
14
+ import { messageStream, compileQuery } from "@kronos-ts/core"
15
15
  import type {
16
16
  EventStore,
17
17
  SourcingResult,
@@ -19,11 +19,12 @@ import type {
19
19
  AppendCondition,
20
20
  ConsistencyMarker,
21
21
  AppendTransaction,
22
- } from "@kronos-ts/eventsourcing"
23
- import type { TrackingToken } from "@kronos-ts/messaging"
24
- import { globalSequenceToken, FIRST_TOKEN } from "@kronos-ts/messaging"
25
- import { markerAt, noMarker } from "@kronos-ts/eventsourcing"
26
- import type { AxonServerConnection } from "./connection.js"
22
+ } from "@kronos-ts/core"
23
+ import type { TrackingToken } from "@kronos-ts/core"
24
+ import { globalSequenceToken, FIRST_TOKEN } from "@kronos-ts/core"
25
+ import { markerAt, noMarker } from "@kronos-ts/core"
26
+ import type { AxonServerStoreSource } from "./connection.js"
27
+ import { contextView } from "./context-view.js"
27
28
  import type {
28
29
  Criterion,
29
30
  TagsAndNamesCriterion,
@@ -32,7 +33,6 @@ import type {
32
33
  Event as ProtoEvent,
33
34
  SourceEventsResponse,
34
35
  } from "./generated/dcb.js"
35
- import { Metadata } from "nice-grpc"
36
36
 
37
37
  // ---------------------------------------------------------------------------
38
38
  // Criteria conversion — framework EventCriteria → proto Criterion[]
@@ -57,24 +57,26 @@ function tagFromProto(tag: ProtoTag): Tag {
57
57
  function criteriaToCriterions(criteria: EventCriteria): Criterion[] {
58
58
  switch (criteria.kind) {
59
59
  case "tags":
60
- return [{
61
- tagsAndNames: {
62
- name: [],
63
- tag: criteria.tags.map(tagToProto),
60
+ return [
61
+ {
62
+ tagsAndNames: {
63
+ name: [],
64
+ tag: criteria.tags.map(tagToProto),
65
+ },
64
66
  },
65
- }]
67
+ ]
66
68
 
67
69
  case "type-restricted":
68
70
  // Inner must be tags or any-tag
69
- const innerTags = criteria.inner.kind === "tags"
70
- ? criteria.inner.tags.map(tagToProto)
71
- : []
72
- return [{
73
- tagsAndNames: {
74
- name: [...criteria.types],
75
- tag: innerTags,
71
+ const innerTags = criteria.inner.kind === "tags" ? criteria.inner.tags.map(tagToProto) : []
72
+ return [
73
+ {
74
+ tagsAndNames: {
75
+ name: [...criteria.types],
76
+ tag: innerTags,
77
+ },
76
78
  },
77
- }]
79
+ ]
78
80
 
79
81
  case "either":
80
82
  // Flatten all sub-criteria into a list of criterions (OR semantics)
@@ -111,9 +113,14 @@ function createEventConverters(serializer: Serializer) {
111
113
  },
112
114
 
113
115
  eventFromProto(protoEvent: ProtoEvent, tags: ProtoTag[]): EventMessage {
114
- const payload = protoEvent.payload.length > 0
115
- ? serializer.deserialize({ data: protoEvent.payload, type: protoEvent.name, revision: protoEvent.version })
116
- : {}
116
+ const payload =
117
+ protoEvent.payload.length > 0
118
+ ? serializer.deserialize({
119
+ data: protoEvent.payload,
120
+ type: protoEvent.name,
121
+ revision: protoEvent.version,
122
+ })
123
+ : {}
117
124
 
118
125
  const metadata: Record<string, unknown> = {}
119
126
  for (const [k, v] of Object.entries(protoEvent.metadata)) {
@@ -139,28 +146,25 @@ function createEventConverters(serializer: Serializer) {
139
146
  // ---------------------------------------------------------------------------
140
147
 
141
148
  /**
142
- * Creates an EventStore implementation backed by Axon Server's DCB event store.
149
+ * An EventStore over Axon Server's DCB event store, in one context.
143
150
  *
144
151
  * This bridges the framework's EventStore interface to the gRPC
145
152
  * DcbEventStore service, handling conversion between framework types
146
153
  * and proto messages.
147
154
  *
155
+ * `context` is Axon Server's tenancy boundary and is a per-call header, so
156
+ * several contexts share the one channel `conn` holds — see `contextView`. The
157
+ * serializer is the connection's: one codec for everything this client puts on
158
+ * the wire.
159
+ *
148
160
  * The {@link open} method returns a persistent {@link MessageStream} backed by
149
161
  * a single gRPC Stream RPC call that stays open indefinitely, aligned with
150
162
  * Java's infinite {@code ResultStream}.
151
163
  */
152
- export function axonServerEventStore(connection: AxonServerConnection, serializer: Serializer): EventStore {
164
+ export function axonServerEventStore(conn: AxonServerStoreSource, context: string): EventStore {
165
+ const { connection, serializer, metadata: createAxonMetadata } = contextView(conn, context)
153
166
  const { eventToProto, eventFromProto } = createEventConverters(serializer)
154
167
 
155
- function createAxonMetadata(): Metadata {
156
- const axonMetadata = new Metadata()
157
- axonMetadata.set("AxonIQ-Context", connection.config.context)
158
- if (connection.config.token) {
159
- axonMetadata.set("AxonIQ-Access-Token", connection.config.token)
160
- }
161
- return axonMetadata
162
- }
163
-
164
168
  // Push-based subscriber registry (EventBus.subscribe contract). Axon Server's
165
169
  // own distribution is the server-side Stream RPC (see open()); these in-process
166
170
  // subscribers are notified best-effort on every successful local append.
@@ -177,7 +181,7 @@ export function axonServerEventStore(connection: AxonServerConnection, serialize
177
181
 
178
182
  return {
179
183
  async source(condition: SourcingCondition): Promise<SourcingResult> {
180
- const criterions = criteriaToCriterions(condition.criteria)
184
+ const criterions = criteriaToCriterions(compileQuery(condition.query))
181
185
 
182
186
  const request = {
183
187
  fromSequence: condition.start ?? 0n,
@@ -213,10 +217,12 @@ export function axonServerEventStore(connection: AxonServerConnection, serialize
213
217
  ): Promise<AppendTransaction> {
214
218
  const taggedEvents = newEvents.map(eventToProto)
215
219
  const request = {
216
- condition: condition ? {
217
- consistencyMarker: condition.marker.position,
218
- criterion: criteriaToCriterions(condition.criteria),
219
- } : undefined,
220
+ condition: condition
221
+ ? {
222
+ consistencyMarker: condition.marker.position,
223
+ criterion: criteriaToCriterions(compileQuery(condition.query)),
224
+ }
225
+ : undefined,
220
226
  event: taggedEvents,
221
227
  }
222
228
 
@@ -229,7 +235,9 @@ export function axonServerEventStore(connection: AxonServerConnection, serialize
229
235
  async function* requestStream() {
230
236
  yield request
231
237
  }
232
- const response = await connection.eventStore.append(requestStream(), { metadata: createAxonMetadata() })
238
+ const response = await connection.eventStore.append(requestStream(), {
239
+ metadata: createAxonMetadata(),
240
+ })
233
241
  responseMarker = response.consistencyMarker
234
242
  await notifySubscribers(newEvents)
235
243
  },
@@ -252,7 +260,7 @@ export function axonServerEventStore(connection: AxonServerConnection, serialize
252
260
  },
253
261
 
254
262
  open(condition: StreamingCondition): MessageStream<SequencedEvent> {
255
- const criterions = condition.criteria ? criteriaToCriterions(condition.criteria) : []
263
+ const criterions = condition.query ? criteriaToCriterions(compileQuery(condition.query)) : []
256
264
 
257
265
  const request = {
258
266
  fromSequence: condition.position,
@@ -1,10 +1,8 @@
1
- import type { SnapshotStore, Snapshot } from "@kronos-ts/eventsourcing"
2
- import type { Serializer } from "@kronos-ts/common"
3
- import type { AxonServerConnection } from "./connection.js"
4
- import type {
5
- Snapshot as ProtoSnapshot,
6
- } from "./generated/dcb.js"
7
- import { Metadata } from "nice-grpc"
1
+ import type { SnapshotStore, Snapshot } from "@kronos-ts/core"
2
+ import type { Serializer } from "@kronos-ts/core"
3
+ import type { AxonServerStoreSource } from "./connection.js"
4
+ import { contextView } from "./context-view.js"
5
+ import type { Snapshot as ProtoSnapshot } from "./generated/dcb.js"
8
6
 
9
7
  // ---------------------------------------------------------------------------
10
8
  // Conversion — framework Snapshot ↔ proto Snapshot
@@ -26,9 +24,10 @@ function createSnapshotConverters(serializer: Serializer) {
26
24
  },
27
25
 
28
26
  snapshotFromProto(proto: ProtoSnapshot, position: bigint): Snapshot {
29
- const payload = proto.payload.length > 0
30
- ? serializer.deserialize({ data: proto.payload, type: "snapshot", revision: "" })
31
- : {}
27
+ const payload =
28
+ proto.payload.length > 0
29
+ ? serializer.deserialize({ data: proto.payload, type: "snapshot", revision: "" })
30
+ : {}
32
31
 
33
32
  return {
34
33
  position,
@@ -50,27 +49,20 @@ function encodeKey(stateName: string, id: unknown): Uint8Array {
50
49
  // ---------------------------------------------------------------------------
51
50
 
52
51
  /**
53
- * Creates a SnapshotStore backed by Axon Server's gRPC snapshot service.
52
+ * A SnapshotStore over Axon Server's gRPC snapshot service, in one context.
54
53
  *
55
- * Uses the `DcbSnapshotStore` gRPC service to store and retrieve
56
- * state snapshots. Payload serialization uses the configured
57
- * Serializer (defaults to JSON).
54
+ * Uses the `DcbSnapshotStore` gRPC service to store and retrieve state
55
+ * snapshots. `context` is a per-call header, so this shares the one channel
56
+ * `conn` holds with every other context — see `contextView`. Payloads go
57
+ * through the connection's serializer.
58
58
  */
59
59
  export function axonServerSnapshotStore(
60
- connection: AxonServerConnection,
61
- serializer: Serializer,
60
+ conn: AxonServerStoreSource,
61
+ context: string,
62
62
  ): SnapshotStore {
63
+ const { connection, serializer, metadata: createAxonMetadata } = contextView(conn, context)
63
64
  const { snapshotToProto, snapshotFromProto } = createSnapshotConverters(serializer)
64
65
 
65
- function createAxonMetadata(): Metadata {
66
- const axonMetadata = new Metadata()
67
- axonMetadata.set("AxonIQ-Context", connection.config.context)
68
- if (connection.config.token) {
69
- axonMetadata.set("AxonIQ-Access-Token", connection.config.token)
70
- }
71
- return axonMetadata
72
- }
73
-
74
66
  return {
75
67
  async store(stateName: string, id: unknown, snapshot: Snapshot): Promise<void> {
76
68
  await connection.snapshotStore.add(