@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
package/src/connection.ts CHANGED
@@ -1,11 +1,23 @@
1
- import { createChannel, createClient, type Channel, type Client, type ChannelCredentials } from "nice-grpc"
1
+ import {
2
+ createChannel,
3
+ createClient,
4
+ type Channel,
5
+ type Client,
6
+ type ChannelCredentials,
7
+ } from "nice-grpc"
2
8
  import { ChannelCredentials as GrpcChannelCredentials } from "@grpc/grpc-js"
3
- import { Metadata } from "nice-grpc"
4
9
  import { readFileSync } from "node:fs"
10
+ import { withRetry, healthCheck, type ResilienceConfig, type Serializer } from "@kronos-ts/core"
5
11
  import { PlatformServiceDefinition } from "./generated/control.js"
6
12
  import { CommandServiceDefinition } from "./generated/command.js"
7
13
  import { QueryServiceDefinition } from "./generated/query.js"
8
14
  import { DcbEventStoreDefinition, DcbSnapshotStoreDefinition } from "./generated/dcb.js"
15
+ import { shutdownLatch, type ShutdownLatch } from "./shutdown-latch.js"
16
+ import {
17
+ platformConnection,
18
+ type PlatformConnection,
19
+ type PlatformServiceOptions,
20
+ } from "./platform-service.js"
9
21
 
10
22
  /**
11
23
  * Configuration for connecting to Axon Server.
@@ -84,7 +96,12 @@ export interface AxonServerConnectionConfig {
84
96
  }
85
97
  }
86
98
 
87
- export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "closed"
99
+ export type ConnectionState =
100
+ | "disconnected"
101
+ | "connecting"
102
+ | "connected"
103
+ | "reconnecting"
104
+ | "closed"
88
105
 
89
106
  /**
90
107
  * An active connection to Axon Server, providing typed gRPC clients
@@ -159,7 +176,11 @@ export function connectToAxonServer(config: AxonServerConnectionConfig): AxonSer
159
176
  const rootCerts = sslConfig.certFile ? readFileSync(sslConfig.certFile) : null
160
177
  const clientKey = sslConfig.clientKeyFile ? readFileSync(sslConfig.clientKeyFile) : null
161
178
  const clientCert = sslConfig.clientCertFile ? readFileSync(sslConfig.clientCertFile) : null
162
- credentials = GrpcChannelCredentials.createSsl(rootCerts, clientKey, clientCert) as ChannelCredentials
179
+ credentials = GrpcChannelCredentials.createSsl(
180
+ rootCerts,
181
+ clientKey,
182
+ clientCert,
183
+ ) as ChannelCredentials
163
184
  }
164
185
 
165
186
  // gRPC channel options — keepalive to maintain persistent connections
@@ -170,9 +191,10 @@ export function connectToAxonServer(config: AxonServerConnectionConfig): AxonSer
170
191
  }
171
192
 
172
193
  // Build server address list for failover
173
- const serverAddresses = config.servers && config.servers.length > 0
174
- ? config.servers
175
- : [`${resolvedConfig.host}:${resolvedConfig.port}`]
194
+ const serverAddresses =
195
+ config.servers && config.servers.length > 0
196
+ ? config.servers
197
+ : [`${resolvedConfig.host}:${resolvedConfig.port}`]
176
198
 
177
199
  let currentServerIndex = 0
178
200
 
@@ -202,15 +224,29 @@ export function connectToAxonServer(config: AxonServerConnectionConfig): AxonSer
202
224
  let clients = createClients()
203
225
 
204
226
  const connection: AxonServerConnection = {
205
- get channel() { return channel },
206
- get platform() { return clients.platform },
207
- get commands() { return clients.commands },
208
- get queries() { return clients.queries },
209
- get eventStore() { return clients.eventStore },
210
- get snapshotStore() { return clients.snapshotStore },
227
+ get channel() {
228
+ return channel
229
+ },
230
+ get platform() {
231
+ return clients.platform
232
+ },
233
+ get commands() {
234
+ return clients.commands
235
+ },
236
+ get queries() {
237
+ return clients.queries
238
+ },
239
+ get eventStore() {
240
+ return clients.eventStore
241
+ },
242
+ get snapshotStore() {
243
+ return clients.snapshotStore
244
+ },
211
245
  config: resolvedConfig,
212
246
 
213
- get state() { return state },
247
+ get state() {
248
+ return state
249
+ },
214
250
 
215
251
  onReconnect(callback) {
216
252
  reconnectCallbacks.push(callback)
@@ -246,15 +282,17 @@ export function connectToAxonServer(config: AxonServerConnectionConfig): AxonSer
246
282
 
247
283
  // Notify listeners that we're back
248
284
  for (const cb of reconnectCallbacks) {
249
- try { cb() } catch { /* ignore listener errors */ }
285
+ try {
286
+ cb()
287
+ } catch {
288
+ /* ignore listener errors */
289
+ }
250
290
  }
251
291
  return
252
292
  } catch (err) {
253
293
  if (maxAttempts > 0 && attempt >= maxAttempts) {
254
294
  state = "disconnected"
255
- throw new Error(
256
- `Failed to reconnect after ${attempt} attempts: ${err}`,
257
- )
295
+ throw new Error(`Failed to reconnect after ${attempt} attempts: ${err}`)
258
296
  }
259
297
 
260
298
  // Exponential backoff: base interval * 2^attempt, capped at 30s
@@ -270,3 +308,217 @@ export function connectToAxonServer(config: AxonServerConnectionConfig): AxonSer
270
308
 
271
309
  return connection
272
310
  }
311
+
312
+ // ---------------------------------------------------------------------------
313
+ // The shared RESOURCE: one channel, the platform stream on it, start()/close()
314
+ // ---------------------------------------------------------------------------
315
+
316
+ /**
317
+ * Everything the shared Axon Server resource needs: where to dial, and how to
318
+ * put a payload on the wire.
319
+ *
320
+ * THE SERIALIZER IS A PROPERTY OF THIS CLIENT'S WIRE, not of a context and not
321
+ * of a bus. Every event, snapshot, command payload and query result this
322
+ * process exchanges with Axon Server goes through the same codec, so it is
323
+ * named once, here — which is also what leaves
324
+ * `axonServerEventStore(conn, context)` and `axonServerCommandBus(conn, local)`
325
+ * their honest two-argument shapes.
326
+ */
327
+ export interface AxonServerConnectionOptions extends AxonServerConnectionConfig {
328
+ /** Payload codec for every message this client exchanges with Axon Server. */
329
+ serializer: Serializer
330
+ /** Retry / health-check policy for the initial connect and stream re-establishment. */
331
+ resilience?: Partial<ResilienceConfig>
332
+ /** Platform stream tuning — heartbeat and processor-status cadence. */
333
+ platformService?: PlatformServiceOptions
334
+ /**
335
+ * How long {@link AxonServerConnectionHandle.start} waits for Axon Server's
336
+ * routing tables to register the subscribe frames sent on the command/query
337
+ * streams. This is the entire data-path readiness barrier.
338
+ *
339
+ * It is a timed wait rather than an observed signal because nothing on the
340
+ * client can observe it: subscribes travel on the bus streams, and the
341
+ * platform stream — which is where an ack would arrive — is a different
342
+ * stream that Axon Server holds open silently after `register`. Default:
343
+ * 1000, matching the legacy enhancer.
344
+ */
345
+ busSubscriptionAckDelayMs?: number
346
+ }
347
+
348
+ /**
349
+ * What a context-scoped STORE borrows from the connection: the gRPC clients and
350
+ * the codec. Narrower than the handle on purpose — a test can drive a store
351
+ * with a fake `connection` and nothing else.
352
+ */
353
+ export interface AxonServerStoreSource {
354
+ readonly connection: AxonServerConnection
355
+ readonly serializer: Serializer
356
+ }
357
+
358
+ /** What a BUS borrows: a store's two, plus the drain latch and the retry policy. */
359
+ export interface AxonServerBusSource extends AxonServerStoreSource {
360
+ /**
361
+ * The connection-wide drain latch. In-flight dispatches register on it and
362
+ * `close()` waits for them, so a bus never has the transport pulled out from
363
+ * under a call it is still awaiting.
364
+ */
365
+ readonly shutdown: ShutdownLatch
366
+ readonly resilience?: Partial<ResilienceConfig>
367
+ }
368
+
369
+ /** What the CONTROL PLANE borrows: the platform stream, and only that. */
370
+ export interface AxonServerPlatformSource {
371
+ readonly platform: PlatformConnection
372
+ }
373
+
374
+ /**
375
+ * The RESOURCE an Axon Server deployment shares: one gRPC channel, the platform
376
+ * stream riding on it, and the lifecycle pair.
377
+ *
378
+ * The stores and buses are NOT on it — `axonServerEventStore(conn, context)`,
379
+ * `axonServerCommandBus(conn, local)` and friends are plain functions over
380
+ * this, and a caller who wants only commands builds only that one. Multiple
381
+ * contexts share this ONE channel: the per-call `AxonIQ-Context` header is what
382
+ * separates them.
383
+ */
384
+ export interface AxonServerConnectionHandle extends AxonServerBusSource, AxonServerPlatformSource {
385
+ /** Config after defaults — the resolved host, context, client id. */
386
+ readonly config: AxonServerConnection["config"]
387
+ /**
388
+ * DATA-PATH START. Two things, both data path:
389
+ *
390
+ * 1. arm heartbeat-driven reconnect detection on the platform stream, and
391
+ * 2. wait until Axon Server can route to the handlers subscribed on the bus
392
+ * streams.
393
+ *
394
+ * Call AFTER `kronos` — the subscribe frames must already be on the wire for
395
+ * the readiness wait to mean anything. Takes no arguments and arms no
396
+ * control-plane state.
397
+ */
398
+ start(): Promise<void>
399
+ /** Drain in-flight bus work, stop the platform stream, close the channel. */
400
+ close(): Promise<void>
401
+ }
402
+
403
+ /**
404
+ * Open the shared Axon Server connection.
405
+ *
406
+ * ```ts
407
+ * const axon = await axonServerConnection({
408
+ * componentName: "university-service",
409
+ * host, port,
410
+ * serializer: jsonSerializer(),
411
+ * })
412
+ * const eventStore = axonServerEventStore(axon, "default")
413
+ * const snapshotStore = axonServerSnapshotStore(axon, "default")
414
+ * const commandBus = interceptingCommandBus(
415
+ * axonServerCommandBus(axon, simpleCommandBus(unitOfWork)), lineage)
416
+ * const queryBus = interceptingQueryBus(
417
+ * axonServerQueryBus(axon, simpleQueryBus(unitOfWork)), lineage)
418
+ *
419
+ * const app = kronos({ states, commandHandlers, queryHandlers })
420
+ * await axon.start() // readiness barrier: the server can route to us
421
+ * // opt in to remote administration
422
+ * const control = await axonServerControlPlane(axon, app.processors.values())
423
+ * // …
424
+ * await app.stop(); await control.close(); await axon.close()
425
+ * ```
426
+ *
427
+ * ASYNC ON PURPOSE. Connecting before anything is built is what removes the
428
+ * lazy proxies and subscribe-buffering the container version needed: by the
429
+ * time `kronos` subscribes a handler, the gRPC streams are already live.
430
+ *
431
+ * REMOTE ADMINISTRATION IS NOT IN HERE. Processor instructions and processor
432
+ * status reporting are the platform CONTROL PLANE — they are neither
433
+ * persistence nor transport, and lived on this object only because they share
434
+ * the gRPC connection. See `control-plane.ts`.
435
+ *
436
+ * Axon-specific protocol invariants are preserved byte-for-byte:
437
+ *
438
+ * - CLIENT_SUPPORTS_STREAMING capability advertised on every dispatched query;
439
+ * - AxonIQ-Context + AxonIQ-Access-Token gRPC metadata headers on every
440
+ * outbound stream/RPC (see `contextView`);
441
+ * - permits-AFTER-subscriptions stream ordering on the initial handshake AND
442
+ * on reconnect;
443
+ * - shutdown ordering: drain latch → platform.stop → connection.close.
444
+ */
445
+ export async function axonServerConnection(
446
+ options: AxonServerConnectionOptions,
447
+ ): Promise<AxonServerConnectionHandle> {
448
+ const {
449
+ serializer,
450
+ resilience,
451
+ platformService,
452
+ busSubscriptionAckDelayMs,
453
+ ...connectionConfig
454
+ } = options
455
+
456
+ const connection = await withRetry(async () => connectToAxonServer(connectionConfig), {
457
+ event: "initial-connect",
458
+ ...resilience,
459
+ })
460
+
461
+ // Health-check ping with warn-then-continue (D-100). AxonServerConnection has
462
+ // no dedicated probe surface today; the gRPC channel itself is created
463
+ // eagerly in connectToAxonServer so the meaningful probe is a round-trip — we
464
+ // approximate via a soft no-op promise that satisfies the threshold contract.
465
+ // Real network failure is surfaced by the first bus call against the channel.
466
+ await healthCheck(async () => undefined, {
467
+ thresholdMs: resilience?.healthCheckThresholdMs,
468
+ log: resilience?.log,
469
+ })
470
+
471
+ // ONE latch for the connection. Both buses ride the same channel, so "drain
472
+ // in-flight work before the transport goes away" is one question, not two.
473
+ const shutdown = shutdownLatch()
474
+
475
+ // Built here, started by the control plane (or by `start()` below for the data
476
+ // path's half). Constructing it eagerly is what lets the control plane be a
477
+ // separate object at all — and it keeps `platformService` tuning and `stop()`
478
+ // ownership in one place, so the documented shutdown order holds whether or
479
+ // not anyone opted in.
480
+ const platform = platformConnection(connection, platformService)
481
+
482
+ return {
483
+ connection,
484
+ config: connection.config,
485
+ serializer,
486
+ resilience,
487
+ shutdown,
488
+ platform,
489
+
490
+ async start() {
491
+ // RECONNECT DETECTION IS DATA PATH. The heartbeat on the platform stream
492
+ // is what notices a dead channel and calls `connection.reconnect()`; both
493
+ // buses hook `connection.onReconnect(...)` to rebuild their own streams.
494
+ // Arming it used to be a side effect of `platform.start()`, which only
495
+ // `axonServerControlPlane(...)` calls — so a service that never opted into
496
+ // remote administration had NO reconnect detection at all and would sit on
497
+ // a dead channel forever. It is armed here, unconditionally.
498
+ //
499
+ // `armConnectionMonitoring()` opens the stream and starts heartbeats but
500
+ // arms NO processor status reporting; that stays the control plane's, and
501
+ // a later `platform.start()` adds it to this same live stream. Both calls
502
+ // are idempotent, so either order works.
503
+ await platform.armConnectionMonitoring()
504
+
505
+ // The only thing the data path has to wait for: Axon Server's
506
+ // command/query routing tables registering the subscribe frames sent on
507
+ // the BUS streams. It cannot be derived from the platform stream, because
508
+ // subscribes travel on a different stream entirely — and the platform
509
+ // stream's own `subscriptionsAcked()` latch says nothing about them (it
510
+ // latches unconditionally once `register` has been flushed). So this
511
+ // barrier is the settle wait, deliberately independent of whether the
512
+ // platform stream is up at all. The legacy enhancer carried the same wait.
513
+ await new Promise((r) => setTimeout(r, busSubscriptionAckDelayMs ?? 1000))
514
+ },
515
+
516
+ async close() {
517
+ await shutdown.initiateShutdown()
518
+ // Idempotent, and independent of `control.close()` — a connection that was
519
+ // never administered still stops a platform stream someone else started.
520
+ platform.stop()
521
+ connection.close()
522
+ },
523
+ }
524
+ }
@@ -0,0 +1,46 @@
1
+ import { Metadata } from "nice-grpc"
2
+ import type { AxonServerStoreSource } from "./connection.js"
3
+
4
+ /**
5
+ * A context-scoped view of the ONE shared connection.
6
+ *
7
+ * Contexts are Axon Server's tenancy boundary, and they are a per-CALL header —
8
+ * not a per-channel property. `AxonIQ-Context` selects the context on every
9
+ * outbound stream and RPC, so `axonServerEventStore(conn, "tenant-a")` and
10
+ * `axonServerEventStore(conn, "tenant-b")` are two views over one gRPC channel,
11
+ * exactly as one connection served one context before. Nothing about the
12
+ * channel, the codec or the drain latch differs between them; only this header
13
+ * does, which is why the whole difference fits in one small record.
14
+ */
15
+ export interface AxonServerContextView extends AxonServerStoreSource {
16
+ /** The Axon Server context every call through this view addresses. */
17
+ readonly context: string
18
+ /**
19
+ * The gRPC metadata headers Axon Server requires. `AxonIQ-Context` is
20
+ * mandatory (it identifies the context); `AxonIQ-Access-Token` is optional
21
+ * auth. Both must be attached to every outbound stream/RPC — preserved
22
+ * verbatim from the legacy enhancer.
23
+ *
24
+ * A function rather than a value so a caller that opens one long-lived stream
25
+ * can hoist it, and one that makes many unary calls can hand each its own.
26
+ */
27
+ metadata(): Metadata
28
+ }
29
+
30
+ /** Scope a connection to one Axon Server context. */
31
+ export function contextView(source: AxonServerStoreSource, context: string): AxonServerContextView {
32
+ const { connection, serializer } = source
33
+ return {
34
+ connection,
35
+ serializer,
36
+ context,
37
+ metadata() {
38
+ const metadata = new Metadata()
39
+ metadata.set("AxonIQ-Context", context)
40
+ if (connection.config.token) {
41
+ metadata.set("AxonIQ-Access-Token", connection.config.token)
42
+ }
43
+ return metadata
44
+ },
45
+ }
46
+ }
@@ -11,19 +11,19 @@
11
11
  * 2. outbound — the client periodically reports each processor's status so
12
12
  * the Axon Dashboard can render it.
13
13
  *
14
- * It lived inside `axonServer().start()` only because it shares the gRPC
14
+ * It lived inside the backend's `start()` only because it shares the gRPC
15
15
  * connection with the data path. It is now separate and OPT-IN: a service that
16
- * nobody administers remotely simply never builds one, and `axonServer()`
17
- * matches `postgres()` / `rabbitmq()` components plus an argument-less
18
- * `start()` readiness barrier.
16
+ * nobody administers remotely simply never builds one, and
17
+ * `axonServerConnection()` is left with an argument-less `start()` readiness
18
+ * barrier and nothing else.
19
19
  *
20
20
  * ```ts
21
- * const axon = await axonServer({ ... })
22
- * const app = kronos({ components: { ...axon.components }, modules })
21
+ * const axon = await axonServerConnection({ ... })
22
+ * const app = kronos({ states, commandHandlers, queryHandlers, eventHandlers })
23
23
  * await axon.start() // data path only
24
24
  *
25
25
  * // opt in to remote administration
26
- * const control = await axonServerControlPlane(axon.platform, app.processors.values())
26
+ * const control = await axonServerControlPlane(axon, app.processors.values())
27
27
  * // …
28
28
  * await app.stop(); await control.close(); await axon.close()
29
29
  * ```
@@ -38,7 +38,7 @@
38
38
  * start — all three inside one function, so there is no call order for a
39
39
  * caller to get wrong.
40
40
  */
41
- import type { PlatformConnection } from "./platform-service.js"
41
+ import type { AxonServerPlatformSource } from "./connection.js"
42
42
  import type { ProcessorStatus, SegmentStatus } from "./event-processor-info.js"
43
43
 
44
44
  /**
@@ -90,9 +90,7 @@ export interface AxonServerControlPlane {
90
90
  }
91
91
 
92
92
  /** Map the managed processors into the status shape the platform stream reports. */
93
- function processorStatuses(
94
- processors: Iterable<ManagedEventProcessor>,
95
- ): ProcessorStatus[] {
93
+ function processorStatuses(processors: Iterable<ManagedEventProcessor>): ProcessorStatus[] {
96
94
  return Array.from(processors, (proc) => {
97
95
  const isStreamingProcessor = proc.supportsReset?.() !== false
98
96
  const perSegment = proc.processingStatus?.()
@@ -132,9 +130,10 @@ function processorStatuses(
132
130
  /**
133
131
  * Wire remote administration onto an Axon Server platform stream and start it.
134
132
  *
135
- * `platform` is `axonServer(...).platform` the backend builds the platform
136
- * connection (it owns the gRPC connection and the `platformService` tuning) but
137
- * never starts it, because starting it is exactly what this function is for.
133
+ * `conn` is the shared connection from `axonServerConnection(...)`. It owns the
134
+ * gRPC channel and the `platformService` tuning, and it builds the platform
135
+ * stream but it never starts the control-plane half, because starting that is
136
+ * exactly what this function is for.
138
137
  *
139
138
  * `processors` are the LIVE processor instances, which only exist after
140
139
  * `kronos` has built them — that is why this cannot be folded back into the
@@ -143,7 +142,7 @@ function processorStatuses(
143
142
  * Caveat on that call: `kronos` types `processors` as
144
143
  * `ReadonlyMap<string, unknown>`, so `.values()` needs a cast today —
145
144
  * `app.processors.values() as Iterable<ManagedEventProcessor>`. Narrowing that
146
- * map in `@kronos-ts/app` would remove the cast; this package cannot.
145
+ * map in `@kronos-ts/core` would remove the cast; this package cannot.
147
146
  *
148
147
  * The collection is SNAPSHOTTED into a name-keyed map here, once. That is
149
148
  * deliberate: a one-shot iterator (`Map.values()` is one) would otherwise yield
@@ -152,9 +151,10 @@ function processorStatuses(
152
151
  * only the membership of the set is fixed at construction.
153
152
  */
154
153
  export async function axonServerControlPlane(
155
- platform: PlatformConnection,
154
+ conn: AxonServerPlatformSource,
156
155
  processors: Iterable<ManagedEventProcessor> = [],
157
156
  ): Promise<AxonServerControlPlane> {
157
+ const { platform } = conn
158
158
  // Name-keyed view so server-initiated instructions route to the right one.
159
159
  const byName = new Map<string, ManagedEventProcessor>()
160
160
  for (const proc of processors) byName.set(proc.name, proc)
@@ -181,7 +181,7 @@ export async function axonServerControlPlane(
181
181
 
182
182
  platform.registerProcessorStatusSupplier(() => processorStatuses(byName.values()))
183
183
 
184
- // ORDERING: strictly AFTER both registrations — see the file-level JSDoc.
184
+ // ORDERING: strictly AFTER both handlers — see the file-level JSDoc.
185
185
  // An instruction arriving in the gap would be dropped; an early status
186
186
  // request would find no supplier.
187
187
  await platform.start()
package/src/index.ts CHANGED
@@ -1,29 +1,24 @@
1
1
  export {
2
2
  type AxonServerConnectionConfig,
3
3
  type AxonServerConnection,
4
+ type AxonServerConnectionOptions,
5
+ type AxonServerConnectionHandle,
6
+ type AxonServerStoreSource,
7
+ type AxonServerBusSource,
8
+ type AxonServerPlatformSource,
4
9
  connectToAxonServer,
10
+ axonServerConnection,
5
11
  } from "./connection.js"
6
12
 
7
- export {
8
- type AxonServerConnectionManager,
9
- connectionManager,
10
- } from "./connection-manager.js"
11
-
12
- export {
13
- axonServerEventStore,
14
- } from "./axon-server-event-store.js"
13
+ export { axonServerEventStore } from "./axon-server-event-store.js"
15
14
 
16
- export {
17
- axonServerSnapshotStore,
18
- } from "./axon-server-snapshot-store.js"
15
+ export { axonServerSnapshotStore } from "./axon-server-snapshot-store.js"
19
16
 
20
17
  export {
21
- axonServer,
22
- distributedCommandBus,
23
- distributedQueryBus,
24
- type AxonServerConfig,
25
- type AxonServerBackend,
26
- type AxonServerComponents,
18
+ axonServerCommandBus,
19
+ axonServerQueryBus,
20
+ type AxonServerCommandBusOptions,
21
+ type AxonServerQueryBusOptions,
27
22
  type FlowControlConfig,
28
23
  type ProcessingInstructions,
29
24
  } from "./axon-server.js"
@@ -83,4 +78,3 @@ export {
83
78
  mapErrorCode,
84
79
  isTransientError,
85
80
  } from "./errors.js"
86
- export type { AxonServerOptions } from "./axon-server.js"
@@ -1,4 +1,4 @@
1
- import type { Metadata } from "@kronos-ts/common"
1
+ import type { Metadata } from "@kronos-ts/core"
2
2
  import type { MetaDataValue } from "./generated/common.js"
3
3
 
4
4
  /**