@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.
@@ -1,4 +1,4 @@
1
- import { createUserContext, getMultiUserManager } from '@almadar/agent';
1
+ import { createUserContext, getMultiUserManager } from '@almadar-io/agent';
2
2
  import admin from 'firebase-admin';
3
3
 
4
4
  // src/middleware/multi-user.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/db.ts","../../src/middleware/multi-user.ts"],"names":[],"mappings":";;;;AAoFA,SAAS,MAAA,GAAwB;AAC/B,EAAA,IAAI,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,MAAM,GAAA,EAAI;AACnB;AAKO,SAAS,YAAA,GAA0C;AACxD,EAAA,OAAO,MAAA,GAAS,SAAA,EAAU;AAC5B;AAKO,SAAS,OAAA,GAA2B;AACzC,EAAA,OAAO,MAAA,GAAS,IAAA,EAAK;AACvB;AASkB,IAAI,KAAA,CAAM,EAAC,EAAgC;AAAA,EAC3D,GAAA,CAAI,OAAA,EAAS,IAAA,EAAM,QAAA,EAAU;AAC3B,IAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,MAAM,QAAQ,CAAA;AACnD,IAAA,OAAO,OAAO,KAAA,KAAU,UAAA,GAAa,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA,GAAI,KAAA;AAAA,EAC/D;AACF,CAAC;;;ACvFD,eAAsB,mBAAA,CACpB,GAAA,EACA,GAAA,EACA,IAAA,EACe;AACf,EAAA,MAAM,MAAA,GAAS,IAAI,IAAA,EAAM,GAAA;AAEzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,2BAA2B,CAAA;AACzD,IAAA;AAAA,EACF;AAGA,EAAA,GAAA,CAAI,WAAA,GAAc,kBAAkB,MAAA,EAAQ;AAAA,IAC1C,KAAA,EAAO,IAAI,IAAA,EAAM,KAAA;AAAA,IACjB,KAAA,EAAO,GAAA,CAAI,IAAA,EAAM,KAAA,IAAS,CAAC,MAAM;AAAA,GAClC,CAAA;AAGD,EAAA,MAAM,YAAA,GAAe,GAAA,CAAI,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA;AACtC,EAAA,GAAA,CAAI,IAAA,GAAO,CAAC,IAAA,KAAkB;AAC5B,IAAA,IAAI,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,cAAc,IAAA,EAAM;AAC1D,MAAA,MAAM,YAAY,mBAAA,EAAoB;AACtC,MAAA,SAAA,CAAU,sBAAA;AAAA,QACP,IAAA,CAA8B,QAAA;AAAA,QAC/B;AAAA,OACF;AAAA,IACF;AACA,IAAA,OAAO,aAAa,IAAI,CAAA;AAAA,EAC1B,CAAA;AAEA,EAAA,IAAA,EAAK;AACP;AAKA,eAAsB,kBAAA,CACpB,GAAA,EACA,GAAA,EACA,IAAA,EACe;AACf,EAAA,MAAM,UAAA,GAAa,IAAI,OAAA,CAAQ,aAAA;AAE/B,EAAA,IAAI,CAAC,UAAA,EAAY,UAAA,CAAW,SAAS,CAAA,EAAG;AACtC,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,qBAAqB,CAAA;AACnD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,CAAM,SAAS,EAAE,CAAC,CAAA;AAE3C,EAAA,IAAI;AACF,IAAA,MAAM,YAAA,GAAe,MAAM,OAAA,EAAQ,CAAE,cAAc,KAAK,CAAA;AAGxD,IAAA,MAAM,OAAO,MAAM,OAAA,EAAQ,CAAE,OAAA,CAAQ,aAAa,GAAG,CAAA;AAErD,IAAA,GAAA,CAAI,IAAA,GAAO;AAAA,MACT,KAAK,YAAA,CAAa,GAAA;AAAA,MAClB,OAAO,YAAA,CAAa,KAAA;AAAA,MACpB,KAAA,EAAQ,IAAA,CAAK,YAAA,EAAc,KAAA,IAAsB,CAAC,MAAM,CAAA;AAAA,MACxD,KAAA,EAAO,KAAK,YAAA,EAAc;AAAA,KAC5B;AAEA,IAAA,IAAA,EAAK;AAAA,EACP,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,8BAA8B,KAAK,CAAA;AACjD,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,iBAAiB,CAAA;AAAA,EACjD;AACF","file":"multi-user.js","sourcesContent":["/**\n * Database Accessors & Initialization\n *\n * This module provides:\n * - `initializeFirebase()` — convenience function to init Firebase from env vars\n * - `getFirestore()`, `getAuth()` — accessors for Firebase services\n * - `db` — lazy Firestore proxy (no eager initialization)\n *\n * The consuming application MUST call `initializeFirebase()` or\n * `admin.initializeApp()` before using any Firebase-dependent features.\n */\n\nimport admin from 'firebase-admin';\n\n/**\n * Initialize Firebase Admin SDK from environment variables.\n *\n * Reads: FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY,\n * FIREBASE_SERVICE_ACCOUNT_PATH, FIRESTORE_EMULATOR_HOST\n *\n * Safe to call multiple times — returns existing app if already initialized.\n */\nexport function initializeFirebase(): admin.app.App {\n // Already initialized — return existing app\n if (admin.apps.length > 0) {\n return admin.app();\n }\n\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;\n\n // Emulator mode — no credentials needed\n if (emulatorHost) {\n const app = admin.initializeApp({\n projectId: projectId || 'demo-project',\n });\n console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);\n return app;\n }\n\n // Service account file\n const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;\n if (serviceAccountPath) {\n // Dynamic require for JSON service account file at runtime\n const serviceAccount = require(serviceAccountPath) as Record<string, unknown>;\n return admin.initializeApp({\n credential: admin.credential.cert(serviceAccount),\n projectId,\n });\n }\n\n // Inline credentials\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY;\n if (projectId && clientEmail && privateKey) {\n return admin.initializeApp({\n credential: admin.credential.cert({\n projectId,\n clientEmail,\n privateKey: privateKey.replace(/\\\\n/g, '\\n'),\n }),\n projectId,\n });\n }\n\n // Application default credentials (Cloud Run, etc.)\n if (projectId) {\n return admin.initializeApp({\n credential: admin.credential.applicationDefault(),\n projectId,\n });\n }\n\n throw new Error(\n '@almadar/server: Cannot initialize Firebase — no credentials found. ' +\n 'Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, ' +\n 'or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST.'\n );\n}\n\n/**\n * Get the initialized Firebase app.\n * Throws if Firebase Admin SDK has not been initialized.\n */\nfunction getApp(): admin.app.App {\n if (admin.apps.length === 0) {\n throw new Error(\n '@almadar/server: Firebase Admin SDK is not initialized. ' +\n 'Call initializeFirebase() or admin.initializeApp() before using @almadar/server.'\n );\n }\n return admin.app();\n}\n\n/**\n * Get Firestore instance from the pre-initialized Firebase app.\n */\nexport function getFirestore(): admin.firestore.Firestore {\n return getApp().firestore();\n}\n\n/**\n * Get Firebase Auth instance from the pre-initialized Firebase app.\n */\nexport function getAuth(): admin.auth.Auth {\n return getApp().auth();\n}\n\n// Re-export admin for convenience\nexport { admin };\n\n/**\n * Lazy Firestore proxy — resolves on first property access, not at import time.\n * This prevents the \"Firebase not initialized\" error during module loading.\n */\nexport const db = new Proxy({} as admin.firestore.Firestore, {\n get(_target, prop, receiver) {\n const firestore = getFirestore();\n const value = Reflect.get(firestore, prop, receiver);\n return typeof value === 'function' ? value.bind(firestore) : value;\n },\n});\n","/**\n * Multi-User Middleware\n *\n * Provides user isolation and session ownership using Firebase Auth.\n *\n * @packageDocumentation\n */\n\nimport { getMultiUserManager, createUserContext } from '@almadar/agent';\nimport { getAuth } from '../lib/db.js';\nimport type { Request, Response, NextFunction } from 'express';\n\n// Extend Express Request to include Firebase user\ndeclare global {\n namespace Express {\n interface Request {\n user?: {\n uid: string;\n email?: string;\n roles?: string[];\n orgId?: string;\n };\n userContext?: {\n userId: string;\n orgId?: string;\n roles?: string[];\n };\n }\n }\n}\n\n/**\n * Middleware to set up user context from Firebase Auth\n */\nexport async function multiUserMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n): Promise<void> {\n const userId = req.user?.uid;\n\n if (!userId) {\n res.status(401).json({ error: 'Authentication required' });\n return;\n }\n\n // Create user context\n req.userContext = createUserContext(userId, {\n orgId: req.user?.orgId,\n roles: req.user?.roles ?? ['user'],\n });\n\n // Assign session ownership when creating new sessions\n const originalJson = res.json.bind(res);\n res.json = (body: unknown) => {\n if (body && typeof body === 'object' && 'threadId' in body) {\n const multiUser = getMultiUserManager();\n multiUser.assignSessionOwnership(\n (body as { threadId: string }).threadId,\n userId,\n );\n }\n return originalJson(body);\n };\n\n next();\n}\n\n/**\n * Verify Firebase Auth token from Authorization header\n */\nexport async function verifyFirebaseAuth(\n req: Request,\n res: Response,\n next: NextFunction,\n): Promise<void> {\n const authHeader = req.headers.authorization;\n\n if (!authHeader?.startsWith('Bearer ')) {\n res.status(401).json({ error: 'No token provided' });\n return;\n }\n\n const token = authHeader.split('Bearer ')[1];\n\n try {\n const decodedToken = await getAuth().verifyIdToken(token);\n\n // Get custom claims for roles/org\n const user = await getAuth().getUser(decodedToken.uid);\n\n req.user = {\n uid: decodedToken.uid,\n email: decodedToken.email,\n roles: (user.customClaims?.roles as string[]) ?? ['user'],\n orgId: user.customClaims?.orgId as string,\n };\n\n next();\n } catch (error) {\n console.error('Token verification failed:', error);\n res.status(401).json({ error: 'Invalid token' });\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/lib/db.ts","../../src/middleware/multi-user.ts"],"names":[],"mappings":"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","file":"multi-user.js","sourcesContent":["/**\n * Database Accessors & Initialization\n *\n * This module provides:\n * - `initializeFirebase()` — convenience function to init Firebase from env vars\n * - `getFirestore()`, `getAuth()` — accessors for Firebase services\n * - `db` — lazy Firestore proxy (no eager initialization)\n *\n * The consuming application MUST call `initializeFirebase()` or\n * `admin.initializeApp()` before using any Firebase-dependent features.\n */\n\nimport admin from 'firebase-admin';\n\n/**\n * Initialize Firebase Admin SDK from environment variables.\n *\n * Reads: FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY,\n * FIREBASE_SERVICE_ACCOUNT_PATH, FIRESTORE_EMULATOR_HOST\n *\n * Safe to call multiple times — returns existing app if already initialized.\n */\nexport function initializeFirebase(): admin.app.App {\n // Already initialized — return existing app\n if (admin.apps.length > 0) {\n return admin.app();\n }\n\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;\n\n // Emulator mode — no credentials needed\n if (emulatorHost) {\n const app = admin.initializeApp({\n projectId: projectId || 'demo-project',\n });\n console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);\n return app;\n }\n\n // Service account file\n const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;\n if (serviceAccountPath) {\n // Dynamic require for JSON service account file at runtime\n const serviceAccount = require(serviceAccountPath) as Record<string, unknown>;\n return admin.initializeApp({\n credential: admin.credential.cert(serviceAccount),\n projectId,\n });\n }\n\n // Inline credentials\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY;\n if (projectId && clientEmail && privateKey) {\n return admin.initializeApp({\n credential: admin.credential.cert({\n projectId,\n clientEmail,\n privateKey: privateKey.replace(/\\\\n/g, '\\n'),\n }),\n projectId,\n });\n }\n\n // Application default credentials (Cloud Run, etc.)\n if (projectId) {\n return admin.initializeApp({\n credential: admin.credential.applicationDefault(),\n projectId,\n });\n }\n\n throw new Error(\n '@almadar/server: Cannot initialize Firebase — no credentials found. ' +\n 'Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, ' +\n 'or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST.'\n );\n}\n\n/**\n * Get the initialized Firebase app.\n * Throws if Firebase Admin SDK has not been initialized.\n */\nfunction getApp(): admin.app.App {\n if (admin.apps.length === 0) {\n throw new Error(\n '@almadar/server: Firebase Admin SDK is not initialized. ' +\n 'Call initializeFirebase() or admin.initializeApp() before using @almadar/server.'\n );\n }\n return admin.app();\n}\n\n/**\n * Get Firestore instance from the pre-initialized Firebase app.\n */\nexport function getFirestore(): admin.firestore.Firestore {\n return getApp().firestore();\n}\n\n/**\n * Get Firebase Auth instance from the pre-initialized Firebase app.\n */\nexport function getAuth(): admin.auth.Auth {\n return getApp().auth();\n}\n\n// Re-export admin for convenience\nexport { admin };\n\n/**\n * Lazy Firestore proxy — resolves on first property access, not at import time.\n * This prevents the \"Firebase not initialized\" error during module loading.\n */\nexport const db = new Proxy({} as admin.firestore.Firestore, {\n get(_target, prop, receiver) {\n const firestore = getFirestore();\n const value = Reflect.get(firestore, prop, receiver);\n return typeof value === 'function' ? value.bind(firestore) : value;\n },\n});\n","/**\n * Multi-User Middleware\n *\n * Provides user isolation and session ownership using Firebase Auth.\n *\n * @packageDocumentation\n */\n\nimport { getMultiUserManager, createUserContext } from '@almadar-io/agent';\nimport { getAuth } from '../lib/db.js';\nimport type { Request, Response, NextFunction } from 'express';\n\n// Extend Express Request to include Firebase user\ndeclare global {\n namespace Express {\n interface Request {\n user?: {\n uid: string;\n email?: string;\n roles?: string[];\n orgId?: string;\n };\n userContext?: {\n userId: string;\n orgId?: string;\n roles?: string[];\n };\n }\n }\n}\n\n/**\n * Middleware to set up user context from Firebase Auth\n */\nexport async function multiUserMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n): Promise<void> {\n const userId = req.user?.uid;\n\n if (!userId) {\n res.status(401).json({ error: 'Authentication required' });\n return;\n }\n\n // Create user context\n req.userContext = createUserContext(userId, {\n orgId: req.user?.orgId,\n roles: req.user?.roles ?? ['user'],\n });\n\n // Assign session ownership when creating new sessions\n const originalJson = res.json.bind(res);\n res.json = (body: unknown) => {\n if (body && typeof body === 'object' && 'threadId' in body) {\n const multiUser = getMultiUserManager();\n multiUser.assignSessionOwnership(\n (body as { threadId: string }).threadId,\n userId,\n );\n }\n return originalJson(body);\n };\n\n next();\n}\n\n/**\n * Verify Firebase Auth token from Authorization header\n */\nexport async function verifyFirebaseAuth(\n req: Request,\n res: Response,\n next: NextFunction,\n): Promise<void> {\n const authHeader = req.headers.authorization;\n\n if (!authHeader?.startsWith('Bearer ')) {\n res.status(401).json({ error: 'No token provided' });\n return;\n }\n\n const token = authHeader.split('Bearer ')[1];\n\n try {\n const decodedToken = await getAuth().verifyIdToken(token);\n\n // Get custom claims for roles/org\n const user = await getAuth().getUser(decodedToken.uid);\n\n req.user = {\n uid: decodedToken.uid,\n email: decodedToken.email,\n roles: (user.customClaims?.roles as string[]) ?? ['user'],\n orgId: user.customClaims?.orgId as string,\n };\n\n next();\n } catch (error) {\n console.error('Token verification failed:', error);\n res.status(401).json({ error: 'Invalid token' });\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { getObservabilityCollector } from '@almadar/agent';
2
+ import { getObservabilityCollector } from '@almadar-io/agent';
3
3
 
4
4
  // src/routes/observability.ts
5
5
  var router = Router();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/observability.ts"],"names":[],"mappings":";;;;AAWA,IAAM,SAAoC,MAAA,EAAO;AAKjD,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAO,GAAA,EAAK,GAAA,KAAQ;AACzC,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,QAAA,GAAW,UAAU,sBAAA,EAAuB;AAClD,IAAA,GAAA,CAAI,KAAK,QAAQ,CAAA;AAAA,EACnB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,kBAAkB,KAAK,CAAA;AACrC,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,yBAAyB,CAAA;AAAA,EACzD;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,OAAO,GAAA,EAAK,GAAA,KAAQ;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,WAAA,EAAY;AAC3C,IAAA,MAAM,aAAa,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,SAAS,CAAA;AAE7D,IAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,GAAA,GAAM,GAAG,EAAE,IAAA,CAAK;AAAA,MACtC,MAAA,EAAQ,aAAa,SAAA,GAAY,UAAA;AAAA,MACjC,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,uBAAuB,KAAK,CAAA;AAC1C,IAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,MACnB,MAAA,EAAQ,WAAA;AAAA,MACR,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,+BAAA,EAAiC,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC9D,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,mBAAA,CAAoB,GAAA,CAAI,OAAO,QAAQ,CAAA;AAEnE,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,qBAAqB,CAAA;AACnD,MAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,KAAK,SAAS,CAAA;AAAA,EACpB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,oBAAoB,KAAK,CAAA;AACvC,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,2BAA2B,CAAA;AAAA,EAC3D;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,kBAAA,EAAoB,OAAO,GAAA,EAAK,GAAA,KAAQ;AACjD,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,QAAA,GAAW,UAAU,iBAAA,EAAkB;AAC7C,IAAA,GAAA,CAAI,KAAK,QAAQ,CAAA;AAAA,EACnB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,0BAA0B,KAAK,CAAA;AAC7C,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,iCAAiC,CAAA;AAAA,EACjE;AACF,CAAC,CAAA;AAED,IAAO,qBAAA,GAAQ","file":"observability.js","sourcesContent":["/**\n * Observability Routes\n *\n * Provides endpoints for metrics, health checks, and telemetry.\n *\n * @packageDocumentation\n */\n\nimport { Router } from 'express';\nimport { getObservabilityCollector } from '@almadar/agent';\n\nconst router: ReturnType<typeof Router> = Router();\n\n/**\n * GET /metrics - Get performance snapshot\n */\nrouter.get('/metrics', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const snapshot = collector.getPerformanceSnapshot();\n res.json(snapshot);\n } catch (error) {\n console.error('Metrics error:', error);\n res.status(500).json({ error: 'Failed to get metrics' });\n }\n});\n\n/**\n * GET /health - Get health check\n */\nrouter.get('/health', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const health = await collector.healthCheck();\n const allHealthy = health.every((h) => h.status === 'healthy');\n\n res.status(allHealthy ? 200 : 503).json({\n status: allHealthy ? 'healthy' : 'degraded',\n timestamp: Date.now(),\n checks: health,\n });\n } catch (error) {\n console.error('Health check error:', error);\n res.status(500).json({\n status: 'unhealthy',\n error: 'Health check failed',\n });\n }\n});\n\n/**\n * GET /sessions/:threadId/telemetry - Get session telemetry\n */\nrouter.get('/sessions/:threadId/telemetry', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const telemetry = collector.getSessionTelemetry(req.params.threadId);\n\n if (!telemetry) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n\n res.json(telemetry);\n } catch (error) {\n console.error('Telemetry error:', error);\n res.status(500).json({ error: 'Failed to get telemetry' });\n }\n});\n\n/**\n * GET /active-sessions - Get active sessions\n */\nrouter.get('/active-sessions', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const sessions = collector.getActiveSessions();\n res.json(sessions);\n } catch (error) {\n console.error('Active sessions error:', error);\n res.status(500).json({ error: 'Failed to get active sessions' });\n }\n});\n\nexport default router;\n"]}
1
+ {"version":3,"sources":["../../src/routes/observability.ts"],"names":[],"mappings":";;;;AAWA,IAAM,SAAoC,MAAA,EAAO;AAKjD,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAO,GAAA,EAAK,GAAA,KAAQ;AACzC,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,QAAA,GAAW,UAAU,sBAAA,EAAuB;AAClD,IAAA,GAAA,CAAI,KAAK,QAAQ,CAAA;AAAA,EACnB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,kBAAkB,KAAK,CAAA;AACrC,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,yBAAyB,CAAA;AAAA,EACzD;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,OAAO,GAAA,EAAK,GAAA,KAAQ;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,WAAA,EAAY;AAC3C,IAAA,MAAM,aAAa,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,SAAS,CAAA;AAE7D,IAAA,GAAA,CAAI,MAAA,CAAO,UAAA,GAAa,GAAA,GAAM,GAAG,EAAE,IAAA,CAAK;AAAA,MACtC,MAAA,EAAQ,aAAa,SAAA,GAAY,UAAA;AAAA,MACjC,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,uBAAuB,KAAK,CAAA;AAC1C,IAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK;AAAA,MACnB,MAAA,EAAQ,WAAA;AAAA,MACR,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,+BAAA,EAAiC,OAAO,GAAA,EAAK,GAAA,KAAQ;AAC9D,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,mBAAA,CAAoB,GAAA,CAAI,OAAO,QAAQ,CAAA;AAEnE,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,qBAAqB,CAAA;AACnD,MAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,KAAK,SAAS,CAAA;AAAA,EACpB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,oBAAoB,KAAK,CAAA;AACvC,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,2BAA2B,CAAA;AAAA,EAC3D;AACF,CAAC,CAAA;AAKD,MAAA,CAAO,GAAA,CAAI,kBAAA,EAAoB,OAAO,GAAA,EAAK,GAAA,KAAQ;AACjD,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,yBAAA,EAA0B;AAC5C,IAAA,MAAM,QAAA,GAAW,UAAU,iBAAA,EAAkB;AAC7C,IAAA,GAAA,CAAI,KAAK,QAAQ,CAAA;AAAA,EACnB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,0BAA0B,KAAK,CAAA;AAC7C,IAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,iCAAiC,CAAA;AAAA,EACjE;AACF,CAAC,CAAA;AAED,IAAO,qBAAA,GAAQ","file":"observability.js","sourcesContent":["/**\n * Observability Routes\n *\n * Provides endpoints for metrics, health checks, and telemetry.\n *\n * @packageDocumentation\n */\n\nimport { Router } from 'express';\nimport { getObservabilityCollector } from '@almadar-io/agent';\n\nconst router: ReturnType<typeof Router> = Router();\n\n/**\n * GET /metrics - Get performance snapshot\n */\nrouter.get('/metrics', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const snapshot = collector.getPerformanceSnapshot();\n res.json(snapshot);\n } catch (error) {\n console.error('Metrics error:', error);\n res.status(500).json({ error: 'Failed to get metrics' });\n }\n});\n\n/**\n * GET /health - Get health check\n */\nrouter.get('/health', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const health = await collector.healthCheck();\n const allHealthy = health.every((h) => h.status === 'healthy');\n\n res.status(allHealthy ? 200 : 503).json({\n status: allHealthy ? 'healthy' : 'degraded',\n timestamp: Date.now(),\n checks: health,\n });\n } catch (error) {\n console.error('Health check error:', error);\n res.status(500).json({\n status: 'unhealthy',\n error: 'Health check failed',\n });\n }\n});\n\n/**\n * GET /sessions/:threadId/telemetry - Get session telemetry\n */\nrouter.get('/sessions/:threadId/telemetry', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const telemetry = collector.getSessionTelemetry(req.params.threadId);\n\n if (!telemetry) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n\n res.json(telemetry);\n } catch (error) {\n console.error('Telemetry error:', error);\n res.status(500).json({ error: 'Failed to get telemetry' });\n }\n});\n\n/**\n * GET /active-sessions - Get active sessions\n */\nrouter.get('/active-sessions', async (req, res) => {\n try {\n const collector = getObservabilityCollector();\n const sessions = collector.getActiveSessions();\n res.json(sessions);\n } catch (error) {\n console.error('Active sessions error:', error);\n res.status(500).json({ error: 'Failed to get active sessions' });\n }\n});\n\nexport default router;\n"]}
@@ -1,4 +1,4 @@
1
- import { getStateSyncManager, getMultiUserManager } from '@almadar/agent';
1
+ import { getStateSyncManager, getMultiUserManager } from '@almadar-io/agent';
2
2
  import admin from 'firebase-admin';
3
3
 
4
4
  // src/websocket/state-sync.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/db.ts","../../src/websocket/state-sync.ts"],"names":[],"mappings":";;;;AAoFA,SAAS,MAAA,GAAwB;AAC/B,EAAA,IAAI,KAAA,CAAM,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,MAAM,GAAA,EAAI;AACnB;AAKO,SAAS,YAAA,GAA0C;AACxD,EAAA,OAAO,MAAA,GAAS,SAAA,EAAU;AAC5B;AAKO,SAAS,OAAA,GAA2B;AACzC,EAAA,OAAO,MAAA,GAAS,IAAA,EAAK;AACvB;AASkB,IAAI,KAAA,CAAM,EAAC,EAAgC;AAAA,EAC3D,GAAA,CAAI,OAAA,EAAS,IAAA,EAAM,QAAA,EAAU;AAC3B,IAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,SAAA,EAAW,MAAM,QAAQ,CAAA;AACnD,IAAA,OAAO,OAAO,KAAA,KAAU,UAAA,GAAa,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA,GAAI,KAAA;AAAA,EAC/D;AACF,CAAC;;;AC1FM,SAAS,wBAAwB,EAAA,EAAwB;AAC9D,EAAA,MAAM,YAAY,mBAAA,EAAoB;AAGtC,EAAA,EAAA,CAAG,GAAA,CAAI,OAAO,MAAA,EAAQ,IAAA,KAAS;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,SAAA,CAAU,IAAA,CAAK,KAAA;AACpC,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,OAAO,IAAA,CAAK,IAAI,KAAA,CAAM,yBAAyB,CAAC,CAAA;AAAA,MAClD;AAEA,MAAA,MAAM,YAAA,GAAe,MAAM,OAAA,EAAQ,CAAE,cAAc,KAAK,CAAA;AACxD,MAAA,MAAM,OAAO,MAAM,OAAA,EAAQ,CAAE,OAAA,CAAQ,aAAa,GAAG,CAAA;AAErD,MAAA,MAAA,CAAO,KAAK,IAAA,GAAO;AAAA,QACjB,KAAK,YAAA,CAAa,GAAA;AAAA,QAClB,KAAA,EAAQ,IAAA,CAAK,YAAA,EAAc,KAAA,IAAsB,CAAC,MAAM,CAAA;AAAA,QACxD,KAAA,EAAO,KAAK,YAAA,EAAc;AAAA,OAC5B;AAEA,MAAA,IAAA,EAAK;AAAA,IACP,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,uBAAuB,KAAK,CAAA;AAC1C,MAAA,IAAA,CAAK,IAAI,KAAA,CAAM,eAAe,CAAC,CAAA;AAAA,IACjC;AAAA,EACF,CAAC,CAAA;AAED,EAAA,EAAA,CAAG,EAAA,CAAG,YAAA,EAAc,CAAC,MAAA,KAAmB;AACtC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,GAAA;AAChC,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,SAAA,CAAU,IAAA,CAAK,QAAA;AAEvC,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,mBAAA,EAAsB,QAAQ,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAE,CAAA;AAGzE,IAAA,SAAA,CAAU,YAAA,CAAa,EAAE,QAAA,EAAU,CAAA;AAGnC,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAE,CAAA;AAG5B,IAAA,MAAA,CAAO,EAAA,CAAG,aAAA,EAAe,CAAA,GAAI,IAAA,KAAoB;AAC/C,MAAA,MAAM,KAAA,GAAQ,KAAK,CAAC,CAAA;AAGpB,MAAA,MAAM,YAAY,mBAAA,EAAoB;AACtC,MAAA,IAAI,CAAC,SAAA,CAAU,cAAA,CAAe,KAAA,CAAM,QAAA,EAAU,MAAM,CAAA,EAAG;AACrD,QAAA,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,EAAE,OAAA,EAAS,qBAAqB,CAAA;AACrD,QAAA;AAAA,MACF;AAGA,MAAA,SAAA,CAAU,oBAAoB,KAA6D,CAAA;AAG3F,MAAA,MAAA,CAAO,GAAG,CAAA,KAAA,EAAQ,MAAM,EAAE,CAAA,CAAE,IAAA,CAAK,gBAAgB,KAAK,CAAA;AAAA,IACxD,CAAC,CAAA;AAGD,IAAA,SAAA,CAAU,EAAA,CAAG,cAAA,EAAgB,CAAC,OAAA,KAAuB;AACnD,MAAA,MAAA,CAAO,IAAA,CAAK,aAAa,OAAO,CAAA;AAAA,IAClC,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,cAAc,MAAM;AAC5B,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,mBAAA,EAAsB,QAAQ,CAAA,aAAA,CAAe,CAAA;AACzD,MAAA,MAAA,CAAO,KAAA,CAAM,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAE,CAAA;AAAA,IAC/B,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH","file":"state-sync.js","sourcesContent":["/**\n * Database Accessors & Initialization\n *\n * This module provides:\n * - `initializeFirebase()` — convenience function to init Firebase from env vars\n * - `getFirestore()`, `getAuth()` — accessors for Firebase services\n * - `db` — lazy Firestore proxy (no eager initialization)\n *\n * The consuming application MUST call `initializeFirebase()` or\n * `admin.initializeApp()` before using any Firebase-dependent features.\n */\n\nimport admin from 'firebase-admin';\n\n/**\n * Initialize Firebase Admin SDK from environment variables.\n *\n * Reads: FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY,\n * FIREBASE_SERVICE_ACCOUNT_PATH, FIRESTORE_EMULATOR_HOST\n *\n * Safe to call multiple times — returns existing app if already initialized.\n */\nexport function initializeFirebase(): admin.app.App {\n // Already initialized — return existing app\n if (admin.apps.length > 0) {\n return admin.app();\n }\n\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;\n\n // Emulator mode — no credentials needed\n if (emulatorHost) {\n const app = admin.initializeApp({\n projectId: projectId || 'demo-project',\n });\n console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);\n return app;\n }\n\n // Service account file\n const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;\n if (serviceAccountPath) {\n // Dynamic require for JSON service account file at runtime\n const serviceAccount = require(serviceAccountPath) as Record<string, unknown>;\n return admin.initializeApp({\n credential: admin.credential.cert(serviceAccount),\n projectId,\n });\n }\n\n // Inline credentials\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY;\n if (projectId && clientEmail && privateKey) {\n return admin.initializeApp({\n credential: admin.credential.cert({\n projectId,\n clientEmail,\n privateKey: privateKey.replace(/\\\\n/g, '\\n'),\n }),\n projectId,\n });\n }\n\n // Application default credentials (Cloud Run, etc.)\n if (projectId) {\n return admin.initializeApp({\n credential: admin.credential.applicationDefault(),\n projectId,\n });\n }\n\n throw new Error(\n '@almadar/server: Cannot initialize Firebase — no credentials found. ' +\n 'Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, ' +\n 'or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST.'\n );\n}\n\n/**\n * Get the initialized Firebase app.\n * Throws if Firebase Admin SDK has not been initialized.\n */\nfunction getApp(): admin.app.App {\n if (admin.apps.length === 0) {\n throw new Error(\n '@almadar/server: Firebase Admin SDK is not initialized. ' +\n 'Call initializeFirebase() or admin.initializeApp() before using @almadar/server.'\n );\n }\n return admin.app();\n}\n\n/**\n * Get Firestore instance from the pre-initialized Firebase app.\n */\nexport function getFirestore(): admin.firestore.Firestore {\n return getApp().firestore();\n}\n\n/**\n * Get Firebase Auth instance from the pre-initialized Firebase app.\n */\nexport function getAuth(): admin.auth.Auth {\n return getApp().auth();\n}\n\n// Re-export admin for convenience\nexport { admin };\n\n/**\n * Lazy Firestore proxy — resolves on first property access, not at import time.\n * This prevents the \"Firebase not initialized\" error during module loading.\n */\nexport const db = new Proxy({} as admin.firestore.Firestore, {\n get(_target, prop, receiver) {\n const firestore = getFirestore();\n const value = Reflect.get(firestore, prop, receiver);\n return typeof value === 'function' ? value.bind(firestore) : value;\n },\n});\n","/**\n * State Sync WebSocket Handler\n *\n * Provides real-time state synchronization using Socket.IO.\n *\n * @packageDocumentation\n */\n\nimport { getStateSyncManager } from '@almadar/agent';\nimport { getMultiUserManager } from '@almadar/agent';\nimport { getAuth } from '../lib/db.js';\n\n// Type definitions for Socket.IO (to avoid dependency)\ninterface Socket {\n data: { user: { uid: string; roles: string[]; orgId?: string } };\n handshake: { auth: { token: string; clientId: string } };\n join: (room: string) => void;\n leave: (room: string) => void;\n on: (event: string, handler: (...args: unknown[]) => void) => void;\n emit: (event: string, ...args: unknown[]) => void;\n to: (room: string) => { emit: (event: string, ...args: unknown[]) => void };\n}\n\ninterface SocketServer {\n use: (middleware: (socket: Socket, next: (err?: Error) => void) => void) => void;\n on: (event: string, handler: (socket: Socket) => void) => void;\n}\n\n/**\n * Set up state sync WebSocket with Firebase Auth\n */\nexport function setupStateSyncWebSocket(io: SocketServer): void {\n const stateSync = getStateSyncManager();\n\n // Firebase Auth middleware for Socket.IO\n io.use(async (socket, next) => {\n try {\n const token = socket.handshake.auth.token as string;\n if (!token) {\n return next(new Error('Authentication required'));\n }\n\n const decodedToken = await getAuth().verifyIdToken(token);\n const user = await getAuth().getUser(decodedToken.uid);\n\n socket.data.user = {\n uid: decodedToken.uid,\n roles: (user.customClaims?.roles as string[]) ?? ['user'],\n orgId: user.customClaims?.orgId as string,\n };\n\n next();\n } catch (error) {\n console.error('Socket auth failed:', error);\n next(new Error('Invalid token'));\n }\n });\n\n io.on('connection', (socket: Socket) => {\n const userId = socket.data.user.uid;\n const clientId = socket.handshake.auth.clientId;\n\n console.log(`[StateSync] Client ${clientId} connected for user ${userId}`);\n\n // Update client ID in sync manager\n stateSync.updateConfig({ clientId });\n\n // Join user's room for targeted updates\n socket.join(`user:${userId}`);\n\n // Listen for state changes from client\n socket.on('stateChange', (...args: unknown[]) => {\n const event = args[0] as { threadId: string };\n \n // Verify ownership\n const multiUser = getMultiUserManager();\n if (!multiUser.isSessionOwner(event.threadId, userId)) {\n socket.emit('error', { message: 'Not session owner' });\n return;\n }\n\n // Process through sync manager\n stateSync.receiveRemoteChange(event as unknown as import('@almadar/agent').StateChangeEvent);\n\n // Broadcast to other clients of same user\n socket.to(`user:${userId}`).emit('remoteChange', event);\n });\n\n // Handle sync required events from agent\n stateSync.on('syncRequired', (changes: unknown[]) => {\n socket.emit('syncBatch', changes);\n });\n\n socket.on('disconnect', () => {\n console.log(`[StateSync] Client ${clientId} disconnected`);\n socket.leave(`user:${userId}`);\n });\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/lib/db.ts","../../src/websocket/state-sync.ts"],"names":[],"mappings":"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","file":"state-sync.js","sourcesContent":["/**\n * Database Accessors & Initialization\n *\n * This module provides:\n * - `initializeFirebase()` — convenience function to init Firebase from env vars\n * - `getFirestore()`, `getAuth()` — accessors for Firebase services\n * - `db` — lazy Firestore proxy (no eager initialization)\n *\n * The consuming application MUST call `initializeFirebase()` or\n * `admin.initializeApp()` before using any Firebase-dependent features.\n */\n\nimport admin from 'firebase-admin';\n\n/**\n * Initialize Firebase Admin SDK from environment variables.\n *\n * Reads: FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY,\n * FIREBASE_SERVICE_ACCOUNT_PATH, FIRESTORE_EMULATOR_HOST\n *\n * Safe to call multiple times — returns existing app if already initialized.\n */\nexport function initializeFirebase(): admin.app.App {\n // Already initialized — return existing app\n if (admin.apps.length > 0) {\n return admin.app();\n }\n\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST;\n\n // Emulator mode — no credentials needed\n if (emulatorHost) {\n const app = admin.initializeApp({\n projectId: projectId || 'demo-project',\n });\n console.log(`Firebase Admin initialized for emulator: ${emulatorHost}`);\n return app;\n }\n\n // Service account file\n const serviceAccountPath = process.env.FIREBASE_SERVICE_ACCOUNT_PATH;\n if (serviceAccountPath) {\n // Dynamic require for JSON service account file at runtime\n const serviceAccount = require(serviceAccountPath) as Record<string, unknown>;\n return admin.initializeApp({\n credential: admin.credential.cert(serviceAccount),\n projectId,\n });\n }\n\n // Inline credentials\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY;\n if (projectId && clientEmail && privateKey) {\n return admin.initializeApp({\n credential: admin.credential.cert({\n projectId,\n clientEmail,\n privateKey: privateKey.replace(/\\\\n/g, '\\n'),\n }),\n projectId,\n });\n }\n\n // Application default credentials (Cloud Run, etc.)\n if (projectId) {\n return admin.initializeApp({\n credential: admin.credential.applicationDefault(),\n projectId,\n });\n }\n\n throw new Error(\n '@almadar/server: Cannot initialize Firebase — no credentials found. ' +\n 'Set FIREBASE_PROJECT_ID + FIREBASE_CLIENT_EMAIL + FIREBASE_PRIVATE_KEY, ' +\n 'or FIREBASE_SERVICE_ACCOUNT_PATH, or FIRESTORE_EMULATOR_HOST.'\n );\n}\n\n/**\n * Get the initialized Firebase app.\n * Throws if Firebase Admin SDK has not been initialized.\n */\nfunction getApp(): admin.app.App {\n if (admin.apps.length === 0) {\n throw new Error(\n '@almadar/server: Firebase Admin SDK is not initialized. ' +\n 'Call initializeFirebase() or admin.initializeApp() before using @almadar/server.'\n );\n }\n return admin.app();\n}\n\n/**\n * Get Firestore instance from the pre-initialized Firebase app.\n */\nexport function getFirestore(): admin.firestore.Firestore {\n return getApp().firestore();\n}\n\n/**\n * Get Firebase Auth instance from the pre-initialized Firebase app.\n */\nexport function getAuth(): admin.auth.Auth {\n return getApp().auth();\n}\n\n// Re-export admin for convenience\nexport { admin };\n\n/**\n * Lazy Firestore proxy — resolves on first property access, not at import time.\n * This prevents the \"Firebase not initialized\" error during module loading.\n */\nexport const db = new Proxy({} as admin.firestore.Firestore, {\n get(_target, prop, receiver) {\n const firestore = getFirestore();\n const value = Reflect.get(firestore, prop, receiver);\n return typeof value === 'function' ? value.bind(firestore) : value;\n },\n});\n","/**\n * State Sync WebSocket Handler\n *\n * Provides real-time state synchronization using Socket.IO.\n *\n * @packageDocumentation\n */\n\nimport { getStateSyncManager } from '@almadar-io/agent';\nimport { getMultiUserManager } from '@almadar-io/agent';\nimport { getAuth } from '../lib/db.js';\n\n// Type definitions for Socket.IO (to avoid dependency)\ninterface Socket {\n data: { user: { uid: string; roles: string[]; orgId?: string } };\n handshake: { auth: { token: string; clientId: string } };\n join: (room: string) => void;\n leave: (room: string) => void;\n on: (event: string, handler: (...args: unknown[]) => void) => void;\n emit: (event: string, ...args: unknown[]) => void;\n to: (room: string) => { emit: (event: string, ...args: unknown[]) => void };\n}\n\ninterface SocketServer {\n use: (middleware: (socket: Socket, next: (err?: Error) => void) => void) => void;\n on: (event: string, handler: (socket: Socket) => void) => void;\n}\n\n/**\n * Set up state sync WebSocket with Firebase Auth\n */\nexport function setupStateSyncWebSocket(io: SocketServer): void {\n const stateSync = getStateSyncManager();\n\n // Firebase Auth middleware for Socket.IO\n io.use(async (socket, next) => {\n try {\n const token = socket.handshake.auth.token as string;\n if (!token) {\n return next(new Error('Authentication required'));\n }\n\n const decodedToken = await getAuth().verifyIdToken(token);\n const user = await getAuth().getUser(decodedToken.uid);\n\n socket.data.user = {\n uid: decodedToken.uid,\n roles: (user.customClaims?.roles as string[]) ?? ['user'],\n orgId: user.customClaims?.orgId as string,\n };\n\n next();\n } catch (error) {\n console.error('Socket auth failed:', error);\n next(new Error('Invalid token'));\n }\n });\n\n io.on('connection', (socket: Socket) => {\n const userId = socket.data.user.uid;\n const clientId = socket.handshake.auth.clientId;\n\n console.log(`[StateSync] Client ${clientId} connected for user ${userId}`);\n\n // Update client ID in sync manager\n stateSync.updateConfig({ clientId });\n\n // Join user's room for targeted updates\n socket.join(`user:${userId}`);\n\n // Listen for state changes from client\n socket.on('stateChange', (...args: unknown[]) => {\n const event = args[0] as { threadId: string };\n \n // Verify ownership\n const multiUser = getMultiUserManager();\n if (!multiUser.isSessionOwner(event.threadId, userId)) {\n socket.emit('error', { message: 'Not session owner' });\n return;\n }\n\n // Process through sync manager\n stateSync.receiveRemoteChange(event as unknown as import('@almadar-io/agent').StateChangeEvent);\n\n // Broadcast to other clients of same user\n socket.to(`user:${userId}`).emit('remoteChange', event);\n });\n\n // Handle sync required events from agent\n stateSync.on('syncRequired', (changes: unknown[]) => {\n socket.emit('syncBatch', changes);\n });\n\n socket.on('disconnect', () => {\n console.log(`[StateSync] Client ${clientId} disconnected`);\n socket.leave(`user:${userId}`);\n });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/server",
3
- "version": "2.0.9",
3
+ "version": "2.1.0",
4
4
  "description": "Shared server infrastructure for Almadar applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,10 +36,10 @@
36
36
  "dist"
37
37
  ],
38
38
  "publishConfig": {
39
+ "registry": "https://registry.npmjs.org",
39
40
  "access": "public"
40
41
  },
41
42
  "dependencies": {
42
- "@almadar/agent": ">=2.0.1",
43
43
  "@almadar/core": ">=2.1.0",
44
44
  "@faker-js/faker": "^9.3.0",
45
45
  "cors": "^2.8.5",
@@ -50,7 +50,13 @@
50
50
  "zod": "^3.24.0"
51
51
  },
52
52
  "peerDependencies": {
53
- "express": "^4.0.0"
53
+ "express": "^4.0.0",
54
+ "@almadar-io/agent": ">=2.0.1"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "@almadar-io/agent": {
58
+ "optional": true
59
+ }
54
60
  },
55
61
  "devDependencies": {
56
62
  "@almadar/eslint-plugin": ">=2.3.0",
@@ -70,7 +76,7 @@
70
76
  },
71
77
  "repository": {
72
78
  "type": "git",
73
- "url": "https://github.com/almadar-io/almadar.git",
79
+ "url": "https://github.com/almadar-io/almadar-server.git",
74
80
  "directory": "docs/packages/server"
75
81
  },
76
82
  "license": "MIT",
package/dist/index.d.ts DELETED
@@ -1,42 +0,0 @@
1
- /**
2
- * @almadar/server - Shared server infrastructure for Almadar applications
3
- *
4
- * This package provides:
5
- * - Database utilities (Firebase/Firestore)
6
- * - Event bus for cross-trait communication
7
- * - Express middleware (auth, error handling, validation)
8
- * - Data services (mock and production)
9
- * - Query filter utilities
10
- *
11
- * @packageDocumentation
12
- */
13
- export { env } from './lib/env.js';
14
- export { logger } from './lib/logger.js';
15
- export { EventBus, getServerEventBus, resetServerEventBus, emitEntityEvent, type EventLogEntry } from './lib/eventBus.js';
16
- export { DistributedEventBus, InMemoryTransport, RedisTransport, type IEventBusTransport, type TransportMessage, type TransportReceiver, type RedisTransportOptions, } from './lib/eventBusTransport.js';
17
- export { EventPersistence, InMemoryEventStore, type PersistedEvent, type EventQuery, type EventPersistenceOptions, type IEventStore, } from './lib/eventPersistence.js';
18
- export { debugEventsRouter } from './lib/debugRouter.js';
19
- export { initializeFirebase, getFirestore, getAuth, admin, db } from './lib/db.js';
20
- export { setupEventBroadcast, getWebSocketServer, closeWebSocketServer, getConnectedClientCount, } from './lib/websocket.js';
21
- export { errorHandler, notFoundHandler, asyncHandler, AppError, NotFoundError, ValidationError, UnauthorizedError, ForbiddenError, ConflictError, } from './middleware/errorHandler.js';
22
- export { validateBody, validateQuery, validateParams } from './middleware/validation.js';
23
- export { authenticateFirebase } from './middleware/authenticateFirebase.js';
24
- export { MockDataService, getMockDataService, resetMockDataService, type FieldSchema, type EntitySchema, } from './services/MockDataService.js';
25
- export { getDataService, resetDataService, seedMockData, type DataService, type EntitySeedConfig, type PaginationOptions, type PaginatedResult, } from './services/DataService.js';
26
- /** @deprecated Use getDataService() instead */
27
- export declare const dataService: import("./index.js").DataService;
28
- /** @deprecated Use getMockDataService() instead */
29
- export declare const mockDataService: import("./index.js").MockDataService;
30
- /** @deprecated Use getServerEventBus() instead */
31
- export declare const serverEventBus: import("./index.js").EventBus;
32
- export { toFirestoreFormat, fromFirestoreFormat, SchemaStore, SnapshotStore, ChangeSetStore, ValidationStore, SchemaProtectionService, } from './stores/index.js';
33
- export { parseQueryFilters, applyFiltersToQuery, extractPaginationParams, type ParsedFilter, type FirestoreWhereFilterOp, type PaginationParams, } from './utils/queryFilters.js';
34
- export { getMemoryManager, resetMemoryManager, } from './deepagent/memory.js';
35
- export { getSessionManager, resetSessionManager, } from './deepagent/session.js';
36
- export { createServerSkillAgent, getMemoryManager as getAgentMemoryManager, getSessionManager as getAgentSessionManager, } from './deepagent/skill-agent.js';
37
- export { multiUserMiddleware, verifyFirebaseAuth, } from './middleware/multi-user.js';
38
- export { setupStateSyncWebSocket } from './websocket/state-sync.js';
39
- export { ServiceDiscovery, InMemoryServiceRegistry, type ServiceRegistration, type ServiceRegistryOptions, type IServiceRegistry, } from './lib/serviceDiscovery.js';
40
- export type { DataServiceActions, DataServiceContract, EventBusActions, EventBusServiceContract, ServiceDiscoveryActions, ServiceDiscoveryContract, ServerServiceContracts, } from './contracts.js';
41
- export { default as observabilityRouter } from './routes/observability.js';
42
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}