jiva-core 0.2.3 → 0.3.2

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.
Files changed (152) hide show
  1. package/.dockerignore +53 -0
  2. package/.gcloudignore +49 -0
  3. package/CONTRIBUTING.md +92 -0
  4. package/Dockerfile +63 -0
  5. package/README.md +250 -88
  6. package/cloud-run-deploy.yaml +135 -0
  7. package/cloud-run.yaml +135 -0
  8. package/cloud-run.yaml.template +143 -0
  9. package/deploy.sh +107 -0
  10. package/dist/core/agent-spawner.d.ts +89 -0
  11. package/dist/core/agent-spawner.d.ts.map +1 -0
  12. package/dist/core/agent-spawner.js +208 -0
  13. package/dist/core/agent-spawner.js.map +1 -0
  14. package/dist/core/agent.js +1 -1
  15. package/dist/core/agent.js.map +1 -1
  16. package/dist/core/client-agent.d.ts +103 -0
  17. package/dist/core/client-agent.d.ts.map +1 -0
  18. package/dist/core/client-agent.js +659 -0
  19. package/dist/core/client-agent.js.map +1 -0
  20. package/dist/core/config.d.ts +59 -10
  21. package/dist/core/config.d.ts.map +1 -1
  22. package/dist/core/config.js +19 -2
  23. package/dist/core/config.js.map +1 -1
  24. package/dist/core/conversation-manager.d.ts +10 -18
  25. package/dist/core/conversation-manager.d.ts.map +1 -1
  26. package/dist/core/conversation-manager.js +31 -63
  27. package/dist/core/conversation-manager.js.map +1 -1
  28. package/dist/core/dual-agent.d.ts +22 -3
  29. package/dist/core/dual-agent.d.ts.map +1 -1
  30. package/dist/core/dual-agent.js +86 -10
  31. package/dist/core/dual-agent.js.map +1 -1
  32. package/dist/core/manager-agent.d.ts +16 -1
  33. package/dist/core/manager-agent.d.ts.map +1 -1
  34. package/dist/core/manager-agent.js +127 -44
  35. package/dist/core/manager-agent.js.map +1 -1
  36. package/dist/core/worker-agent.d.ts +9 -1
  37. package/dist/core/worker-agent.d.ts.map +1 -1
  38. package/dist/core/worker-agent.js +169 -14
  39. package/dist/core/worker-agent.js.map +1 -1
  40. package/dist/core/workspace.d.ts +5 -0
  41. package/dist/core/workspace.d.ts.map +1 -1
  42. package/dist/core/workspace.js +47 -7
  43. package/dist/core/workspace.js.map +1 -1
  44. package/dist/index.d.ts +3 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +4 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/interfaces/cli/index.js +349 -42
  49. package/dist/interfaces/cli/index.js.map +1 -1
  50. package/dist/interfaces/http/index.d.ts +22 -0
  51. package/dist/interfaces/http/index.d.ts.map +1 -0
  52. package/dist/interfaces/http/index.js +135 -0
  53. package/dist/interfaces/http/index.js.map +1 -0
  54. package/dist/interfaces/http/middleware/auth.d.ts +32 -0
  55. package/dist/interfaces/http/middleware/auth.d.ts.map +1 -0
  56. package/dist/interfaces/http/middleware/auth.js +176 -0
  57. package/dist/interfaces/http/middleware/auth.js.map +1 -0
  58. package/dist/interfaces/http/routes/chat.d.ts +7 -0
  59. package/dist/interfaces/http/routes/chat.d.ts.map +1 -0
  60. package/dist/interfaces/http/routes/chat.js +144 -0
  61. package/dist/interfaces/http/routes/chat.js.map +1 -0
  62. package/dist/interfaces/http/routes/health.d.ts +6 -0
  63. package/dist/interfaces/http/routes/health.d.ts.map +1 -0
  64. package/dist/interfaces/http/routes/health.js +25 -0
  65. package/dist/interfaces/http/routes/health.js.map +1 -0
  66. package/dist/interfaces/http/routes/session.d.ts +7 -0
  67. package/dist/interfaces/http/routes/session.d.ts.map +1 -0
  68. package/dist/interfaces/http/routes/session.js +114 -0
  69. package/dist/interfaces/http/routes/session.js.map +1 -0
  70. package/dist/interfaces/http/session-manager.d.ts +76 -0
  71. package/dist/interfaces/http/session-manager.d.ts.map +1 -0
  72. package/dist/interfaces/http/session-manager.js +350 -0
  73. package/dist/interfaces/http/session-manager.js.map +1 -0
  74. package/dist/interfaces/http/websocket-handler.d.ts +18 -0
  75. package/dist/interfaces/http/websocket-handler.d.ts.map +1 -0
  76. package/dist/interfaces/http/websocket-handler.js +146 -0
  77. package/dist/interfaces/http/websocket-handler.js.map +1 -0
  78. package/dist/mcp/client.d.ts +11 -2
  79. package/dist/mcp/client.d.ts.map +1 -1
  80. package/dist/mcp/client.js +44 -19
  81. package/dist/mcp/client.js.map +1 -1
  82. package/dist/mcp/server-manager.d.ts +1 -1
  83. package/dist/mcp/server-manager.d.ts.map +1 -1
  84. package/dist/mcp/server-manager.js +12 -2
  85. package/dist/mcp/server-manager.js.map +1 -1
  86. package/dist/models/krutrim.js +1 -1
  87. package/dist/models/krutrim.js.map +1 -1
  88. package/dist/personas/index.d.ts +13 -0
  89. package/dist/personas/index.d.ts.map +1 -0
  90. package/dist/personas/index.js +13 -0
  91. package/dist/personas/index.js.map +1 -0
  92. package/dist/personas/persona-loader.d.ts +30 -0
  93. package/dist/personas/persona-loader.d.ts.map +1 -0
  94. package/dist/personas/persona-loader.js +246 -0
  95. package/dist/personas/persona-loader.js.map +1 -0
  96. package/dist/personas/persona-manager.d.ts +93 -0
  97. package/dist/personas/persona-manager.d.ts.map +1 -0
  98. package/dist/personas/persona-manager.js +268 -0
  99. package/dist/personas/persona-manager.js.map +1 -0
  100. package/dist/personas/skill-loader.d.ts +35 -0
  101. package/dist/personas/skill-loader.d.ts.map +1 -0
  102. package/dist/personas/skill-loader.js +144 -0
  103. package/dist/personas/skill-loader.js.map +1 -0
  104. package/dist/personas/skill-packager.d.ts +25 -0
  105. package/dist/personas/skill-packager.d.ts.map +1 -0
  106. package/dist/personas/skill-packager.js +233 -0
  107. package/dist/personas/skill-packager.js.map +1 -0
  108. package/dist/personas/types.d.ts +134 -0
  109. package/dist/personas/types.d.ts.map +1 -0
  110. package/dist/personas/types.js +7 -0
  111. package/dist/personas/types.js.map +1 -0
  112. package/dist/personas/validator.d.ts +22 -0
  113. package/dist/personas/validator.d.ts.map +1 -0
  114. package/dist/personas/validator.js +144 -0
  115. package/dist/personas/validator.js.map +1 -0
  116. package/dist/storage/factory.d.ts +51 -0
  117. package/dist/storage/factory.d.ts.map +1 -0
  118. package/dist/storage/factory.js +154 -0
  119. package/dist/storage/factory.js.map +1 -0
  120. package/dist/storage/gcp-bucket-provider.d.ts +60 -0
  121. package/dist/storage/gcp-bucket-provider.d.ts.map +1 -0
  122. package/dist/storage/gcp-bucket-provider.js +292 -0
  123. package/dist/storage/gcp-bucket-provider.js.map +1 -0
  124. package/dist/storage/index.d.ts +33 -0
  125. package/dist/storage/index.d.ts.map +1 -0
  126. package/dist/storage/index.js +37 -0
  127. package/dist/storage/index.js.map +1 -0
  128. package/dist/storage/local-provider.d.ts +37 -0
  129. package/dist/storage/local-provider.d.ts.map +1 -0
  130. package/dist/storage/local-provider.js +228 -0
  131. package/dist/storage/local-provider.js.map +1 -0
  132. package/dist/storage/provider.d.ts +142 -0
  133. package/dist/storage/provider.d.ts.map +1 -0
  134. package/dist/storage/provider.js +136 -0
  135. package/dist/storage/provider.js.map +1 -0
  136. package/dist/storage/types.d.ts +78 -0
  137. package/dist/storage/types.d.ts.map +1 -0
  138. package/dist/storage/types.js +14 -0
  139. package/dist/storage/types.js.map +1 -0
  140. package/dist/utils/logger.d.ts +19 -0
  141. package/dist/utils/logger.d.ts.map +1 -1
  142. package/dist/utils/logger.js +49 -1
  143. package/dist/utils/logger.js.map +1 -1
  144. package/dist/utils/orchestration-logger.d.ts +27 -3
  145. package/dist/utils/orchestration-logger.d.ts.map +1 -1
  146. package/dist/utils/orchestration-logger.js +110 -6
  147. package/dist/utils/orchestration-logger.js.map +1 -1
  148. package/package.json +30 -2
  149. package/.fluen/cache/state.json +0 -7
  150. package/actions/action_registry.py +0 -75
  151. package/actions/python_coder.py +0 -470
  152. package/api/main.py +0 -269
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * HTTP/WebSocket Interface for Jiva
4
+ *
5
+ * Entry point for Cloud Run deployment. Provides REST API and WebSocket
6
+ * endpoints for stateful, persistent sessions backed by GCS.
7
+ *
8
+ * Usage:
9
+ * - Cloud Run: Deployed as container, auto-scales to zero
10
+ * - Local dev: npm run serve
11
+ */
12
+ import express from 'express';
13
+ import { createServer } from 'http';
14
+ import { WebSocketServer } from 'ws';
15
+ import { logger, LogLevel } from '../../utils/logger.js';
16
+ import { SessionManager } from './session-manager.js';
17
+ import { createStorageProvider } from '../../storage/factory.js';
18
+ import { setupHealthRoutes } from './routes/health.js';
19
+ import { setupSessionRoutes } from './routes/session.js';
20
+ import { setupChatRoutes } from './routes/chat.js';
21
+ import { setupWebSocketHandler } from './websocket-handler.js';
22
+ import { authMiddleware } from './middleware/auth.js';
23
+ const PORT = parseInt(process.env.PORT || '8080', 10);
24
+ const HOST = process.env.HOST || '0.0.0.0';
25
+ const LOG_LEVEL = process.env.LOG_LEVEL || LogLevel.INFO;
26
+ const MAX_CONCURRENT_SESSIONS = parseInt(process.env.MAX_CONCURRENT_SESSIONS || '100', 10);
27
+ const SESSION_IDLE_TIMEOUT_MS = parseInt(process.env.SESSION_IDLE_TIMEOUT_MS || '1800000', 10); // 30 min default
28
+ // Configure logger
29
+ logger.setLogLevel(LOG_LEVEL);
30
+ async function bootstrap() {
31
+ const app = express();
32
+ const server = createServer(app);
33
+ const wss = new WebSocketServer({ noServer: true });
34
+ // Middleware
35
+ app.use(express.json({ limit: '10mb' }));
36
+ app.use(express.urlencoded({ extended: true }));
37
+ // CORS for development (restrict in production)
38
+ app.use((req, res, next) => {
39
+ const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'];
40
+ const origin = req.headers.origin;
41
+ if (origin && allowedOrigins.includes(origin)) {
42
+ res.setHeader('Access-Control-Allow-Origin', origin);
43
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
44
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
45
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
46
+ }
47
+ if (req.method === 'OPTIONS') {
48
+ res.sendStatus(200);
49
+ }
50
+ else {
51
+ next();
52
+ }
53
+ });
54
+ // Initialize storage provider (auto-detects environment)
55
+ const storageProvider = await createStorageProvider();
56
+ logger.info(`[HTTP] Storage provider initialized: ${storageProvider.constructor.name}`);
57
+ // Initialize session manager
58
+ const sessionManager = new SessionManager({
59
+ storageProvider,
60
+ maxConcurrentSessions: MAX_CONCURRENT_SESSIONS,
61
+ idleTimeoutMs: SESSION_IDLE_TIMEOUT_MS,
62
+ });
63
+ // Health check routes (no auth required)
64
+ setupHealthRoutes(app);
65
+ // API routes (auth required)
66
+ app.use('/api', authMiddleware);
67
+ setupSessionRoutes(app, sessionManager);
68
+ setupChatRoutes(app, sessionManager);
69
+ // WebSocket upgrade handler
70
+ server.on('upgrade', (request, socket, head) => {
71
+ // Extract token from query params or headers
72
+ const url = new URL(request.url || '', `http://${request.headers.host}`);
73
+ const token = url.searchParams.get('token') || request.headers.authorization?.replace('Bearer ', '');
74
+ if (!token) {
75
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
76
+ socket.destroy();
77
+ return;
78
+ }
79
+ // Auth will be validated in WebSocket handler
80
+ wss.handleUpgrade(request, socket, head, (ws) => {
81
+ wss.emit('connection', ws, request);
82
+ });
83
+ });
84
+ // Setup WebSocket handler
85
+ setupWebSocketHandler(wss, sessionManager);
86
+ // Error handling
87
+ app.use((err, req, res, next) => {
88
+ logger.error('[HTTP] Unhandled error:', err);
89
+ res.status(500).json({ error: 'Internal server error', message: err.message });
90
+ });
91
+ return { app, server, wss };
92
+ }
93
+ async function start() {
94
+ try {
95
+ logger.info('[HTTP] Starting Jiva HTTP/WebSocket server...');
96
+ logger.info(`[HTTP] Environment: ${process.env.NODE_ENV || 'development'}`);
97
+ logger.info(`[HTTP] Storage: ${process.env.JIVA_STORAGE_PROVIDER || 'auto-detect'}`);
98
+ logger.info(`[HTTP] Max sessions: ${MAX_CONCURRENT_SESSIONS}`);
99
+ logger.info(`[HTTP] Idle timeout: ${SESSION_IDLE_TIMEOUT_MS}ms`);
100
+ const { app, server, wss } = await bootstrap();
101
+ server.listen(PORT, HOST, () => {
102
+ logger.info(`[HTTP] Server listening on ${HOST}:${PORT}`);
103
+ logger.info(`[HTTP] Health check: http://${HOST}:${PORT}/health`);
104
+ logger.info(`[HTTP] WebSocket: ws://${HOST}:${PORT}/ws`);
105
+ });
106
+ // Graceful shutdown
107
+ const shutdown = async (signal) => {
108
+ logger.info(`[HTTP] Received ${signal}, shutting down gracefully...`);
109
+ wss.clients.forEach((client) => {
110
+ client.close(1000, 'Server shutting down');
111
+ });
112
+ server.close(() => {
113
+ logger.info('[HTTP] Server closed');
114
+ process.exit(0);
115
+ });
116
+ // Force exit after 30s
117
+ setTimeout(() => {
118
+ logger.error('[HTTP] Forced shutdown after timeout');
119
+ process.exit(1);
120
+ }, 30000);
121
+ };
122
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
123
+ process.on('SIGINT', () => shutdown('SIGINT'));
124
+ }
125
+ catch (error) {
126
+ logger.error('[HTTP] Failed to start server:', error);
127
+ process.exit(1);
128
+ }
129
+ }
130
+ // Start server if run directly
131
+ if (import.meta.url === `file://${process.argv[1]}`) {
132
+ start();
133
+ }
134
+ export { bootstrap, start };
135
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/interfaces/http/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Authentication Middleware
3
+ *
4
+ * Verifies JWT tokens and extracts tenantId/sessionId for storage context.
5
+ * Supports multiple auth strategies:
6
+ * - Firebase Auth
7
+ * - Custom JWT (HS256/RS256)
8
+ * - Development mode (no auth)
9
+ */
10
+ import { Request, Response, NextFunction } from 'express';
11
+ export interface AuthContext {
12
+ tenantId: string;
13
+ sessionId: string;
14
+ userId?: string;
15
+ email?: string;
16
+ }
17
+ declare global {
18
+ namespace Express {
19
+ interface Request {
20
+ auth?: AuthContext;
21
+ }
22
+ }
23
+ }
24
+ /**
25
+ * Extract and verify JWT token
26
+ */
27
+ export declare function authMiddleware(req: Request, res: Response, next: NextFunction): Promise<void>;
28
+ /**
29
+ * Optional: Extract auth from WebSocket connection
30
+ */
31
+ export declare function extractAuthFromWebSocket(request: any): Promise<AuthContext>;
32
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/http/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,WAAW,CAAC;SACpB;KACF;CACF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDnG;AAwGD;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CA6BjF"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Authentication Middleware
3
+ *
4
+ * Verifies JWT tokens and extracts tenantId/sessionId for storage context.
5
+ * Supports multiple auth strategies:
6
+ * - Firebase Auth
7
+ * - Custom JWT (HS256/RS256)
8
+ * - Development mode (no auth)
9
+ */
10
+ import { logger } from '../../../utils/logger.js';
11
+ /**
12
+ * Extract and verify JWT token
13
+ */
14
+ export async function authMiddleware(req, res, next) {
15
+ try {
16
+ // Development mode or auth disabled bypass
17
+ if (process.env.AUTH_DISABLED === 'true') {
18
+ logger.debug('[Auth] Auth disabled - bypassing authentication');
19
+ req.auth = {
20
+ tenantId: req.headers['x-tenant-id'] || 'dev-tenant',
21
+ sessionId: req.headers['x-session-id'] || generateSessionId(),
22
+ userId: 'dev-user',
23
+ email: 'dev@jiva.local',
24
+ };
25
+ next();
26
+ return;
27
+ }
28
+ // Extract token
29
+ const authHeader = req.headers.authorization;
30
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
31
+ res.status(401).json({ error: 'Missing or invalid authorization header' });
32
+ return;
33
+ }
34
+ const token = authHeader.substring(7);
35
+ // Verify token based on strategy
36
+ const authStrategy = process.env.AUTH_STRATEGY || 'custom';
37
+ let authContext;
38
+ switch (authStrategy) {
39
+ case 'firebase':
40
+ authContext = await verifyFirebaseToken(token);
41
+ break;
42
+ case 'custom':
43
+ authContext = await verifyCustomToken(token);
44
+ break;
45
+ default:
46
+ throw new Error(`Unknown auth strategy: ${authStrategy}`);
47
+ }
48
+ // Attach to request
49
+ req.auth = authContext;
50
+ next();
51
+ }
52
+ catch (error) {
53
+ logger.error('[Auth] Authentication failed:', error);
54
+ res.status(401).json({
55
+ error: 'Authentication failed',
56
+ message: error instanceof Error ? error.message : 'Invalid token'
57
+ });
58
+ }
59
+ }
60
+ /**
61
+ * Verify Firebase ID token
62
+ */
63
+ async function verifyFirebaseToken(token) {
64
+ // This would use firebase-admin SDK in production
65
+ // For now, implement basic JWT parsing
66
+ try {
67
+ // Dynamic import to keep firebase-admin optional
68
+ // @ts-expect-error - firebase-admin is an optional peer dependency
69
+ const admin = await import('firebase-admin');
70
+ if (!admin.apps.length) {
71
+ // Initialize Firebase Admin if not already done
72
+ const serviceAccount = process.env.FIREBASE_SERVICE_ACCOUNT
73
+ ? JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT)
74
+ : undefined;
75
+ admin.initializeApp({
76
+ credential: admin.credential.cert(serviceAccount),
77
+ });
78
+ }
79
+ const decodedToken = await admin.auth().verifyIdToken(token);
80
+ return {
81
+ tenantId: decodedToken.uid, // Use Firebase UID as tenantId
82
+ sessionId: decodedToken.session_id || generateSessionId(),
83
+ userId: decodedToken.uid,
84
+ email: decodedToken.email,
85
+ };
86
+ }
87
+ catch (error) {
88
+ logger.debug('[Auth] Firebase Admin not available, falling back to basic parsing');
89
+ // Fallback: parse JWT without verification (dev only)
90
+ return parseTokenBasic(token);
91
+ }
92
+ }
93
+ /**
94
+ * Verify custom JWT token
95
+ */
96
+ async function verifyCustomToken(token) {
97
+ const secret = process.env.JWT_SECRET;
98
+ if (!secret) {
99
+ throw new Error('JWT_SECRET not configured');
100
+ }
101
+ try {
102
+ // Use jsonwebtoken library
103
+ const jwt = await import('jsonwebtoken');
104
+ const decoded = jwt.verify(token, secret);
105
+ if (!decoded.tenantId && !decoded.sub) {
106
+ throw new Error('Token missing tenantId/sub claim');
107
+ }
108
+ return {
109
+ tenantId: decoded.tenantId || decoded.sub,
110
+ sessionId: decoded.sessionId || decoded.session_id || generateSessionId(),
111
+ userId: decoded.userId || decoded.sub,
112
+ email: decoded.email,
113
+ };
114
+ }
115
+ catch (error) {
116
+ logger.debug('[Auth] jsonwebtoken not available, falling back to basic parsing');
117
+ // Fallback: parse JWT without verification (dev only)
118
+ return parseTokenBasic(token);
119
+ }
120
+ }
121
+ /**
122
+ * Parse JWT token without verification (dev/fallback only)
123
+ */
124
+ function parseTokenBasic(token) {
125
+ const parts = token.split('.');
126
+ if (parts.length !== 3) {
127
+ throw new Error('Invalid JWT format');
128
+ }
129
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
130
+ if (!payload.tenantId && !payload.sub) {
131
+ throw new Error('Token missing tenantId/sub claim');
132
+ }
133
+ logger.warn('[Auth] Using unverified token parsing - DEVELOPMENT ONLY');
134
+ return {
135
+ tenantId: payload.tenantId || payload.sub || 'unknown',
136
+ sessionId: payload.sessionId || payload.session_id || generateSessionId(),
137
+ userId: payload.userId || payload.sub || 'unknown',
138
+ email: payload.email,
139
+ };
140
+ }
141
+ /**
142
+ * Generate a session ID
143
+ */
144
+ function generateSessionId() {
145
+ return `session-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
146
+ }
147
+ /**
148
+ * Optional: Extract auth from WebSocket connection
149
+ */
150
+ export async function extractAuthFromWebSocket(request) {
151
+ const url = new URL(request.url || '', `http://${request.headers.host}`);
152
+ const token = url.searchParams.get('token') || request.headers.authorization?.replace('Bearer ', '');
153
+ if (!token) {
154
+ throw new Error('No token provided');
155
+ }
156
+ // Development mode
157
+ if (process.env.NODE_ENV === 'development' && process.env.AUTH_DISABLED === 'true') {
158
+ return {
159
+ tenantId: url.searchParams.get('tenantId') || 'dev-tenant',
160
+ sessionId: url.searchParams.get('sessionId') || generateSessionId(),
161
+ userId: 'dev-user',
162
+ email: 'dev@jiva.local',
163
+ };
164
+ }
165
+ // Verify token
166
+ const authStrategy = process.env.AUTH_STRATEGY || 'custom';
167
+ switch (authStrategy) {
168
+ case 'firebase':
169
+ return await verifyFirebaseToken(token);
170
+ case 'custom':
171
+ return await verifyCustomToken(token);
172
+ default:
173
+ throw new Error(`Unknown auth strategy: ${authStrategy}`);
174
+ }
175
+ }
176
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/interfaces/http/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Chat routes - REST API with Server-Sent Events (SSE) streaming
3
+ */
4
+ import { Express } from 'express';
5
+ import { SessionManager } from '../session-manager.js';
6
+ export declare function setupChatRoutes(app: Express, sessionManager: SessionManager): void;
7
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/http/routes/chat.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,CA4JlF"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Chat routes - REST API with Server-Sent Events (SSE) streaming
3
+ */
4
+ import { logger } from '../../../utils/logger.js';
5
+ export function setupChatRoutes(app, sessionManager) {
6
+ /**
7
+ * Send a message (non-streaming)
8
+ * POST /api/chat
9
+ */
10
+ app.post('/api/chat', async (req, res) => {
11
+ try {
12
+ const { tenantId, sessionId } = req.auth;
13
+ const { message } = req.body;
14
+ if (!message || typeof message !== 'string') {
15
+ res.status(400).json({ error: 'Message is required and must be a string' });
16
+ return;
17
+ }
18
+ // Get or create session
19
+ const agent = await sessionManager.getOrCreateSession(tenantId, sessionId);
20
+ // Process message
21
+ const response = await agent.chat(message);
22
+ // Update activity
23
+ sessionManager.updateActivity(tenantId, sessionId);
24
+ res.status(200).json({
25
+ success: true,
26
+ response: response.content,
27
+ iterations: response.iterations,
28
+ toolsUsed: response.toolsUsed,
29
+ plan: response.plan,
30
+ });
31
+ }
32
+ catch (error) {
33
+ logger.error('[API] Chat error:', error);
34
+ res.status(500).json({
35
+ error: 'Failed to process message',
36
+ message: error instanceof Error ? error.message : 'Unknown error'
37
+ });
38
+ }
39
+ });
40
+ /**
41
+ * Send a message with streaming (Server-Sent Events)
42
+ * POST /api/chat/stream
43
+ */
44
+ app.post('/api/chat/stream', async (req, res) => {
45
+ try {
46
+ const { tenantId, sessionId } = req.auth;
47
+ const { message } = req.body;
48
+ if (!message || typeof message !== 'string') {
49
+ res.status(400).json({ error: 'Message is required and must be a string' });
50
+ return;
51
+ }
52
+ // Setup SSE
53
+ res.setHeader('Content-Type', 'text/event-stream');
54
+ res.setHeader('Cache-Control', 'no-cache');
55
+ res.setHeader('Connection', 'keep-alive');
56
+ res.flushHeaders();
57
+ // Helper to send SSE message
58
+ const sendEvent = (event, data) => {
59
+ res.write(`event: ${event}\n`);
60
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
61
+ };
62
+ try {
63
+ // Get or create session
64
+ const agent = await sessionManager.getOrCreateSession(tenantId, sessionId);
65
+ sendEvent('status', { message: 'Processing request...' });
66
+ // Process message (for now, not truly streaming from agent)
67
+ // TODO: Implement streaming support in DualAgent
68
+ const response = await agent.chat(message);
69
+ // Send response
70
+ sendEvent('response', {
71
+ content: response.content,
72
+ iterations: response.iterations,
73
+ toolsUsed: response.toolsUsed,
74
+ plan: response.plan,
75
+ });
76
+ // Update activity
77
+ sessionManager.updateActivity(tenantId, sessionId);
78
+ sendEvent('done', { success: true });
79
+ res.end();
80
+ }
81
+ catch (error) {
82
+ logger.error('[API] Chat stream error:', error);
83
+ sendEvent('error', {
84
+ message: error instanceof Error ? error.message : 'Unknown error'
85
+ });
86
+ res.end();
87
+ }
88
+ }
89
+ catch (error) {
90
+ logger.error('[API] Chat stream setup error:', error);
91
+ res.status(500).json({
92
+ error: 'Failed to setup stream',
93
+ message: error instanceof Error ? error.message : 'Unknown error'
94
+ });
95
+ }
96
+ });
97
+ /**
98
+ * Get conversation history
99
+ * GET /api/chat/history
100
+ */
101
+ app.get('/api/chat/history', async (req, res) => {
102
+ try {
103
+ const { tenantId, sessionId } = req.auth;
104
+ // Get session
105
+ const agent = await sessionManager.getOrCreateSession(tenantId, sessionId);
106
+ const history = agent.getConversationHistory();
107
+ res.status(200).json({
108
+ success: true,
109
+ history,
110
+ count: history.length,
111
+ });
112
+ }
113
+ catch (error) {
114
+ logger.error('[API] Failed to get history:', error);
115
+ res.status(500).json({
116
+ error: 'Failed to get history',
117
+ message: error instanceof Error ? error.message : 'Unknown error'
118
+ });
119
+ }
120
+ });
121
+ /**
122
+ * Clear conversation history
123
+ * DELETE /api/chat/history
124
+ */
125
+ app.delete('/api/chat/history', async (req, res) => {
126
+ try {
127
+ const { tenantId, sessionId } = req.auth;
128
+ // Destroy and recreate session to clear history
129
+ await sessionManager.destroySession(tenantId, sessionId);
130
+ res.status(200).json({
131
+ success: true,
132
+ message: 'Conversation history cleared',
133
+ });
134
+ }
135
+ catch (error) {
136
+ logger.error('[API] Failed to clear history:', error);
137
+ res.status(500).json({
138
+ error: 'Failed to clear history',
139
+ message: error instanceof Error ? error.message : 'Unknown error'
140
+ });
141
+ }
142
+ });
143
+ }
144
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../../src/interfaces/http/routes/chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Health check routes for Cloud Run
3
+ */
4
+ import { Express } from 'express';
5
+ export declare function setupHealthRoutes(app: Express): void;
6
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/http/routes/health.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAErD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAsBpD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Health check routes for Cloud Run
3
+ */
4
+ export function setupHealthRoutes(app) {
5
+ /**
6
+ * Liveness probe - is the server running?
7
+ */
8
+ app.get('/health', (req, res) => {
9
+ res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
10
+ });
11
+ /**
12
+ * Readiness probe - is the server ready to accept traffic?
13
+ */
14
+ app.get('/ready', (req, res) => {
15
+ // Could check database connections, model availability, etc.
16
+ res.status(200).json({ status: 'ready', timestamp: new Date().toISOString() });
17
+ });
18
+ /**
19
+ * Startup probe - has the server finished initialization?
20
+ */
21
+ app.get('/startup', (req, res) => {
22
+ res.status(200).json({ status: 'started', timestamp: new Date().toISOString() });
23
+ });
24
+ }
25
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../../src/interfaces/http/routes/health.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C;;OAEG;IACH,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACjD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH;;OAEG;IACH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAChD,6DAA6D;QAC7D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH;;OAEG;IACH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Session management routes
3
+ */
4
+ import { Express } from 'express';
5
+ import { SessionManager } from '../session-manager.js';
6
+ export declare function setupSessionRoutes(app: Express, sessionManager: SessionManager): void;
7
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/http/routes/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,GAAG,IAAI,CAsHrF"}