@almadar/server 2.0.9 → 2.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/index.js CHANGED
@@ -1,19 +1,407 @@
1
- import { z, ZodError } from 'zod';
2
- import dotenv from 'dotenv';
3
- import { Router } from 'express';
4
1
  import admin from 'firebase-admin';
5
2
  export { default as admin } from 'firebase-admin';
3
+ import { MemoryManager, SessionManager, getObservabilityCollector, getMultiUserManager, createWorkflowToolWrapper, createSkillAgent, createUserContext, getStateSyncManager } from '@almadar-io/agent';
4
+ import { Router } from 'express';
5
+ import { z, ZodError } from 'zod';
6
+ import dotenv from 'dotenv';
6
7
  import { faker } from '@faker-js/faker';
7
8
  import { WebSocketServer, WebSocket } from 'ws';
8
9
  import { diffSchemas, categorizeRemovals, detectPageContentReduction, isDestructiveChange, hasSignificantPageReduction, requiresConfirmation } from '@almadar/core';
9
- import { getObservabilityCollector, MemoryManager, SessionManager, getMultiUserManager, createWorkflowToolWrapper, createSkillAgent, createUserContext, getStateSyncManager } from '@almadar/agent';
10
10
 
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
13
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
12
14
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
13
15
  }) : x)(function(x) {
14
16
  if (typeof require !== "undefined") return require.apply(this, arguments);
15
17
  throw Error('Dynamic require of "' + x + '" is not supported');
16
18
  });
19
+ var __esm = (fn, res) => function __init() {
20
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
26
+ function initializeFirebase() {
27
+ if (admin.apps.length > 0) {
28
+ return admin.app();
29
+ }
30
+ const projectId = process.env.FIREBASE_PROJECT_ID;
31
+ const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;
32
+ if (emulatorHost) {
33
+ const app = admin.initializeApp({
34
+ projectId: projectId || "demo-project"
35
+ });
36
+ console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);
37
+ return app;
38
+ }
39
+ const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;
40
+ if (serviceAccountPath) {
41
+ const serviceAccount = __require(serviceAccountPath);
42
+ return admin.initializeApp({
43
+ credential: admin.credential.cert(serviceAccount),
44
+ projectId
45
+ });
46
+ }
47
+ const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;
48
+ const privateKey = process.env.FIREBASE_PRIVATE_KEY;
49
+ if (projectId && clientEmail && privateKey) {
50
+ return admin.initializeApp({
51
+ credential: admin.credential.cert({
52
+ projectId,
53
+ clientEmail,
54
+ privateKey: privateKey.replace(/\\n/g, "\n")
55
+ }),
56
+ projectId
57
+ });
58
+ }
59
+ if (projectId) {
60
+ return admin.initializeApp({
61
+ credential: admin.credential.applicationDefault(),
62
+ projectId
63
+ });
64
+ }
65
+ throw new Error(
66
+ "@almadar/server: Cannot initialize Firebase \u2014 no credentials found. Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST."
67
+ );
68
+ }
69
+ function getApp() {
70
+ if (admin.apps.length === 0) {
71
+ throw new Error(
72
+ "@almadar/server: Firebase Admin SDK is not initialized. Call initializeFirebase() or admin.initializeApp() before using @almadar/server."
73
+ );
74
+ }
75
+ return admin.app();
76
+ }
77
+ function getFirestore() {
78
+ return getApp().firestore();
79
+ }
80
+ function getAuth() {
81
+ return getApp().auth();
82
+ }
83
+ var db;
84
+ var init_db = __esm({
85
+ "src/lib/db.ts"() {
86
+ db = new Proxy({}, {
87
+ get(_target, prop, receiver) {
88
+ const firestore = getFirestore();
89
+ const value = Reflect.get(firestore, prop, receiver);
90
+ return typeof value === "function" ? value.bind(firestore) : value;
91
+ }
92
+ });
93
+ }
94
+ });
95
+
96
+ // src/deepagent/memory.ts
97
+ var memory_exports = {};
98
+ __export(memory_exports, {
99
+ getMemoryManager: () => getMemoryManager,
100
+ resetMemoryManager: () => resetMemoryManager
101
+ });
102
+ function getMemoryManager() {
103
+ if (!memoryManager) {
104
+ memoryManager = new MemoryManager({
105
+ db,
106
+ usersCollection: "agent_memory_users",
107
+ projectsCollection: "agent_memory_projects",
108
+ generationsCollection: "agent_memory_generations",
109
+ patternsCollection: "agent_memory_patterns",
110
+ interruptsCollection: "agent_memory_interrupts",
111
+ feedbackCollection: "agent_memory_feedback",
112
+ checkpointsCollection: "agent_memory_checkpoints",
113
+ toolPreferencesCollection: "agent_memory_tool_preferences"
114
+ });
115
+ }
116
+ return memoryManager;
117
+ }
118
+ function resetMemoryManager() {
119
+ memoryManager = null;
120
+ }
121
+ var memoryManager;
122
+ var init_memory = __esm({
123
+ "src/deepagent/memory.ts"() {
124
+ init_db();
125
+ memoryManager = null;
126
+ }
127
+ });
128
+
129
+ // src/deepagent/session.ts
130
+ var session_exports = {};
131
+ __export(session_exports, {
132
+ getSessionManager: () => getSessionManager,
133
+ resetSessionManager: () => resetSessionManager
134
+ });
135
+ function createFirestoreAdapter(firestore) {
136
+ return firestore;
137
+ }
138
+ function getSessionManager() {
139
+ if (!sessionManager) {
140
+ sessionManager = new SessionManager({
141
+ mode: "firestore",
142
+ firestoreDb: createFirestoreAdapter(db),
143
+ memoryManager: getMemoryManager(),
144
+ // Enable GAP-002D
145
+ compactionConfig: {
146
+ maxTokens: 15e4,
147
+ keepRecentMessages: 10,
148
+ strategy: "last"
149
+ }
150
+ });
151
+ }
152
+ return sessionManager;
153
+ }
154
+ function resetSessionManager() {
155
+ sessionManager = null;
156
+ }
157
+ var sessionManager;
158
+ var init_session = __esm({
159
+ "src/deepagent/session.ts"() {
160
+ init_db();
161
+ init_memory();
162
+ sessionManager = null;
163
+ }
164
+ });
165
+
166
+ // src/deepagent/skill-agent.ts
167
+ var skill_agent_exports = {};
168
+ __export(skill_agent_exports, {
169
+ createServerSkillAgent: () => createServerSkillAgent,
170
+ getMemoryManager: () => getMemoryManager,
171
+ getSessionManager: () => getSessionManager
172
+ });
173
+ async function createServerSkillAgent(options) {
174
+ const memoryManager2 = getMemoryManager();
175
+ getSessionManager();
176
+ const observability = getObservabilityCollector();
177
+ const multiUser = getMultiUserManager();
178
+ if (options.threadId) {
179
+ const access = multiUser.canAccessSession(options.threadId, {
180
+ userId: options.userId,
181
+ roles: ["user"]
182
+ });
183
+ if (!access.allowed) {
184
+ throw new Error(`Access denied: ${access.reason}`);
185
+ }
186
+ }
187
+ observability.startSession(options.threadId ?? "new", options.userId);
188
+ const workflowToolWrapper = createWorkflowToolWrapper({
189
+ maxRetries: 2,
190
+ enableTelemetry: true,
191
+ timeoutMs: 3e5
192
+ // 5 minutes
193
+ });
194
+ try {
195
+ const result = await createSkillAgent({
196
+ ...options,
197
+ memoryManager: memoryManager2,
198
+ // GAP-001: Enable memory
199
+ userId: options.userId,
200
+ // GAP-002D: Session → Memory sync
201
+ appId: options.appId,
202
+ toolWrapper: workflowToolWrapper.wrap
203
+ // Always use workflow wrapper for reliability
204
+ });
205
+ if (result.threadId) {
206
+ multiUser.assignSessionOwnership(result.threadId, options.userId);
207
+ }
208
+ observability.recordEvent({
209
+ type: "session_start",
210
+ sessionId: result.threadId,
211
+ userId: options.userId,
212
+ payload: { skill: options.skill }
213
+ });
214
+ return result;
215
+ } catch (error) {
216
+ observability.recordError(options.threadId ?? "new", error);
217
+ throw error;
218
+ }
219
+ }
220
+ var init_skill_agent = __esm({
221
+ "src/deepagent/skill-agent.ts"() {
222
+ init_memory();
223
+ init_session();
224
+ }
225
+ });
226
+
227
+ // src/middleware/multi-user.ts
228
+ var multi_user_exports = {};
229
+ __export(multi_user_exports, {
230
+ multiUserMiddleware: () => multiUserMiddleware,
231
+ verifyFirebaseAuth: () => verifyFirebaseAuth
232
+ });
233
+ async function multiUserMiddleware(req, res, next) {
234
+ const userId = req.user?.uid;
235
+ if (!userId) {
236
+ res.status(401).json({ error: "Authentication required" });
237
+ return;
238
+ }
239
+ req.userContext = createUserContext(userId, {
240
+ orgId: req.user?.orgId,
241
+ roles: req.user?.roles ?? ["user"]
242
+ });
243
+ const originalJson = res.json.bind(res);
244
+ res.json = (body) => {
245
+ if (body && typeof body === "object" && "threadId" in body) {
246
+ const multiUser = getMultiUserManager();
247
+ multiUser.assignSessionOwnership(
248
+ body.threadId,
249
+ userId
250
+ );
251
+ }
252
+ return originalJson(body);
253
+ };
254
+ next();
255
+ }
256
+ async function verifyFirebaseAuth(req, res, next) {
257
+ const authHeader = req.headers.authorization;
258
+ if (!authHeader?.startsWith("Bearer ")) {
259
+ res.status(401).json({ error: "No token provided" });
260
+ return;
261
+ }
262
+ const token = authHeader.split("Bearer ")[1];
263
+ try {
264
+ const decodedToken = await getAuth().verifyIdToken(token);
265
+ const user = await getAuth().getUser(decodedToken.uid);
266
+ req.user = {
267
+ uid: decodedToken.uid,
268
+ email: decodedToken.email,
269
+ roles: user.customClaims?.roles ?? ["user"],
270
+ orgId: user.customClaims?.orgId
271
+ };
272
+ next();
273
+ } catch (error) {
274
+ console.error("Token verification failed:", error);
275
+ res.status(401).json({ error: "Invalid token" });
276
+ }
277
+ }
278
+ var init_multi_user = __esm({
279
+ "src/middleware/multi-user.ts"() {
280
+ init_db();
281
+ }
282
+ });
283
+
284
+ // src/websocket/state-sync.ts
285
+ var state_sync_exports = {};
286
+ __export(state_sync_exports, {
287
+ setupStateSyncWebSocket: () => setupStateSyncWebSocket
288
+ });
289
+ function setupStateSyncWebSocket(io) {
290
+ const stateSync = getStateSyncManager();
291
+ io.use(async (socket, next) => {
292
+ try {
293
+ const token = socket.handshake.auth.token;
294
+ if (!token) {
295
+ return next(new Error("Authentication required"));
296
+ }
297
+ const decodedToken = await getAuth().verifyIdToken(token);
298
+ const user = await getAuth().getUser(decodedToken.uid);
299
+ socket.data.user = {
300
+ uid: decodedToken.uid,
301
+ roles: user.customClaims?.roles ?? ["user"],
302
+ orgId: user.customClaims?.orgId
303
+ };
304
+ next();
305
+ } catch (error) {
306
+ console.error("Socket auth failed:", error);
307
+ next(new Error("Invalid token"));
308
+ }
309
+ });
310
+ io.on("connection", (socket) => {
311
+ const userId = socket.data.user.uid;
312
+ const clientId = socket.handshake.auth.clientId;
313
+ console.log(`[StateSync] Client ${clientId} connected for user ${userId}`);
314
+ stateSync.updateConfig({ clientId });
315
+ socket.join(`user:${userId}`);
316
+ socket.on("stateChange", (...args) => {
317
+ const event = args[0];
318
+ const multiUser = getMultiUserManager();
319
+ if (!multiUser.isSessionOwner(event.threadId, userId)) {
320
+ socket.emit("error", { message: "Not session owner" });
321
+ return;
322
+ }
323
+ stateSync.receiveRemoteChange(event);
324
+ socket.to(`user:${userId}`).emit("remoteChange", event);
325
+ });
326
+ stateSync.on("syncRequired", (changes) => {
327
+ socket.emit("syncBatch", changes);
328
+ });
329
+ socket.on("disconnect", () => {
330
+ console.log(`[StateSync] Client ${clientId} disconnected`);
331
+ socket.leave(`user:${userId}`);
332
+ });
333
+ });
334
+ }
335
+ var init_state_sync = __esm({
336
+ "src/websocket/state-sync.ts"() {
337
+ init_db();
338
+ }
339
+ });
340
+
341
+ // src/routes/observability.ts
342
+ var observability_exports = {};
343
+ __export(observability_exports, {
344
+ default: () => observability_default
345
+ });
346
+ var router, observability_default;
347
+ var init_observability = __esm({
348
+ "src/routes/observability.ts"() {
349
+ router = Router();
350
+ router.get("/metrics", async (req, res) => {
351
+ try {
352
+ const collector = getObservabilityCollector();
353
+ const snapshot = collector.getPerformanceSnapshot();
354
+ res.json(snapshot);
355
+ } catch (error) {
356
+ console.error("Metrics error:", error);
357
+ res.status(500).json({ error: "Failed to get metrics" });
358
+ }
359
+ });
360
+ router.get("/health", async (req, res) => {
361
+ try {
362
+ const collector = getObservabilityCollector();
363
+ const health = await collector.healthCheck();
364
+ const allHealthy = health.every((h) => h.status === "healthy");
365
+ res.status(allHealthy ? 200 : 503).json({
366
+ status: allHealthy ? "healthy" : "degraded",
367
+ timestamp: Date.now(),
368
+ checks: health
369
+ });
370
+ } catch (error) {
371
+ console.error("Health check error:", error);
372
+ res.status(500).json({
373
+ status: "unhealthy",
374
+ error: "Health check failed"
375
+ });
376
+ }
377
+ });
378
+ router.get("/sessions/:threadId/telemetry", async (req, res) => {
379
+ try {
380
+ const collector = getObservabilityCollector();
381
+ const telemetry = collector.getSessionTelemetry(req.params.threadId);
382
+ if (!telemetry) {
383
+ res.status(404).json({ error: "Session not found" });
384
+ return;
385
+ }
386
+ res.json(telemetry);
387
+ } catch (error) {
388
+ console.error("Telemetry error:", error);
389
+ res.status(500).json({ error: "Failed to get telemetry" });
390
+ }
391
+ });
392
+ router.get("/active-sessions", async (req, res) => {
393
+ try {
394
+ const collector = getObservabilityCollector();
395
+ const sessions = collector.getActiveSessions();
396
+ res.json(sessions);
397
+ } catch (error) {
398
+ console.error("Active sessions error:", error);
399
+ res.status(500).json({ error: "Failed to get active sessions" });
400
+ }
401
+ });
402
+ observability_default = router;
403
+ }
404
+ });
17
405
  dotenv.config();
18
406
  var envSchema = z.object({
19
407
  NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
@@ -428,94 +816,33 @@ var EventPersistence = class {
428
816
  this.cleanup().catch((err) => {
429
817
  console.error("[EventPersistence] Cleanup error:", err);
430
818
  });
431
- }, this.options.cleanupIntervalMs);
432
- }
433
- /**
434
- * Stop periodic cleanup timer.
435
- */
436
- stopCleanup() {
437
- if (this.cleanupTimer) {
438
- clearInterval(this.cleanupTimer);
439
- this.cleanupTimer = null;
440
- }
441
- }
442
- /**
443
- * Clear all persisted events.
444
- */
445
- async clear() {
446
- await this.store.clear();
447
- }
448
- /**
449
- * Get the underlying store (for testing or custom queries).
450
- */
451
- getStore() {
452
- return this.store;
453
- }
454
- };
455
- function initializeFirebase() {
456
- if (admin.apps.length > 0) {
457
- return admin.app();
458
- }
459
- const projectId = process.env.FIREBASE_PROJECT_ID;
460
- const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;
461
- if (emulatorHost) {
462
- const app = admin.initializeApp({
463
- projectId: projectId || "demo-project"
464
- });
465
- console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);
466
- return app;
467
- }
468
- const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;
469
- if (serviceAccountPath) {
470
- const serviceAccount = __require(serviceAccountPath);
471
- return admin.initializeApp({
472
- credential: admin.credential.cert(serviceAccount),
473
- projectId
474
- });
475
- }
476
- const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;
477
- const privateKey = process.env.FIREBASE_PRIVATE_KEY;
478
- if (projectId && clientEmail && privateKey) {
479
- return admin.initializeApp({
480
- credential: admin.credential.cert({
481
- projectId,
482
- clientEmail,
483
- privateKey: privateKey.replace(/\\n/g, "\n")
484
- }),
485
- projectId
486
- });
487
- }
488
- if (projectId) {
489
- return admin.initializeApp({
490
- credential: admin.credential.applicationDefault(),
491
- projectId
492
- });
819
+ }, this.options.cleanupIntervalMs);
493
820
  }
494
- throw new Error(
495
- "@almadar/server: Cannot initialize Firebase \u2014 no credentials found. Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST."
496
- );
497
- }
498
- function getApp() {
499
- if (admin.apps.length === 0) {
500
- throw new Error(
501
- "@almadar/server: Firebase Admin SDK is not initialized. Call initializeFirebase() or admin.initializeApp() before using @almadar/server."
502
- );
821
+ /**
822
+ * Stop periodic cleanup timer.
823
+ */
824
+ stopCleanup() {
825
+ if (this.cleanupTimer) {
826
+ clearInterval(this.cleanupTimer);
827
+ this.cleanupTimer = null;
828
+ }
503
829
  }
504
- return admin.app();
505
- }
506
- function getFirestore() {
507
- return getApp().firestore();
508
- }
509
- function getAuth() {
510
- return getApp().auth();
511
- }
512
- var db = new Proxy({}, {
513
- get(_target, prop, receiver) {
514
- const firestore = getFirestore();
515
- const value = Reflect.get(firestore, prop, receiver);
516
- return typeof value === "function" ? value.bind(firestore) : value;
830
+ /**
831
+ * Clear all persisted events.
832
+ */
833
+ async clear() {
834
+ await this.store.clear();
517
835
  }
518
- });
836
+ /**
837
+ * Get the underlying store (for testing or custom queries).
838
+ */
839
+ getStore() {
840
+ return this.store;
841
+ }
842
+ };
843
+
844
+ // src/services/DataService.ts
845
+ init_db();
519
846
  var MockDataService = class {
520
847
  stores = /* @__PURE__ */ new Map();
521
848
  schemas = /* @__PURE__ */ new Map();
@@ -1276,6 +1603,9 @@ function debugEventsRouter() {
1276
1603
  });
1277
1604
  return router2;
1278
1605
  }
1606
+
1607
+ // src/index.ts
1608
+ init_db();
1279
1609
  var wss = null;
1280
1610
  function setupEventBroadcast(server, path = "/ws/events") {
1281
1611
  if (wss) {
@@ -1502,6 +1832,7 @@ var validateParams = (schema) => async (req, res, next) => {
1502
1832
  };
1503
1833
 
1504
1834
  // src/middleware/authenticateFirebase.ts
1835
+ init_db();
1505
1836
  var BEARER_PREFIX = "Bearer ";
1506
1837
  var DEV_USER = {
1507
1838
  uid: "dev-user-001",
@@ -1593,6 +1924,9 @@ function fromFirestoreFormat(data) {
1593
1924
  }
1594
1925
  return result;
1595
1926
  }
1927
+
1928
+ // src/stores/SchemaStore.ts
1929
+ init_db();
1596
1930
  var SchemaProtectionService = class {
1597
1931
  /**
1598
1932
  * Compare two schemas and detect destructive changes.
@@ -1826,6 +2160,7 @@ var SchemaStore = class {
1826
2160
  };
1827
2161
 
1828
2162
  // src/stores/SnapshotStore.ts
2163
+ init_db();
1829
2164
  var SNAPSHOTS_COLLECTION = "snapshots";
1830
2165
  var SnapshotStore = class {
1831
2166
  appsCollection;
@@ -1909,6 +2244,7 @@ var SnapshotStore = class {
1909
2244
  };
1910
2245
 
1911
2246
  // src/stores/ChangeSetStore.ts
2247
+ init_db();
1912
2248
  var CHANGESETS_COLLECTION = "changesets";
1913
2249
  var ChangeSetStore = class {
1914
2250
  appsCollection;
@@ -1985,6 +2321,7 @@ var ChangeSetStore = class {
1985
2321
  };
1986
2322
 
1987
2323
  // src/stores/ValidationStore.ts
2324
+ init_db();
1988
2325
  var VALIDATION_COLLECTION = "validation";
1989
2326
  var VALIDATION_DOC_ID = "current";
1990
2327
  var ValidationStore = class {
@@ -2034,187 +2371,6 @@ var ValidationStore = class {
2034
2371
  });
2035
2372
  }
2036
2373
  };
2037
- var memoryManager = null;
2038
- function getMemoryManager() {
2039
- if (!memoryManager) {
2040
- memoryManager = new MemoryManager({
2041
- db,
2042
- usersCollection: "agent_memory_users",
2043
- projectsCollection: "agent_memory_projects",
2044
- generationsCollection: "agent_memory_generations",
2045
- patternsCollection: "agent_memory_patterns",
2046
- interruptsCollection: "agent_memory_interrupts",
2047
- feedbackCollection: "agent_memory_feedback",
2048
- checkpointsCollection: "agent_memory_checkpoints",
2049
- toolPreferencesCollection: "agent_memory_tool_preferences"
2050
- });
2051
- }
2052
- return memoryManager;
2053
- }
2054
- function resetMemoryManager() {
2055
- memoryManager = null;
2056
- }
2057
- var sessionManager = null;
2058
- function createFirestoreAdapter(firestore) {
2059
- return firestore;
2060
- }
2061
- function getSessionManager() {
2062
- if (!sessionManager) {
2063
- sessionManager = new SessionManager({
2064
- mode: "firestore",
2065
- firestoreDb: createFirestoreAdapter(db),
2066
- memoryManager: getMemoryManager(),
2067
- // Enable GAP-002D
2068
- compactionConfig: {
2069
- maxTokens: 15e4,
2070
- keepRecentMessages: 10,
2071
- strategy: "last"
2072
- }
2073
- });
2074
- }
2075
- return sessionManager;
2076
- }
2077
- function resetSessionManager() {
2078
- sessionManager = null;
2079
- }
2080
- async function createServerSkillAgent(options) {
2081
- const memoryManager2 = getMemoryManager();
2082
- getSessionManager();
2083
- const observability = getObservabilityCollector();
2084
- const multiUser = getMultiUserManager();
2085
- if (options.threadId) {
2086
- const access = multiUser.canAccessSession(options.threadId, {
2087
- userId: options.userId,
2088
- roles: ["user"]
2089
- });
2090
- if (!access.allowed) {
2091
- throw new Error(`Access denied: ${access.reason}`);
2092
- }
2093
- }
2094
- observability.startSession(options.threadId ?? "new", options.userId);
2095
- const workflowToolWrapper = createWorkflowToolWrapper({
2096
- maxRetries: 2,
2097
- enableTelemetry: true,
2098
- timeoutMs: 3e5
2099
- // 5 minutes
2100
- });
2101
- try {
2102
- const result = await createSkillAgent({
2103
- ...options,
2104
- memoryManager: memoryManager2,
2105
- // GAP-001: Enable memory
2106
- userId: options.userId,
2107
- // GAP-002D: Session → Memory sync
2108
- appId: options.appId,
2109
- toolWrapper: workflowToolWrapper.wrap
2110
- // Always use workflow wrapper for reliability
2111
- });
2112
- if (result.threadId) {
2113
- multiUser.assignSessionOwnership(result.threadId, options.userId);
2114
- }
2115
- observability.recordEvent({
2116
- type: "session_start",
2117
- sessionId: result.threadId,
2118
- userId: options.userId,
2119
- payload: { skill: options.skill }
2120
- });
2121
- return result;
2122
- } catch (error) {
2123
- observability.recordError(options.threadId ?? "new", error);
2124
- throw error;
2125
- }
2126
- }
2127
- async function multiUserMiddleware(req, res, next) {
2128
- const userId = req.user?.uid;
2129
- if (!userId) {
2130
- res.status(401).json({ error: "Authentication required" });
2131
- return;
2132
- }
2133
- req.userContext = createUserContext(userId, {
2134
- orgId: req.user?.orgId,
2135
- roles: req.user?.roles ?? ["user"]
2136
- });
2137
- const originalJson = res.json.bind(res);
2138
- res.json = (body) => {
2139
- if (body && typeof body === "object" && "threadId" in body) {
2140
- const multiUser = getMultiUserManager();
2141
- multiUser.assignSessionOwnership(
2142
- body.threadId,
2143
- userId
2144
- );
2145
- }
2146
- return originalJson(body);
2147
- };
2148
- next();
2149
- }
2150
- async function verifyFirebaseAuth(req, res, next) {
2151
- const authHeader = req.headers.authorization;
2152
- if (!authHeader?.startsWith("Bearer ")) {
2153
- res.status(401).json({ error: "No token provided" });
2154
- return;
2155
- }
2156
- const token = authHeader.split("Bearer ")[1];
2157
- try {
2158
- const decodedToken = await getAuth().verifyIdToken(token);
2159
- const user = await getAuth().getUser(decodedToken.uid);
2160
- req.user = {
2161
- uid: decodedToken.uid,
2162
- email: decodedToken.email,
2163
- roles: user.customClaims?.roles ?? ["user"],
2164
- orgId: user.customClaims?.orgId
2165
- };
2166
- next();
2167
- } catch (error) {
2168
- console.error("Token verification failed:", error);
2169
- res.status(401).json({ error: "Invalid token" });
2170
- }
2171
- }
2172
- function setupStateSyncWebSocket(io) {
2173
- const stateSync = getStateSyncManager();
2174
- io.use(async (socket, next) => {
2175
- try {
2176
- const token = socket.handshake.auth.token;
2177
- if (!token) {
2178
- return next(new Error("Authentication required"));
2179
- }
2180
- const decodedToken = await getAuth().verifyIdToken(token);
2181
- const user = await getAuth().getUser(decodedToken.uid);
2182
- socket.data.user = {
2183
- uid: decodedToken.uid,
2184
- roles: user.customClaims?.roles ?? ["user"],
2185
- orgId: user.customClaims?.orgId
2186
- };
2187
- next();
2188
- } catch (error) {
2189
- console.error("Socket auth failed:", error);
2190
- next(new Error("Invalid token"));
2191
- }
2192
- });
2193
- io.on("connection", (socket) => {
2194
- const userId = socket.data.user.uid;
2195
- const clientId = socket.handshake.auth.clientId;
2196
- console.log(`[StateSync] Client ${clientId} connected for user ${userId}`);
2197
- stateSync.updateConfig({ clientId });
2198
- socket.join(`user:${userId}`);
2199
- socket.on("stateChange", (...args) => {
2200
- const event = args[0];
2201
- const multiUser = getMultiUserManager();
2202
- if (!multiUser.isSessionOwner(event.threadId, userId)) {
2203
- socket.emit("error", { message: "Not session owner" });
2204
- return;
2205
- }
2206
- stateSync.receiveRemoteChange(event);
2207
- socket.to(`user:${userId}`).emit("remoteChange", event);
2208
- });
2209
- stateSync.on("syncRequired", (changes) => {
2210
- socket.emit("syncBatch", changes);
2211
- });
2212
- socket.on("disconnect", () => {
2213
- console.log(`[StateSync] Client ${clientId} disconnected`);
2214
- socket.leave(`user:${userId}`);
2215
- });
2216
- });
2217
- }
2218
2374
 
2219
2375
  // src/lib/serviceDiscovery.ts
2220
2376
  var InMemoryServiceRegistry = class {
@@ -2383,60 +2539,6 @@ var ServiceDiscovery = class {
2383
2539
  return this.registry;
2384
2540
  }
2385
2541
  };
2386
- var router = Router();
2387
- router.get("/metrics", async (req, res) => {
2388
- try {
2389
- const collector = getObservabilityCollector();
2390
- const snapshot = collector.getPerformanceSnapshot();
2391
- res.json(snapshot);
2392
- } catch (error) {
2393
- console.error("Metrics error:", error);
2394
- res.status(500).json({ error: "Failed to get metrics" });
2395
- }
2396
- });
2397
- router.get("/health", async (req, res) => {
2398
- try {
2399
- const collector = getObservabilityCollector();
2400
- const health = await collector.healthCheck();
2401
- const allHealthy = health.every((h) => h.status === "healthy");
2402
- res.status(allHealthy ? 200 : 503).json({
2403
- status: allHealthy ? "healthy" : "degraded",
2404
- timestamp: Date.now(),
2405
- checks: health
2406
- });
2407
- } catch (error) {
2408
- console.error("Health check error:", error);
2409
- res.status(500).json({
2410
- status: "unhealthy",
2411
- error: "Health check failed"
2412
- });
2413
- }
2414
- });
2415
- router.get("/sessions/:threadId/telemetry", async (req, res) => {
2416
- try {
2417
- const collector = getObservabilityCollector();
2418
- const telemetry = collector.getSessionTelemetry(req.params.threadId);
2419
- if (!telemetry) {
2420
- res.status(404).json({ error: "Session not found" });
2421
- return;
2422
- }
2423
- res.json(telemetry);
2424
- } catch (error) {
2425
- console.error("Telemetry error:", error);
2426
- res.status(500).json({ error: "Failed to get telemetry" });
2427
- }
2428
- });
2429
- router.get("/active-sessions", async (req, res) => {
2430
- try {
2431
- const collector = getObservabilityCollector();
2432
- const sessions = collector.getActiveSessions();
2433
- res.json(sessions);
2434
- } catch (error) {
2435
- console.error("Active sessions error:", error);
2436
- res.status(500).json({ error: "Failed to get active sessions" });
2437
- }
2438
- });
2439
- var observability_default = router;
2440
2542
 
2441
2543
  // src/index.ts
2442
2544
  var dataService = new Proxy({}, {
@@ -2454,7 +2556,43 @@ var serverEventBus = new Proxy({}, {
2454
2556
  return Reflect.get(getServerEventBus(), prop, receiver);
2455
2557
  }
2456
2558
  });
2559
+ async function getMemoryManager2(...args) {
2560
+ const m = await Promise.resolve().then(() => (init_memory(), memory_exports));
2561
+ return m.getMemoryManager(...args);
2562
+ }
2563
+ async function resetMemoryManager2() {
2564
+ const m = await Promise.resolve().then(() => (init_memory(), memory_exports));
2565
+ return m.resetMemoryManager();
2566
+ }
2567
+ async function getSessionManager2(...args) {
2568
+ const m = await Promise.resolve().then(() => (init_session(), session_exports));
2569
+ return m.getSessionManager(...args);
2570
+ }
2571
+ async function resetSessionManager2() {
2572
+ const m = await Promise.resolve().then(() => (init_session(), session_exports));
2573
+ return m.resetSessionManager();
2574
+ }
2575
+ async function createServerSkillAgent2(...args) {
2576
+ const m = await Promise.resolve().then(() => (init_skill_agent(), skill_agent_exports));
2577
+ return m.createServerSkillAgent(...args);
2578
+ }
2579
+ async function multiUserMiddleware2(...args) {
2580
+ const m = await Promise.resolve().then(() => (init_multi_user(), multi_user_exports));
2581
+ return m.multiUserMiddleware(...args);
2582
+ }
2583
+ async function verifyFirebaseAuth2(...args) {
2584
+ const m = await Promise.resolve().then(() => (init_multi_user(), multi_user_exports));
2585
+ return m.verifyFirebaseAuth(...args);
2586
+ }
2587
+ async function setupStateSyncWebSocket2(...args) {
2588
+ const m = await Promise.resolve().then(() => (init_state_sync(), state_sync_exports));
2589
+ return m.setupStateSyncWebSocket(...args);
2590
+ }
2591
+ async function observabilityRouter() {
2592
+ const m = await Promise.resolve().then(() => (init_observability(), observability_exports));
2593
+ return m.default;
2594
+ }
2457
2595
 
2458
- 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, getDataService, getFirestore, getMemoryManager, getMockDataService, getServerEventBus, getSessionManager, getWebSocketServer, initializeFirebase, logger, mockDataService, multiUserMiddleware, notFoundHandler, observability_default as observabilityRouter, parseQueryFilters, resetDataService, resetMemoryManager, resetMockDataService, resetServerEventBus, resetSessionManager, seedMockData, serverEventBus, setupEventBroadcast, setupStateSyncWebSocket, toFirestoreFormat, validateBody, validateParams, validateQuery, verifyFirebaseAuth };
2596
+ 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, createServerSkillAgent2 as createServerSkillAgent, dataService, db, debugEventsRouter, emitEntityEvent, env, errorHandler, extractPaginationParams, fromFirestoreFormat, getAuth, getConnectedClientCount, getDataService, getFirestore, getMemoryManager2 as getMemoryManager, getMockDataService, getServerEventBus, getSessionManager2 as getSessionManager, getWebSocketServer, initializeFirebase, logger, mockDataService, multiUserMiddleware2 as multiUserMiddleware, notFoundHandler, observabilityRouter, parseQueryFilters, resetDataService, resetMemoryManager2 as resetMemoryManager, resetMockDataService, resetServerEventBus, resetSessionManager2 as resetSessionManager, seedMockData, serverEventBus, setupEventBroadcast, setupStateSyncWebSocket2 as setupStateSyncWebSocket, toFirestoreFormat, validateBody, validateParams, validateQuery, verifyFirebaseAuth2 as verifyFirebaseAuth };
2459
2597
  //# sourceMappingURL=index.js.map
2460
2598
  //# sourceMappingURL=index.js.map