@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.
- package/dist/axon-server-event-store.d.ts +16 -0
- package/dist/axon-server-event-store.d.ts.map +1 -0
- package/dist/axon-server-event-store.js +282 -0
- package/dist/axon-server-event-store.js.map +1 -0
- package/dist/axon-server-snapshot-store.d.ts +12 -0
- package/dist/axon-server-snapshot-store.d.ts.map +1 -0
- package/dist/axon-server-snapshot-store.js +88 -0
- package/dist/axon-server-snapshot-store.js.map +1 -0
- package/dist/axon-server.d.ts +115 -0
- package/dist/axon-server.d.ts.map +1 -0
- package/dist/axon-server.js +986 -0
- package/dist/axon-server.js.map +1 -0
- package/dist/connection-manager.d.ts +49 -0
- package/dist/connection-manager.d.ts.map +1 -0
- package/dist/connection-manager.js +37 -0
- package/dist/connection-manager.js.map +1 -0
- package/dist/connection.d.ts +129 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +130 -0
- package/dist/connection.js.map +1 -0
- package/dist/errors.d.ts +96 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +189 -0
- package/dist/errors.js.map +1 -0
- package/dist/event-processor-info.d.ts +35 -0
- package/dist/event-processor-info.d.ts.map +1 -0
- package/dist/event-processor-info.js +28 -0
- package/dist/event-processor-info.js.map +1 -0
- package/dist/flow-controlled-sender.d.ts +30 -0
- package/dist/flow-controlled-sender.d.ts.map +1 -0
- package/dist/flow-controlled-sender.js +60 -0
- package/dist/flow-controlled-sender.js.map +1 -0
- package/dist/generated/command.d.ts +158 -0
- package/dist/generated/command.d.ts.map +1 -0
- package/dist/generated/command.js +970 -0
- package/dist/generated/command.js.map +1 -0
- package/dist/generated/common.d.ts +130 -0
- package/dist/generated/common.d.ts.map +1 -0
- package/dist/generated/common.js +908 -0
- package/dist/generated/common.js.map +1 -0
- package/dist/generated/control.d.ts +293 -0
- package/dist/generated/control.d.ts.map +1 -0
- package/dist/generated/control.js +1938 -0
- package/dist/generated/control.js.map +1 -0
- package/dist/generated/dcb.d.ts +650 -0
- package/dist/generated/dcb.d.ts.map +1 -0
- package/dist/generated/dcb.js +2943 -0
- package/dist/generated/dcb.js.map +1 -0
- package/dist/generated/event.d.ts +667 -0
- package/dist/generated/event.d.ts.map +1 -0
- package/dist/generated/event.js +3185 -0
- package/dist/generated/event.js.map +1 -0
- package/dist/generated/google/protobuf/empty.d.ts +30 -0
- package/dist/generated/google/protobuf/empty.d.ts.map +1 -0
- package/dist/generated/google/protobuf/empty.js +46 -0
- package/dist/generated/google/protobuf/empty.js.map +1 -0
- package/dist/generated/query.d.ts +300 -0
- package/dist/generated/query.d.ts.map +1 -0
- package/dist/generated/query.js +2183 -0
- package/dist/generated/query.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/message-size.d.ts +38 -0
- package/dist/message-size.d.ts.map +1 -0
- package/dist/message-size.js +57 -0
- package/dist/message-size.js.map +1 -0
- package/dist/metadata-conversion.d.ts +11 -0
- package/dist/metadata-conversion.d.ts.map +1 -0
- package/dist/metadata-conversion.js +51 -0
- package/dist/metadata-conversion.js.map +1 -0
- package/dist/outbound-stream.d.ts +15 -0
- package/dist/outbound-stream.d.ts.map +1 -0
- package/dist/outbound-stream.js +39 -0
- package/dist/outbound-stream.js.map +1 -0
- package/dist/platform-service.d.ts +119 -0
- package/dist/platform-service.d.ts.map +1 -0
- package/dist/platform-service.js +250 -0
- package/dist/platform-service.js.map +1 -0
- package/dist/shutdown-latch.d.ts +38 -0
- package/dist/shutdown-latch.d.ts.map +1 -0
- package/dist/shutdown-latch.js +51 -0
- package/dist/shutdown-latch.js.map +1 -0
- package/package.json +69 -0
- package/src/axon-server-event-store.ts +358 -0
- package/src/axon-server-snapshot-store.ts +118 -0
- package/src/axon-server.ts +1202 -0
- package/src/connection-manager.ts +88 -0
- package/src/connection.ts +272 -0
- package/src/errors.ts +223 -0
- package/src/event-processor-info.ts +62 -0
- package/src/flow-controlled-sender.ts +91 -0
- package/src/generated/command.ts +1231 -0
- package/src/generated/common.ts +1097 -0
- package/src/generated/control.ts +2419 -0
- package/src/generated/dcb.ts +3826 -0
- package/src/generated/event.ts +4076 -0
- package/src/generated/google/protobuf/empty.ts +84 -0
- package/src/generated/query.ts +2723 -0
- package/src/index.ts +75 -0
- package/src/message-size.ts +75 -0
- package/src/metadata-conversion.ts +46 -0
- package/src/outbound-stream.ts +52 -0
- package/src/platform-service.ts +361 -0
- 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
|
+
}
|