@kronos-ts/axon-server 0.1.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 (106) hide show
  1. package/dist/axon-server-event-store.d.ts +16 -0
  2. package/dist/axon-server-event-store.d.ts.map +1 -0
  3. package/dist/axon-server-event-store.js +282 -0
  4. package/dist/axon-server-event-store.js.map +1 -0
  5. package/dist/axon-server-snapshot-store.d.ts +12 -0
  6. package/dist/axon-server-snapshot-store.d.ts.map +1 -0
  7. package/dist/axon-server-snapshot-store.js +88 -0
  8. package/dist/axon-server-snapshot-store.js.map +1 -0
  9. package/dist/axon-server.d.ts +115 -0
  10. package/dist/axon-server.d.ts.map +1 -0
  11. package/dist/axon-server.js +986 -0
  12. package/dist/axon-server.js.map +1 -0
  13. package/dist/connection-manager.d.ts +49 -0
  14. package/dist/connection-manager.d.ts.map +1 -0
  15. package/dist/connection-manager.js +37 -0
  16. package/dist/connection-manager.js.map +1 -0
  17. package/dist/connection.d.ts +129 -0
  18. package/dist/connection.d.ts.map +1 -0
  19. package/dist/connection.js +130 -0
  20. package/dist/connection.js.map +1 -0
  21. package/dist/errors.d.ts +96 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/errors.js +189 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/event-processor-info.d.ts +35 -0
  26. package/dist/event-processor-info.d.ts.map +1 -0
  27. package/dist/event-processor-info.js +28 -0
  28. package/dist/event-processor-info.js.map +1 -0
  29. package/dist/flow-controlled-sender.d.ts +30 -0
  30. package/dist/flow-controlled-sender.d.ts.map +1 -0
  31. package/dist/flow-controlled-sender.js +60 -0
  32. package/dist/flow-controlled-sender.js.map +1 -0
  33. package/dist/generated/command.d.ts +158 -0
  34. package/dist/generated/command.d.ts.map +1 -0
  35. package/dist/generated/command.js +970 -0
  36. package/dist/generated/command.js.map +1 -0
  37. package/dist/generated/common.d.ts +130 -0
  38. package/dist/generated/common.d.ts.map +1 -0
  39. package/dist/generated/common.js +908 -0
  40. package/dist/generated/common.js.map +1 -0
  41. package/dist/generated/control.d.ts +293 -0
  42. package/dist/generated/control.d.ts.map +1 -0
  43. package/dist/generated/control.js +1938 -0
  44. package/dist/generated/control.js.map +1 -0
  45. package/dist/generated/dcb.d.ts +650 -0
  46. package/dist/generated/dcb.d.ts.map +1 -0
  47. package/dist/generated/dcb.js +2943 -0
  48. package/dist/generated/dcb.js.map +1 -0
  49. package/dist/generated/event.d.ts +667 -0
  50. package/dist/generated/event.d.ts.map +1 -0
  51. package/dist/generated/event.js +3185 -0
  52. package/dist/generated/event.js.map +1 -0
  53. package/dist/generated/google/protobuf/empty.d.ts +30 -0
  54. package/dist/generated/google/protobuf/empty.d.ts.map +1 -0
  55. package/dist/generated/google/protobuf/empty.js +46 -0
  56. package/dist/generated/google/protobuf/empty.js.map +1 -0
  57. package/dist/generated/query.d.ts +300 -0
  58. package/dist/generated/query.d.ts.map +1 -0
  59. package/dist/generated/query.js +2183 -0
  60. package/dist/generated/query.js.map +1 -0
  61. package/dist/index.d.ts +12 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +12 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/message-size.d.ts +38 -0
  66. package/dist/message-size.d.ts.map +1 -0
  67. package/dist/message-size.js +57 -0
  68. package/dist/message-size.js.map +1 -0
  69. package/dist/metadata-conversion.d.ts +11 -0
  70. package/dist/metadata-conversion.d.ts.map +1 -0
  71. package/dist/metadata-conversion.js +51 -0
  72. package/dist/metadata-conversion.js.map +1 -0
  73. package/dist/outbound-stream.d.ts +15 -0
  74. package/dist/outbound-stream.d.ts.map +1 -0
  75. package/dist/outbound-stream.js +39 -0
  76. package/dist/outbound-stream.js.map +1 -0
  77. package/dist/platform-service.d.ts +119 -0
  78. package/dist/platform-service.d.ts.map +1 -0
  79. package/dist/platform-service.js +250 -0
  80. package/dist/platform-service.js.map +1 -0
  81. package/dist/shutdown-latch.d.ts +38 -0
  82. package/dist/shutdown-latch.d.ts.map +1 -0
  83. package/dist/shutdown-latch.js +51 -0
  84. package/dist/shutdown-latch.js.map +1 -0
  85. package/package.json +69 -0
  86. package/src/axon-server-event-store.ts +358 -0
  87. package/src/axon-server-snapshot-store.ts +118 -0
  88. package/src/axon-server.ts +1202 -0
  89. package/src/connection-manager.ts +88 -0
  90. package/src/connection.ts +272 -0
  91. package/src/errors.ts +223 -0
  92. package/src/event-processor-info.ts +62 -0
  93. package/src/flow-controlled-sender.ts +91 -0
  94. package/src/generated/command.ts +1231 -0
  95. package/src/generated/common.ts +1097 -0
  96. package/src/generated/control.ts +2419 -0
  97. package/src/generated/dcb.ts +3826 -0
  98. package/src/generated/event.ts +4076 -0
  99. package/src/generated/google/protobuf/empty.ts +84 -0
  100. package/src/generated/query.ts +2723 -0
  101. package/src/index.ts +75 -0
  102. package/src/message-size.ts +75 -0
  103. package/src/metadata-conversion.ts +46 -0
  104. package/src/outbound-stream.ts +52 -0
  105. package/src/platform-service.ts +361 -0
  106. package/src/shutdown-latch.ts +97 -0
@@ -0,0 +1,250 @@
1
+ import { createOutboundStream } from "./outbound-stream.js";
2
+ import { Metadata } from "nice-grpc";
3
+ import { toEventProcessorInfo } from "./event-processor-info.js";
4
+ /**
5
+ * Creates a PlatformService connection to Axon Server.
6
+ *
7
+ * The platform stream is the control plane — it:
8
+ * 1. Registers this client with Axon Server
9
+ * 2. Sends periodic heartbeats to verify connectivity
10
+ * 3. Receives instructions from Axon Server (split, merge, pause, resume)
11
+ */
12
+ export function createPlatformConnection(connection, options) {
13
+ const heartbeatIntervalMs = options?.heartbeatIntervalMs ?? 10000;
14
+ const heartbeatTimeoutMs = options?.heartbeatTimeoutMs ?? 7500;
15
+ const processorsNotificationRateMs = options?.processorsNotificationRateMs ?? 500;
16
+ const processorsNotificationInitialDelayMs = options?.processorsNotificationInitialDelayMs ?? 5000;
17
+ const instructionHandlers = [];
18
+ const processorStatusSuppliers = [];
19
+ let isConnected = false;
20
+ let heartbeatTimer = null;
21
+ let heartbeatTimeoutTimer = null;
22
+ let processorStatusTimer = null;
23
+ let lastHeartbeatResponse = Date.now();
24
+ let outbound = null;
25
+ /**
26
+ * Latches once Axon Server sends its first inbound message after
27
+ * registration — the earliest observable signal that the platform stream
28
+ * is fully wired (mirror of kronosdb Plan 09-03 / D-102, replaces the
29
+ * legacy 1-second sleep). Reset on every `start()` so a stop/start cycle
30
+ * re-arms the latch correctly.
31
+ */
32
+ let acked = false;
33
+ const grpcMetadata = new Metadata();
34
+ grpcMetadata.set("AxonIQ-Context", connection.config.context);
35
+ if (connection.config.token) {
36
+ grpcMetadata.set("AxonIQ-Access-Token", connection.config.token);
37
+ }
38
+ async function processInboundInstructions(inbound) {
39
+ try {
40
+ for await (const message of inbound) {
41
+ // First inbound message after start() = the platform has accepted our
42
+ // registration and is talking back. Latch the ack flag (mirror of
43
+ // kronosdb Plan 09-03 / D-102 — replaces the legacy 1s sleep).
44
+ acked = true;
45
+ // Parse instruction type
46
+ const instruction = parseInstruction(message);
47
+ if (instruction) {
48
+ for (const handler of instructionHandlers) {
49
+ try {
50
+ await handler(instruction);
51
+ }
52
+ catch (err) {
53
+ console.error("Platform instruction handler error:", err);
54
+ }
55
+ }
56
+ }
57
+ // Handle heartbeat response — track last response time for timeout detection
58
+ if (message.heartbeat) {
59
+ lastHeartbeatResponse = Date.now();
60
+ }
61
+ }
62
+ }
63
+ catch (err) {
64
+ if (isConnected) {
65
+ console.error("Platform stream error:", err);
66
+ isConnected = false;
67
+ }
68
+ }
69
+ }
70
+ function parseInstruction(message) {
71
+ if (message.requestReconnect) {
72
+ return { kind: "reconnect-request" };
73
+ }
74
+ // Processor control instructions
75
+ const ctrl = message.eventProcessorControl;
76
+ if (ctrl) {
77
+ const processorName = ctrl.processorName ?? "";
78
+ if (ctrl.pauseEventProcessor) {
79
+ return { kind: "pause-processor", processorName };
80
+ }
81
+ if (ctrl.startEventProcessor) {
82
+ return { kind: "start-processor", processorName };
83
+ }
84
+ if (ctrl.releaseSegment !== undefined) {
85
+ return { kind: "release-segment", processorName, segmentId: ctrl.releaseSegment.segmentId ?? 0 };
86
+ }
87
+ if (ctrl.splitEventProcessor !== undefined) {
88
+ return { kind: "split-segment", processorName, segmentId: ctrl.splitEventProcessor.segmentId ?? 0 };
89
+ }
90
+ if (ctrl.mergeEventProcessor !== undefined) {
91
+ return { kind: "merge-segment", processorName, segmentId: ctrl.mergeEventProcessor.segmentId ?? 0 };
92
+ }
93
+ }
94
+ // Topology change instructions
95
+ const topo = message.topologyChange;
96
+ if (topo) {
97
+ const componentName = topo.componentName ?? "";
98
+ if (topo.commandHandlerAdded) {
99
+ return { kind: "command-handler-added", componentName, commandName: topo.commandHandlerAdded.commandName ?? "" };
100
+ }
101
+ if (topo.commandHandlerRemoved) {
102
+ return { kind: "command-handler-removed", componentName, commandName: topo.commandHandlerRemoved.commandName ?? "" };
103
+ }
104
+ if (topo.queryHandlerAdded) {
105
+ return { kind: "query-handler-added", componentName, queryName: topo.queryHandlerAdded.queryName ?? "" };
106
+ }
107
+ if (topo.queryHandlerRemoved) {
108
+ return { kind: "query-handler-removed", componentName, queryName: topo.queryHandlerRemoved.queryName ?? "" };
109
+ }
110
+ }
111
+ return null;
112
+ }
113
+ function startHeartbeat() {
114
+ if (heartbeatTimer)
115
+ clearInterval(heartbeatTimer);
116
+ lastHeartbeatResponse = Date.now();
117
+ heartbeatTimer = setInterval(() => {
118
+ if (!isConnected || !outbound)
119
+ return;
120
+ // Check if last heartbeat response was too long ago
121
+ const timeSinceLastResponse = Date.now() - lastHeartbeatResponse;
122
+ if (timeSinceLastResponse > heartbeatTimeoutMs) {
123
+ console.warn(`Platform heartbeat timeout: no response in ${timeSinceLastResponse}ms ` +
124
+ `(threshold: ${heartbeatTimeoutMs}ms). Marking connection as lost.`);
125
+ isConnected = false;
126
+ connection.reconnect().catch((err) => {
127
+ console.error("Failed to reconnect after heartbeat timeout:", err);
128
+ });
129
+ return;
130
+ }
131
+ outbound.send({
132
+ heartbeat: {
133
+ clientId: connection.config.clientId,
134
+ },
135
+ instructionId: "",
136
+ });
137
+ }, heartbeatIntervalMs);
138
+ }
139
+ function startProcessorStatusReporting() {
140
+ if (processorStatusTimer)
141
+ clearInterval(processorStatusTimer);
142
+ // Initial delay before first report
143
+ setTimeout(() => {
144
+ if (!isConnected)
145
+ return;
146
+ reportProcessorStatus();
147
+ // Then report at the configured rate
148
+ processorStatusTimer = setInterval(() => {
149
+ if (!isConnected || !outbound)
150
+ return;
151
+ reportProcessorStatus();
152
+ }, processorsNotificationRateMs);
153
+ }, processorsNotificationInitialDelayMs);
154
+ }
155
+ function reportProcessorStatus() {
156
+ if (!outbound || processorStatusSuppliers.length === 0)
157
+ return;
158
+ for (const supplier of processorStatusSuppliers) {
159
+ try {
160
+ const statuses = supplier();
161
+ for (const status of statuses) {
162
+ outbound.send({
163
+ eventProcessorInfo: toEventProcessorInfo(status),
164
+ instructionId: "",
165
+ });
166
+ }
167
+ }
168
+ catch (err) {
169
+ console.warn("Failed to report processor status:", err);
170
+ }
171
+ }
172
+ }
173
+ return {
174
+ async start() {
175
+ if (isConnected)
176
+ return;
177
+ // Re-arm the ack latch so a stop/start cycle correctly re-waits.
178
+ acked = false;
179
+ outbound = createOutboundStream();
180
+ // Register with Axon Server
181
+ outbound.send({
182
+ register: {
183
+ clientId: connection.config.clientId,
184
+ componentName: connection.config.componentName,
185
+ version: "1.0.0",
186
+ tags: {},
187
+ },
188
+ instructionId: "",
189
+ });
190
+ // Open bidirectional stream
191
+ const inbound = connection.platform.openStream(outbound.iterable, {
192
+ metadata: grpcMetadata,
193
+ });
194
+ isConnected = true;
195
+ startHeartbeat();
196
+ startProcessorStatusReporting();
197
+ processInboundInstructions(inbound);
198
+ // Axon Server's PlatformService does NOT proactively emit an inbound
199
+ // frame in response to `register` — the stream is held open silently
200
+ // until either (a) the server pushes a topology / instruction event,
201
+ // or (b) one of our heartbeat pings round-trips back. That means the
202
+ // first-inbound-frame ack signal used by kronosdb (Plan 09-03 / D-102)
203
+ // doesn't fire deterministically here, and the processors-stage
204
+ // `withRetry({event: "per-operation"})` poll would otherwise hang.
205
+ //
206
+ // Axon-specific ack derivation: latch `acked = true` immediately once
207
+ // the outbound `register` frame has been flushed to the gRPC layer.
208
+ // Bus subscriptions (sent on the command/query streams, NOT the
209
+ // platform stream) are an orthogonal concern handled by the
210
+ // command/query bus reconnect path — the legacy 1-second sleep that
211
+ // we replaced was always covering register processing, not bus-side
212
+ // routability. Structurally this is the Axon Server equivalent of
213
+ // D-102: drop the magic-number wait, use the earliest deterministic
214
+ // observable signal that fits the underlying protocol.
215
+ acked = true;
216
+ },
217
+ stop() {
218
+ isConnected = false;
219
+ if (heartbeatTimer) {
220
+ clearInterval(heartbeatTimer);
221
+ heartbeatTimer = null;
222
+ }
223
+ if (heartbeatTimeoutTimer) {
224
+ clearTimeout(heartbeatTimeoutTimer);
225
+ heartbeatTimeoutTimer = null;
226
+ }
227
+ if (processorStatusTimer) {
228
+ clearInterval(processorStatusTimer);
229
+ processorStatusTimer = null;
230
+ }
231
+ if (outbound) {
232
+ outbound.close();
233
+ outbound = null;
234
+ }
235
+ },
236
+ onInstruction(handler) {
237
+ instructionHandlers.push(handler);
238
+ },
239
+ registerProcessorStatusSupplier(supplier) {
240
+ processorStatusSuppliers.push(supplier);
241
+ },
242
+ get connected() {
243
+ return isConnected;
244
+ },
245
+ async subscriptionsAcked() {
246
+ return isConnected && acked;
247
+ },
248
+ };
249
+ }
250
+ //# sourceMappingURL=platform-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-service.js","sourceRoot":"","sources":["../src/platform-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A shutdown latch that tracks in-flight operations and enables
3
+ * graceful shutdown by draining pending work.
4
+ *
5
+ * Usage:
6
+ * - `registerActivity()` before starting a dispatch — returns a handle
7
+ * - `handle.end()` when the dispatch completes
8
+ * - `initiateShutdown()` prevents new activities and returns a promise
9
+ * that resolves when all in-flight operations complete
10
+ *
11
+ * This is the TypeScript equivalent of AF5's ShutdownLatch pattern.
12
+ */
13
+ export interface ShutdownLatch {
14
+ /**
15
+ * Register an in-flight activity. Throws if shutdown is in progress.
16
+ * Call `end()` on the returned handle when the activity completes.
17
+ */
18
+ registerActivity(): ActivityHandle;
19
+ /**
20
+ * Begin graceful shutdown. Returns a promise that resolves when
21
+ * all in-flight activities have completed.
22
+ * New calls to `registerActivity()` will throw after this.
23
+ */
24
+ initiateShutdown(): Promise<void>;
25
+ /** Whether shutdown has been initiated. */
26
+ readonly shuttingDown: boolean;
27
+ /** Number of currently in-flight activities. */
28
+ readonly activeCount: number;
29
+ }
30
+ export interface ActivityHandle {
31
+ /** Mark this activity as complete. */
32
+ end(): void;
33
+ }
34
+ export declare class ShutdownInProgressError extends Error {
35
+ constructor(message?: string);
36
+ }
37
+ export declare function createShutdownLatch(): ShutdownLatch;
38
+ //# sourceMappingURL=shutdown-latch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-latch.d.ts","sourceRoot":"","sources":["../src/shutdown-latch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,IAAI,cAAc,CAAA;IAElC;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjC,2CAA2C;IAC3C,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAE9B,gDAAgD;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,GAAG,IAAI,IAAI,CAAA;CACZ;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,GAAE,MAA+B;CAIrD;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAmDnD"}
@@ -0,0 +1,51 @@
1
+ export class ShutdownInProgressError extends Error {
2
+ constructor(message = "Shutdown in progress") {
3
+ super(message);
4
+ this.name = "ShutdownInProgressError";
5
+ }
6
+ }
7
+ export function createShutdownLatch() {
8
+ let activeCount = 0;
9
+ let shuttingDown = false;
10
+ let drainResolve = null;
11
+ function checkDrained() {
12
+ if (shuttingDown && activeCount === 0 && drainResolve) {
13
+ drainResolve();
14
+ drainResolve = null;
15
+ }
16
+ }
17
+ return {
18
+ registerActivity() {
19
+ if (shuttingDown) {
20
+ throw new ShutdownInProgressError();
21
+ }
22
+ activeCount++;
23
+ let ended = false;
24
+ return {
25
+ end() {
26
+ if (ended)
27
+ return;
28
+ ended = true;
29
+ activeCount--;
30
+ checkDrained();
31
+ },
32
+ };
33
+ },
34
+ initiateShutdown() {
35
+ shuttingDown = true;
36
+ if (activeCount === 0) {
37
+ return Promise.resolve();
38
+ }
39
+ return new Promise((resolve) => {
40
+ drainResolve = resolve;
41
+ });
42
+ },
43
+ get shuttingDown() {
44
+ return shuttingDown;
45
+ },
46
+ get activeCount() {
47
+ return activeCount;
48
+ },
49
+ };
50
+ }
51
+ //# sourceMappingURL=shutdown-latch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-latch.js","sourceRoot":"","sources":["../src/shutdown-latch.ts"],"names":[],"mappings":"AAsCA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,UAAkB,sBAAsB;QAClD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;IACvC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,IAAI,YAAY,GAAwB,IAAI,CAAA;IAE5C,SAAS,YAAY;QACnB,IAAI,YAAY,IAAI,WAAW,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;YACtD,YAAY,EAAE,CAAA;YACd,YAAY,GAAG,IAAI,CAAA;QACrB,CAAC;IACH,CAAC;IAED,OAAO;QACL,gBAAgB;YACd,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,IAAI,uBAAuB,EAAE,CAAA;YACrC,CAAC;YAED,WAAW,EAAE,CAAA;YACb,IAAI,KAAK,GAAG,KAAK,CAAA;YAEjB,OAAO;gBACL,GAAG;oBACD,IAAI,KAAK;wBAAE,OAAM;oBACjB,KAAK,GAAG,IAAI,CAAA;oBACZ,WAAW,EAAE,CAAA;oBACb,YAAY,EAAE,CAAA;gBAChB,CAAC;aACF,CAAA;QACH,CAAC;QAED,gBAAgB;YACd,YAAY,GAAG,IAAI,CAAA;YAEnB,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;YAC1B,CAAC;YAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,YAAY,GAAG,OAAO,CAAA;YACxB,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,YAAY;YACd,OAAO,YAAY,CAAA;QACrB,CAAC;QAED,IAAI,WAAW;YACb,OAAO,WAAW,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@kronos-ts/axon-server",
3
+ "version": "0.1.0",
4
+ "description": "Axon Server extension for Kronos — event store and command bus over Axon Server.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "author": "Theo Emanuelsson",
8
+ "homepage": "https://github.com/KronosDB/kronos-ts/tree/main/packages/extensions/axon-server#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/KronosDB/kronos-ts.git",
12
+ "directory": "packages/extensions/axon-server"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/KronosDB/kronos-ts/issues"
16
+ },
17
+ "keywords": [
18
+ "kronos",
19
+ "event-sourcing",
20
+ "cqrs",
21
+ "dcb",
22
+ "typescript",
23
+ "axon-server"
24
+ ],
25
+ "sideEffects": false,
26
+ "main": "src/index.ts",
27
+ "types": "src/index.ts",
28
+ "files": [
29
+ "dist",
30
+ "src",
31
+ "!src/**/__tests__",
32
+ "!src/**/*.test.ts",
33
+ "!src/**/*.bench.ts"
34
+ ],
35
+ "scripts": {
36
+ "generate-proto": "grpc_tools_node_protoc --ts_proto_out=./src/generated --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false,esModuleInterop=true --proto_path=./proto ./proto/*.proto",
37
+ "build": "tsc -p tsconfig.json",
38
+ "clean": "rm -rf dist *.tsbuildinfo"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public",
42
+ "main": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "exports": {
45
+ ".": {
46
+ "types": "./dist/index.d.ts",
47
+ "default": "./dist/index.js"
48
+ }
49
+ }
50
+ },
51
+ "dependencies": {
52
+ "@kronos-ts/common": "workspace:*",
53
+ "@kronos-ts/app": "workspace:*",
54
+ "@kronos-ts/eventsourcing": "workspace:*",
55
+ "@kronos-ts/messaging": "workspace:*",
56
+ "@kronos-ts/modelling": "workspace:*",
57
+ "@bufbuild/protobuf": "^2.3",
58
+ "@grpc/grpc-js": "^1.12",
59
+ "nice-grpc": "^2.1",
60
+ "nice-grpc-common": "^2.0",
61
+ "zod": "^4.3.6"
62
+ },
63
+ "devDependencies": {
64
+ "grpc-tools": "^1.12",
65
+ "grpc_tools_node_protoc_ts": "^5.3",
66
+ "testcontainers": "^11.13.0",
67
+ "ts-proto": "^2.6"
68
+ }
69
+ }