@almadar/server 1.4.4 → 2.0.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/LICENSE +21 -72
- package/README.md +25 -0
- package/dist/index.js +435 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -12
- package/dist/deepagent/memory.d.ts +0 -20
- package/dist/deepagent/session.d.ts +0 -20
- package/dist/deepagent/skill-agent.d.ts +0 -24
- package/dist/index-B64ll_cY.d.ts +0 -149
- package/dist/index-D8fohXsO.d.ts +0 -178
- package/dist/index.d.ts +0 -41
- package/dist/lib/index.d.ts +0 -4
- package/dist/middleware/index.d.ts +0 -71
- package/dist/middleware/multi-user.d.ts +0 -37
- package/dist/routes/observability.d.ts +0 -12
- package/dist/services/index.d.ts +0 -2
- package/dist/stores/index.d.ts +0 -167
- package/dist/utils/index.d.ts +0 -78
- package/dist/websocket/state-sync.d.ts +0 -39
package/LICENSE
CHANGED
|
@@ -1,72 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
23
|
-
available distribution of a specific version of the Licensed Work under this
|
|
24
|
-
License, whichever comes first, the Licensor hereby grants you rights under
|
|
25
|
-
the terms of the Change License, and the rights granted in the paragraph
|
|
26
|
-
above terminate.
|
|
27
|
-
|
|
28
|
-
If your use of the Licensed Work does not comply with the requirements
|
|
29
|
-
currently in effect as described in this License, you must purchase a
|
|
30
|
-
commercial license from the Licensor, its affiliated entities, or authorized
|
|
31
|
-
resellers, or you must refrain from using the Licensed Work.
|
|
32
|
-
|
|
33
|
-
All copies of the original and modified Licensed Work, and derivative works
|
|
34
|
-
of the Licensed Work, are subject to this License. This License applies
|
|
35
|
-
separately for each version of the Licensed Work and the Change Date may vary
|
|
36
|
-
for each version of the Licensed Work released by Licensor.
|
|
37
|
-
|
|
38
|
-
You must conspicuously display this License on each original or modified copy
|
|
39
|
-
of the Licensed Work. If you receive the Licensed Work in original or
|
|
40
|
-
modified form from a third party, the terms and conditions set forth in this
|
|
41
|
-
License apply to your use of that work.
|
|
42
|
-
|
|
43
|
-
Any use of the Licensed Work in violation of this License will automatically
|
|
44
|
-
terminate your rights under this License for the current and all other
|
|
45
|
-
versions of the Licensed Work.
|
|
46
|
-
|
|
47
|
-
This License does not grant you any right in any trademark or logo of
|
|
48
|
-
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
49
|
-
Licensor as expressly required by this License).
|
|
50
|
-
|
|
51
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
52
|
-
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
53
|
-
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
54
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
55
|
-
TITLE.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
60
|
-
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
61
|
-
|
|
62
|
-
ADDITIONAL TERMS:
|
|
63
|
-
|
|
64
|
-
Documentation (builder/packages/website/docs/) is licensed under CC BY 4.0.
|
|
65
|
-
|
|
66
|
-
TRADEMARKS:
|
|
67
|
-
|
|
68
|
-
"Orbital", "KFlow", "Almadar", and the Almadar logo are trademarks of
|
|
69
|
-
Almadar FZE. You may not use these trademarks without prior written
|
|
70
|
-
permission from Almadar FZE.
|
|
71
|
-
|
|
72
|
-
For licensing inquiries: licensing@almadar.io
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Almadar Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @almadar/server
|
|
2
|
+
|
|
3
|
+
> Shared server infrastructure for Almadar applications
|
|
4
|
+
|
|
5
|
+
Part of the [Almadar](https://github.com/almadar-io/almadar) platform.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @almadar/server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { /* ... */ } from '@almadar/server';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API
|
|
20
|
+
|
|
21
|
+
<!-- Document public exports here -->
|
|
22
|
+
|
|
23
|
+
## License
|
|
24
|
+
|
|
25
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -176,6 +176,272 @@ function emitEntityEvent(entityType, action, payload) {
|
|
|
176
176
|
const eventType = `${entityType.toUpperCase()}_${action}`;
|
|
177
177
|
serverEventBus.emit(eventType, payload, { orbital: entityType });
|
|
178
178
|
}
|
|
179
|
+
|
|
180
|
+
// src/lib/eventBusTransport.ts
|
|
181
|
+
var InMemoryTransport = class {
|
|
182
|
+
async publish() {
|
|
183
|
+
}
|
|
184
|
+
async subscribe() {
|
|
185
|
+
}
|
|
186
|
+
async close() {
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
var RedisTransport = class {
|
|
190
|
+
channel;
|
|
191
|
+
publishFn;
|
|
192
|
+
subscribeFn;
|
|
193
|
+
closeFn;
|
|
194
|
+
constructor(options) {
|
|
195
|
+
this.channel = options.channel ?? "almadar:events";
|
|
196
|
+
this.publishFn = options.publishFn;
|
|
197
|
+
this.subscribeFn = options.subscribeFn;
|
|
198
|
+
this.closeFn = options.closeFn;
|
|
199
|
+
}
|
|
200
|
+
async publish(message) {
|
|
201
|
+
const serialized = JSON.stringify(message);
|
|
202
|
+
await this.publishFn(this.channel, serialized);
|
|
203
|
+
}
|
|
204
|
+
async subscribe(receiver) {
|
|
205
|
+
await this.subscribeFn(this.channel, (raw) => {
|
|
206
|
+
try {
|
|
207
|
+
const message = JSON.parse(raw);
|
|
208
|
+
receiver(message);
|
|
209
|
+
} catch {
|
|
210
|
+
console.error("[RedisTransport] Failed to parse message:", raw);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
async close() {
|
|
215
|
+
if (this.closeFn) {
|
|
216
|
+
await this.closeFn();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var instanceCounter = 0;
|
|
221
|
+
var DistributedEventBus = class {
|
|
222
|
+
localBus;
|
|
223
|
+
transport;
|
|
224
|
+
instanceId;
|
|
225
|
+
isRelaying = false;
|
|
226
|
+
constructor(options) {
|
|
227
|
+
this.localBus = new EventBus({ debug: options?.debug });
|
|
228
|
+
this.transport = options?.transport ?? new InMemoryTransport();
|
|
229
|
+
this.instanceId = `instance_${++instanceCounter}_${Date.now()}`;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Initialize the transport subscription. Call once at startup.
|
|
233
|
+
*/
|
|
234
|
+
async connect() {
|
|
235
|
+
await this.transport.subscribe((message) => {
|
|
236
|
+
if (message.sourceId === this.instanceId) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
this.isRelaying = true;
|
|
240
|
+
try {
|
|
241
|
+
this.localBus.emit(message.event, message.payload, message.meta);
|
|
242
|
+
} finally {
|
|
243
|
+
this.isRelaying = false;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Emit an event locally and publish to transport for other processes.
|
|
249
|
+
*/
|
|
250
|
+
emit(event, payload, meta) {
|
|
251
|
+
this.localBus.emit(event, payload, meta);
|
|
252
|
+
if (!this.isRelaying) {
|
|
253
|
+
const message = {
|
|
254
|
+
event,
|
|
255
|
+
payload,
|
|
256
|
+
meta,
|
|
257
|
+
sourceId: this.instanceId,
|
|
258
|
+
timestamp: Date.now()
|
|
259
|
+
};
|
|
260
|
+
this.transport.publish(message).catch((err) => {
|
|
261
|
+
console.error("[DistributedEventBus] Transport publish error:", err);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/** Subscribe to an event */
|
|
266
|
+
on(event, handler) {
|
|
267
|
+
return this.localBus.on(event, handler);
|
|
268
|
+
}
|
|
269
|
+
/** Unsubscribe from an event */
|
|
270
|
+
off(event, handler) {
|
|
271
|
+
this.localBus.off(event, handler);
|
|
272
|
+
}
|
|
273
|
+
/** Get recent events (dev diagnostics) */
|
|
274
|
+
getRecentEvents(limit) {
|
|
275
|
+
return this.localBus.getRecentEvents(limit);
|
|
276
|
+
}
|
|
277
|
+
/** Clear event log */
|
|
278
|
+
clearEventLog() {
|
|
279
|
+
this.localBus.clearEventLog();
|
|
280
|
+
}
|
|
281
|
+
/** Get listener counts */
|
|
282
|
+
getListenerCounts() {
|
|
283
|
+
return this.localBus.getListenerCounts();
|
|
284
|
+
}
|
|
285
|
+
/** Clear all listeners and log */
|
|
286
|
+
clear() {
|
|
287
|
+
this.localBus.clear();
|
|
288
|
+
}
|
|
289
|
+
/** Disconnect transport */
|
|
290
|
+
async disconnect() {
|
|
291
|
+
await this.transport.close();
|
|
292
|
+
}
|
|
293
|
+
/** Get the instance ID (for debugging) */
|
|
294
|
+
getInstanceId() {
|
|
295
|
+
return this.instanceId;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// src/lib/eventPersistence.ts
|
|
300
|
+
var InMemoryEventStore = class {
|
|
301
|
+
events = [];
|
|
302
|
+
index = /* @__PURE__ */ new Map();
|
|
303
|
+
async store(event) {
|
|
304
|
+
this.events.push(event);
|
|
305
|
+
this.index.set(event.id, event);
|
|
306
|
+
}
|
|
307
|
+
async query(filters) {
|
|
308
|
+
let results = this.events;
|
|
309
|
+
if (filters.eventName) {
|
|
310
|
+
results = results.filter((e) => e.eventName === filters.eventName);
|
|
311
|
+
}
|
|
312
|
+
if (filters.source) {
|
|
313
|
+
results = results.filter((e) => e.source === filters.source);
|
|
314
|
+
}
|
|
315
|
+
if (filters.traceId) {
|
|
316
|
+
results = results.filter((e) => e.traceId === filters.traceId);
|
|
317
|
+
}
|
|
318
|
+
if (filters.after !== void 0) {
|
|
319
|
+
results = results.filter((e) => e.timestamp > filters.after);
|
|
320
|
+
}
|
|
321
|
+
if (filters.before !== void 0) {
|
|
322
|
+
results = results.filter((e) => e.timestamp < filters.before);
|
|
323
|
+
}
|
|
324
|
+
if (filters.order === "desc") {
|
|
325
|
+
results = [...results].reverse();
|
|
326
|
+
}
|
|
327
|
+
if (filters.limit !== void 0 && filters.limit > 0) {
|
|
328
|
+
results = results.slice(0, filters.limit);
|
|
329
|
+
}
|
|
330
|
+
return results;
|
|
331
|
+
}
|
|
332
|
+
async get(id) {
|
|
333
|
+
return this.index.get(id) ?? null;
|
|
334
|
+
}
|
|
335
|
+
async deleteOlderThan(timestamp) {
|
|
336
|
+
const before = this.events.length;
|
|
337
|
+
this.events = this.events.filter((e) => e.timestamp >= timestamp);
|
|
338
|
+
this.index.clear();
|
|
339
|
+
for (const event of this.events) {
|
|
340
|
+
this.index.set(event.id, event);
|
|
341
|
+
}
|
|
342
|
+
return before - this.events.length;
|
|
343
|
+
}
|
|
344
|
+
async count() {
|
|
345
|
+
return this.events.length;
|
|
346
|
+
}
|
|
347
|
+
async clear() {
|
|
348
|
+
this.events = [];
|
|
349
|
+
this.index.clear();
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
var idCounter = 0;
|
|
353
|
+
var EventPersistence = class {
|
|
354
|
+
store;
|
|
355
|
+
options;
|
|
356
|
+
cleanupTimer = null;
|
|
357
|
+
constructor(options, store) {
|
|
358
|
+
this.options = {
|
|
359
|
+
enabled: options?.enabled ?? true,
|
|
360
|
+
retentionMs: options?.retentionMs ?? 24 * 60 * 60 * 1e3,
|
|
361
|
+
// 24 hours
|
|
362
|
+
maxEvents: options?.maxEvents ?? 1e4,
|
|
363
|
+
cleanupIntervalMs: options?.cleanupIntervalMs ?? 5 * 60 * 1e3,
|
|
364
|
+
// 5 minutes
|
|
365
|
+
defaultSource: options?.defaultSource ?? "unknown"
|
|
366
|
+
};
|
|
367
|
+
this.store = store ?? new InMemoryEventStore();
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Persist an event.
|
|
371
|
+
*/
|
|
372
|
+
async persist(eventName, payload, meta) {
|
|
373
|
+
const event = {
|
|
374
|
+
id: `evt_${++idCounter}_${Date.now()}`,
|
|
375
|
+
eventName,
|
|
376
|
+
payload,
|
|
377
|
+
source: meta?.source ?? this.options.defaultSource,
|
|
378
|
+
timestamp: Date.now(),
|
|
379
|
+
traceId: meta?.traceId ?? `trace_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
380
|
+
meta: meta ? { ...meta } : void 0
|
|
381
|
+
};
|
|
382
|
+
if (this.options.enabled) {
|
|
383
|
+
await this.store.store(event);
|
|
384
|
+
}
|
|
385
|
+
return event;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Replay events matching the query filters.
|
|
389
|
+
*/
|
|
390
|
+
async replay(query) {
|
|
391
|
+
return this.store.query(query);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Get a single event by ID.
|
|
395
|
+
*/
|
|
396
|
+
async getEvent(id) {
|
|
397
|
+
return this.store.get(id);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get event count.
|
|
401
|
+
*/
|
|
402
|
+
async getEventCount() {
|
|
403
|
+
return this.store.count();
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Run cleanup — delete events older than retention period.
|
|
407
|
+
*/
|
|
408
|
+
async cleanup() {
|
|
409
|
+
const cutoff = Date.now() - this.options.retentionMs;
|
|
410
|
+
return this.store.deleteOlderThan(cutoff);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Start periodic cleanup timer.
|
|
414
|
+
*/
|
|
415
|
+
startCleanup() {
|
|
416
|
+
if (this.cleanupTimer) return;
|
|
417
|
+
this.cleanupTimer = setInterval(() => {
|
|
418
|
+
this.cleanup().catch((err) => {
|
|
419
|
+
console.error("[EventPersistence] Cleanup error:", err);
|
|
420
|
+
});
|
|
421
|
+
}, this.options.cleanupIntervalMs);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Stop periodic cleanup timer.
|
|
425
|
+
*/
|
|
426
|
+
stopCleanup() {
|
|
427
|
+
if (this.cleanupTimer) {
|
|
428
|
+
clearInterval(this.cleanupTimer);
|
|
429
|
+
this.cleanupTimer = null;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Clear all persisted events.
|
|
434
|
+
*/
|
|
435
|
+
async clear() {
|
|
436
|
+
await this.store.clear();
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get the underlying store (for testing or custom queries).
|
|
440
|
+
*/
|
|
441
|
+
getStore() {
|
|
442
|
+
return this.store;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
179
445
|
function debugEventsRouter() {
|
|
180
446
|
const router2 = Router();
|
|
181
447
|
if (process.env.NODE_ENV !== "development") {
|
|
@@ -1776,6 +2042,174 @@ function setupStateSyncWebSocket(io) {
|
|
|
1776
2042
|
});
|
|
1777
2043
|
});
|
|
1778
2044
|
}
|
|
2045
|
+
|
|
2046
|
+
// src/lib/serviceDiscovery.ts
|
|
2047
|
+
var InMemoryServiceRegistry = class {
|
|
2048
|
+
services = /* @__PURE__ */ new Map();
|
|
2049
|
+
async register(service) {
|
|
2050
|
+
this.services.set(service.instanceId, {
|
|
2051
|
+
...service,
|
|
2052
|
+
registeredAt: Date.now(),
|
|
2053
|
+
lastHeartbeat: Date.now()
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
async deregister(instanceId) {
|
|
2057
|
+
this.services.delete(instanceId);
|
|
2058
|
+
}
|
|
2059
|
+
async heartbeat(instanceId) {
|
|
2060
|
+
const service = this.services.get(instanceId);
|
|
2061
|
+
if (service) {
|
|
2062
|
+
service.lastHeartbeat = Date.now();
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
async updateStatus(instanceId, status) {
|
|
2066
|
+
const service = this.services.get(instanceId);
|
|
2067
|
+
if (service) {
|
|
2068
|
+
service.status = status;
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
async getAll() {
|
|
2072
|
+
return Array.from(this.services.values());
|
|
2073
|
+
}
|
|
2074
|
+
async getByName(name) {
|
|
2075
|
+
return Array.from(this.services.values()).filter((s) => s.name === name);
|
|
2076
|
+
}
|
|
2077
|
+
async findListeners(event) {
|
|
2078
|
+
return Array.from(this.services.values()).filter(
|
|
2079
|
+
(s) => s.listens.includes(event) && s.status !== "stopping"
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
async findEmitters(event) {
|
|
2083
|
+
return Array.from(this.services.values()).filter(
|
|
2084
|
+
(s) => s.emits.includes(event) && s.status !== "stopping"
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2087
|
+
async cleanup(ttlMs) {
|
|
2088
|
+
const cutoff = Date.now() - ttlMs;
|
|
2089
|
+
let removed = 0;
|
|
2090
|
+
for (const [id, service] of this.services) {
|
|
2091
|
+
if (service.lastHeartbeat < cutoff) {
|
|
2092
|
+
this.services.delete(id);
|
|
2093
|
+
removed++;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
return removed;
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
var ServiceDiscovery = class {
|
|
2100
|
+
registry;
|
|
2101
|
+
options;
|
|
2102
|
+
cleanupTimer = null;
|
|
2103
|
+
constructor(options, registry) {
|
|
2104
|
+
this.options = {
|
|
2105
|
+
heartbeatTtlMs: options?.heartbeatTtlMs ?? 6e4,
|
|
2106
|
+
cleanupIntervalMs: options?.cleanupIntervalMs ?? 3e4
|
|
2107
|
+
};
|
|
2108
|
+
this.registry = registry ?? new InMemoryServiceRegistry();
|
|
2109
|
+
}
|
|
2110
|
+
/**
|
|
2111
|
+
* Register a service with the registry.
|
|
2112
|
+
*/
|
|
2113
|
+
async register(service) {
|
|
2114
|
+
await this.registry.register({
|
|
2115
|
+
...service,
|
|
2116
|
+
status: service.status ?? "starting",
|
|
2117
|
+
registeredAt: Date.now(),
|
|
2118
|
+
lastHeartbeat: Date.now()
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Deregister a service.
|
|
2123
|
+
*/
|
|
2124
|
+
async deregister(instanceId) {
|
|
2125
|
+
await this.registry.deregister(instanceId);
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Send heartbeat for a service.
|
|
2129
|
+
*/
|
|
2130
|
+
async heartbeat(instanceId) {
|
|
2131
|
+
await this.registry.heartbeat(instanceId);
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Mark a service as ready.
|
|
2135
|
+
*/
|
|
2136
|
+
async markReady(instanceId) {
|
|
2137
|
+
await this.registry.updateStatus(instanceId, "ready");
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Mark a service as degraded.
|
|
2141
|
+
*/
|
|
2142
|
+
async markDegraded(instanceId) {
|
|
2143
|
+
await this.registry.updateStatus(instanceId, "degraded");
|
|
2144
|
+
}
|
|
2145
|
+
/**
|
|
2146
|
+
* Find all services that listen for a given event.
|
|
2147
|
+
*/
|
|
2148
|
+
async findListeners(event) {
|
|
2149
|
+
return this.registry.findListeners(event);
|
|
2150
|
+
}
|
|
2151
|
+
/**
|
|
2152
|
+
* Find all services that emit a given event.
|
|
2153
|
+
*/
|
|
2154
|
+
async findEmitters(event) {
|
|
2155
|
+
return this.registry.findEmitters(event);
|
|
2156
|
+
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Get all registered services.
|
|
2159
|
+
*/
|
|
2160
|
+
async getAll() {
|
|
2161
|
+
return this.registry.getAll();
|
|
2162
|
+
}
|
|
2163
|
+
/**
|
|
2164
|
+
* Get the full event topology (who emits what, who listens for what).
|
|
2165
|
+
*/
|
|
2166
|
+
async getEventTopology() {
|
|
2167
|
+
const services = await this.registry.getAll();
|
|
2168
|
+
const eventMap = /* @__PURE__ */ new Map();
|
|
2169
|
+
for (const service of services) {
|
|
2170
|
+
for (const event of service.emits) {
|
|
2171
|
+
if (!eventMap.has(event)) eventMap.set(event, { emitters: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set() });
|
|
2172
|
+
eventMap.get(event).emitters.add(service.name);
|
|
2173
|
+
}
|
|
2174
|
+
for (const event of service.listens) {
|
|
2175
|
+
if (!eventMap.has(event)) eventMap.set(event, { emitters: /* @__PURE__ */ new Set(), listeners: /* @__PURE__ */ new Set() });
|
|
2176
|
+
eventMap.get(event).listeners.add(service.name);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
const events = Array.from(eventMap.entries()).map(([event, { emitters, listeners }]) => ({
|
|
2180
|
+
event,
|
|
2181
|
+
emitters: Array.from(emitters),
|
|
2182
|
+
listeners: Array.from(listeners)
|
|
2183
|
+
}));
|
|
2184
|
+
return { events };
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Start periodic cleanup of expired services.
|
|
2188
|
+
*/
|
|
2189
|
+
startCleanup() {
|
|
2190
|
+
if (this.cleanupTimer) return;
|
|
2191
|
+
this.cleanupTimer = setInterval(() => {
|
|
2192
|
+
this.registry.cleanup(this.options.heartbeatTtlMs).catch((err) => {
|
|
2193
|
+
console.error("[ServiceDiscovery] Cleanup error:", err);
|
|
2194
|
+
});
|
|
2195
|
+
}, this.options.cleanupIntervalMs);
|
|
2196
|
+
}
|
|
2197
|
+
/**
|
|
2198
|
+
* Stop periodic cleanup.
|
|
2199
|
+
*/
|
|
2200
|
+
stopCleanup() {
|
|
2201
|
+
if (this.cleanupTimer) {
|
|
2202
|
+
clearInterval(this.cleanupTimer);
|
|
2203
|
+
this.cleanupTimer = null;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Get the underlying registry (for testing).
|
|
2208
|
+
*/
|
|
2209
|
+
getRegistry() {
|
|
2210
|
+
return this.registry;
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
1779
2213
|
var router = Router();
|
|
1780
2214
|
router.get("/metrics", async (req, res) => {
|
|
1781
2215
|
try {
|
|
@@ -1831,6 +2265,6 @@ router.get("/active-sessions", async (req, res) => {
|
|
|
1831
2265
|
});
|
|
1832
2266
|
var observability_default = router;
|
|
1833
2267
|
|
|
1834
|
-
export { AppError, ChangeSetStore, ConflictError, EventBus, ForbiddenError, MockDataService, NotFoundError, SchemaProtectionService, SchemaStore, SnapshotStore, UnauthorizedError, ValidationError, ValidationStore, applyFiltersToQuery, asyncHandler, authenticateFirebase, closeWebSocketServer, createServerSkillAgent, dataService, db, debugEventsRouter, emitEntityEvent, env, errorHandler, extractPaginationParams, fromFirestoreFormat, getMemoryManager as getAgentMemoryManager, getSessionManager as getAgentSessionManager, getAuth, getConnectedClientCount, getFirestore, getMemoryManager, getSessionManager, getWebSocketServer, initializeFirebase, logger, mockDataService, multiUserMiddleware, notFoundHandler, observability_default as observabilityRouter, parseQueryFilters, resetMemoryManager, resetSessionManager, seedMockData, serverEventBus, setupEventBroadcast, setupStateSyncWebSocket, toFirestoreFormat, validateBody, validateParams, validateQuery, verifyFirebaseAuth };
|
|
2268
|
+
export { AppError, ChangeSetStore, ConflictError, DistributedEventBus, EventBus, EventPersistence, ForbiddenError, InMemoryEventStore, InMemoryServiceRegistry, InMemoryTransport, MockDataService, NotFoundError, RedisTransport, SchemaProtectionService, SchemaStore, ServiceDiscovery, SnapshotStore, UnauthorizedError, ValidationError, ValidationStore, applyFiltersToQuery, asyncHandler, authenticateFirebase, closeWebSocketServer, createServerSkillAgent, dataService, db, debugEventsRouter, emitEntityEvent, env, errorHandler, extractPaginationParams, fromFirestoreFormat, getMemoryManager as getAgentMemoryManager, getSessionManager as getAgentSessionManager, getAuth, getConnectedClientCount, getFirestore, getMemoryManager, getSessionManager, getWebSocketServer, initializeFirebase, logger, mockDataService, multiUserMiddleware, notFoundHandler, observability_default as observabilityRouter, parseQueryFilters, resetMemoryManager, resetSessionManager, seedMockData, serverEventBus, setupEventBroadcast, setupStateSyncWebSocket, toFirestoreFormat, validateBody, validateParams, validateQuery, verifyFirebaseAuth };
|
|
1835
2269
|
//# sourceMappingURL=index.js.map
|
|
1836
2270
|
//# sourceMappingURL=index.js.map
|