@almadar/server 1.0.16 → 1.2.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
@@ -6,6 +6,7 @@ export { default as admin } from 'firebase-admin';
6
6
  import { WebSocketServer, WebSocket } from 'ws';
7
7
  import { faker } from '@faker-js/faker';
8
8
  import { diffSchemas, categorizeRemovals, detectPageContentReduction, isDestructiveChange, hasSignificantPageReduction, requiresConfirmation } from '@almadar/core';
9
+ import { getObservabilityCollector, MemoryManager, SessionManager, getMultiUserManager, createSkillAgent, createUserContext, getStateSyncManager } from '@almadar/agent';
9
10
 
10
11
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
12
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -176,25 +177,25 @@ function emitEntityEvent(entityType, action, payload) {
176
177
  serverEventBus.emit(eventType, payload, { orbital: entityType });
177
178
  }
178
179
  function debugEventsRouter() {
179
- const router = Router();
180
+ const router2 = Router();
180
181
  if (process.env.NODE_ENV !== "development") {
181
- return router;
182
+ return router2;
182
183
  }
183
- router.get("/event-log", (_req, res) => {
184
+ router2.get("/event-log", (_req, res) => {
184
185
  const limit = parseInt(String(_req.query.limit) || "50", 10);
185
186
  const events = serverEventBus.getRecentEvents(limit);
186
187
  res.json({ count: events.length, events });
187
188
  });
188
- router.delete("/event-log", (_req, res) => {
189
+ router2.delete("/event-log", (_req, res) => {
189
190
  serverEventBus.clearEventLog();
190
191
  res.json({ cleared: true });
191
192
  });
192
- router.get("/listeners", (_req, res) => {
193
+ router2.get("/listeners", (_req, res) => {
193
194
  const counts = serverEventBus.getListenerCounts();
194
195
  const total = Object.values(counts).reduce((sum, n) => sum + n, 0);
195
196
  res.json({ total, events: counts });
196
197
  });
197
- return router;
198
+ return router2;
198
199
  }
199
200
  var firebaseApp = null;
200
201
  function initializeFirebase() {
@@ -1590,7 +1591,234 @@ var ValidationStore = class {
1590
1591
  });
1591
1592
  }
1592
1593
  };
1594
+ var memoryManager = null;
1595
+ function getMemoryManager() {
1596
+ if (!memoryManager) {
1597
+ memoryManager = new MemoryManager({
1598
+ db,
1599
+ usersCollection: "agent_memory_users",
1600
+ projectsCollection: "agent_memory_projects",
1601
+ generationsCollection: "agent_memory_generations",
1602
+ patternsCollection: "agent_memory_patterns",
1603
+ interruptsCollection: "agent_memory_interrupts",
1604
+ feedbackCollection: "agent_memory_feedback",
1605
+ checkpointsCollection: "agent_memory_checkpoints",
1606
+ toolPreferencesCollection: "agent_memory_tool_preferences"
1607
+ });
1608
+ }
1609
+ return memoryManager;
1610
+ }
1611
+ function resetMemoryManager() {
1612
+ memoryManager = null;
1613
+ }
1614
+ var sessionManager = null;
1615
+ function createFirestoreAdapter(firestore) {
1616
+ return firestore;
1617
+ }
1618
+ function getSessionManager() {
1619
+ if (!sessionManager) {
1620
+ sessionManager = new SessionManager({
1621
+ mode: "firestore",
1622
+ firestoreDb: createFirestoreAdapter(db),
1623
+ memoryManager: getMemoryManager(),
1624
+ // Enable GAP-002D
1625
+ compactionConfig: {
1626
+ maxTokens: 15e4,
1627
+ keepRecentMessages: 10,
1628
+ strategy: "last"
1629
+ }
1630
+ });
1631
+ }
1632
+ return sessionManager;
1633
+ }
1634
+ function resetSessionManager() {
1635
+ sessionManager = null;
1636
+ }
1637
+ async function createServerSkillAgent(options) {
1638
+ const memoryManager2 = getMemoryManager();
1639
+ getSessionManager();
1640
+ const observability = getObservabilityCollector();
1641
+ const multiUser = getMultiUserManager();
1642
+ if (options.threadId) {
1643
+ const access = multiUser.canAccessSession(options.threadId, {
1644
+ userId: options.userId,
1645
+ roles: ["user"]
1646
+ });
1647
+ if (!access.allowed) {
1648
+ throw new Error(`Access denied: ${access.reason}`);
1649
+ }
1650
+ }
1651
+ observability.startSession(options.threadId ?? "new", options.userId);
1652
+ try {
1653
+ const result = await createSkillAgent({
1654
+ ...options,
1655
+ memoryManager: memoryManager2,
1656
+ // GAP-001: Enable memory
1657
+ userId: options.userId,
1658
+ // GAP-002D: Session → Memory sync
1659
+ appId: options.appId
1660
+ });
1661
+ if (result.threadId) {
1662
+ multiUser.assignSessionOwnership(result.threadId, options.userId);
1663
+ }
1664
+ observability.recordEvent({
1665
+ type: "session_start",
1666
+ sessionId: result.threadId,
1667
+ userId: options.userId,
1668
+ payload: { skill: options.skill }
1669
+ });
1670
+ return result;
1671
+ } catch (error) {
1672
+ observability.recordError(options.threadId ?? "new", error);
1673
+ throw error;
1674
+ }
1675
+ }
1676
+ async function multiUserMiddleware(req, res, next) {
1677
+ const userId = req.user?.uid;
1678
+ if (!userId) {
1679
+ res.status(401).json({ error: "Authentication required" });
1680
+ return;
1681
+ }
1682
+ req.userContext = createUserContext(userId, {
1683
+ orgId: req.user?.orgId,
1684
+ roles: req.user?.roles ?? ["user"]
1685
+ });
1686
+ const originalJson = res.json.bind(res);
1687
+ res.json = (body) => {
1688
+ if (body && typeof body === "object" && "threadId" in body) {
1689
+ const multiUser = getMultiUserManager();
1690
+ multiUser.assignSessionOwnership(
1691
+ body.threadId,
1692
+ userId
1693
+ );
1694
+ }
1695
+ return originalJson(body);
1696
+ };
1697
+ next();
1698
+ }
1699
+ async function verifyFirebaseAuth(req, res, next) {
1700
+ const authHeader = req.headers.authorization;
1701
+ if (!authHeader?.startsWith("Bearer ")) {
1702
+ res.status(401).json({ error: "No token provided" });
1703
+ return;
1704
+ }
1705
+ const token = authHeader.split("Bearer ")[1];
1706
+ try {
1707
+ const decodedToken = await getAuth().verifyIdToken(token);
1708
+ const user = await getAuth().getUser(decodedToken.uid);
1709
+ req.user = {
1710
+ uid: decodedToken.uid,
1711
+ email: decodedToken.email,
1712
+ roles: user.customClaims?.roles ?? ["user"],
1713
+ orgId: user.customClaims?.orgId
1714
+ };
1715
+ next();
1716
+ } catch (error) {
1717
+ console.error("Token verification failed:", error);
1718
+ res.status(401).json({ error: "Invalid token" });
1719
+ }
1720
+ }
1721
+ function setupStateSyncWebSocket(io) {
1722
+ const stateSync = getStateSyncManager();
1723
+ io.use(async (socket, next) => {
1724
+ try {
1725
+ const token = socket.handshake.auth.token;
1726
+ if (!token) {
1727
+ return next(new Error("Authentication required"));
1728
+ }
1729
+ const decodedToken = await getAuth().verifyIdToken(token);
1730
+ const user = await getAuth().getUser(decodedToken.uid);
1731
+ socket.data.user = {
1732
+ uid: decodedToken.uid,
1733
+ roles: user.customClaims?.roles ?? ["user"],
1734
+ orgId: user.customClaims?.orgId
1735
+ };
1736
+ next();
1737
+ } catch (error) {
1738
+ console.error("Socket auth failed:", error);
1739
+ next(new Error("Invalid token"));
1740
+ }
1741
+ });
1742
+ io.on("connection", (socket) => {
1743
+ const userId = socket.data.user.uid;
1744
+ const clientId = socket.handshake.auth.clientId;
1745
+ console.log(`[StateSync] Client ${clientId} connected for user ${userId}`);
1746
+ stateSync.updateConfig({ clientId });
1747
+ socket.join(`user:${userId}`);
1748
+ socket.on("stateChange", (...args) => {
1749
+ const event = args[0];
1750
+ const multiUser = getMultiUserManager();
1751
+ if (!multiUser.isSessionOwner(event.threadId, userId)) {
1752
+ socket.emit("error", { message: "Not session owner" });
1753
+ return;
1754
+ }
1755
+ stateSync.receiveRemoteChange(event);
1756
+ socket.to(`user:${userId}`).emit("remoteChange", event);
1757
+ });
1758
+ stateSync.on("syncRequired", (changes) => {
1759
+ socket.emit("syncBatch", changes);
1760
+ });
1761
+ socket.on("disconnect", () => {
1762
+ console.log(`[StateSync] Client ${clientId} disconnected`);
1763
+ socket.leave(`user:${userId}`);
1764
+ });
1765
+ });
1766
+ }
1767
+ var router = Router();
1768
+ router.get("/metrics", async (req, res) => {
1769
+ try {
1770
+ const collector = getObservabilityCollector();
1771
+ const snapshot = collector.getPerformanceSnapshot();
1772
+ res.json(snapshot);
1773
+ } catch (error) {
1774
+ console.error("Metrics error:", error);
1775
+ res.status(500).json({ error: "Failed to get metrics" });
1776
+ }
1777
+ });
1778
+ router.get("/health", async (req, res) => {
1779
+ try {
1780
+ const collector = getObservabilityCollector();
1781
+ const health = await collector.healthCheck();
1782
+ const allHealthy = health.every((h) => h.status === "healthy");
1783
+ res.status(allHealthy ? 200 : 503).json({
1784
+ status: allHealthy ? "healthy" : "degraded",
1785
+ timestamp: Date.now(),
1786
+ checks: health
1787
+ });
1788
+ } catch (error) {
1789
+ console.error("Health check error:", error);
1790
+ res.status(500).json({
1791
+ status: "unhealthy",
1792
+ error: "Health check failed"
1793
+ });
1794
+ }
1795
+ });
1796
+ router.get("/sessions/:threadId/telemetry", async (req, res) => {
1797
+ try {
1798
+ const collector = getObservabilityCollector();
1799
+ const telemetry = collector.getSessionTelemetry(req.params.threadId);
1800
+ if (!telemetry) {
1801
+ res.status(404).json({ error: "Session not found" });
1802
+ return;
1803
+ }
1804
+ res.json(telemetry);
1805
+ } catch (error) {
1806
+ console.error("Telemetry error:", error);
1807
+ res.status(500).json({ error: "Failed to get telemetry" });
1808
+ }
1809
+ });
1810
+ router.get("/active-sessions", async (req, res) => {
1811
+ try {
1812
+ const collector = getObservabilityCollector();
1813
+ const sessions = collector.getActiveSessions();
1814
+ res.json(sessions);
1815
+ } catch (error) {
1816
+ console.error("Active sessions error:", error);
1817
+ res.status(500).json({ error: "Failed to get active sessions" });
1818
+ }
1819
+ });
1820
+ var observability_default = router;
1593
1821
 
1594
- export { AppError, ChangeSetStore, ConflictError, EventBus, ForbiddenError, MockDataService, NotFoundError, SchemaProtectionService, SchemaStore, SnapshotStore, UnauthorizedError, ValidationError, ValidationStore, applyFiltersToQuery, asyncHandler, authenticateFirebase, closeWebSocketServer, dataService, db, debugEventsRouter, emitEntityEvent, env, errorHandler, extractPaginationParams, fromFirestoreFormat, getAuth, getConnectedClientCount, getFirestore, getWebSocketServer, logger, mockDataService, notFoundHandler, parseQueryFilters, seedMockData, serverEventBus, setupEventBroadcast, toFirestoreFormat, validateBody, validateParams, validateQuery };
1822
+ 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, logger, mockDataService, multiUserMiddleware, notFoundHandler, observability_default as observabilityRouter, parseQueryFilters, resetMemoryManager, resetSessionManager, seedMockData, serverEventBus, setupEventBroadcast, setupStateSyncWebSocket, toFirestoreFormat, validateBody, validateParams, validateQuery, verifyFirebaseAuth };
1595
1823
  //# sourceMappingURL=index.js.map
1596
1824
  //# sourceMappingURL=index.js.map