@agent-relay/dashboard-server 2.0.38 → 2.0.40

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 (56) hide show
  1. package/dist/server.js +47 -6
  2. package/dist/server.js.map +1 -1
  3. package/out/404.html +1 -1
  4. package/out/_next/static/chunks/983-598ff3b7e6dffb8f.js +1 -0
  5. package/out/about.html +1 -1
  6. package/out/about.txt +1 -1
  7. package/out/app/onboarding.html +1 -1
  8. package/out/app/onboarding.txt +1 -1
  9. package/out/app.html +1 -1
  10. package/out/app.txt +2 -2
  11. package/out/blog.html +1 -1
  12. package/out/blog.txt +1 -1
  13. package/out/careers.html +1 -1
  14. package/out/careers.txt +1 -1
  15. package/out/changelog.html +1 -1
  16. package/out/changelog.txt +1 -1
  17. package/out/cloud/link.html +1 -1
  18. package/out/cloud/link.txt +1 -1
  19. package/out/complete-profile.html +1 -1
  20. package/out/complete-profile.txt +1 -1
  21. package/out/connect-repos.html +1 -1
  22. package/out/connect-repos.txt +1 -1
  23. package/out/contact.html +1 -1
  24. package/out/contact.txt +1 -1
  25. package/out/docs.html +1 -1
  26. package/out/docs.txt +1 -1
  27. package/out/history.html +1 -1
  28. package/out/history.txt +1 -1
  29. package/out/index.html +1 -1
  30. package/out/index.txt +2 -2
  31. package/out/login.html +1 -1
  32. package/out/login.txt +1 -1
  33. package/out/metrics.html +1 -1
  34. package/out/metrics.txt +1 -1
  35. package/out/pricing.html +1 -1
  36. package/out/pricing.txt +1 -1
  37. package/out/privacy.html +1 -1
  38. package/out/privacy.txt +1 -1
  39. package/out/providers/setup/claude.html +1 -1
  40. package/out/providers/setup/claude.txt +1 -1
  41. package/out/providers/setup/codex.html +1 -1
  42. package/out/providers/setup/codex.txt +1 -1
  43. package/out/providers/setup/cursor.html +1 -1
  44. package/out/providers/setup/cursor.txt +1 -1
  45. package/out/providers.html +1 -1
  46. package/out/providers.txt +1 -1
  47. package/out/security.html +1 -1
  48. package/out/security.txt +1 -1
  49. package/out/signup.html +1 -1
  50. package/out/signup.txt +1 -1
  51. package/out/terms.html +1 -1
  52. package/out/terms.txt +1 -1
  53. package/package.json +1 -1
  54. package/out/_next/static/chunks/983-ae0bbf38febd0c61.js +0 -1
  55. /package/out/_next/static/{5Gm-p6vZlC7ybV6NrMmHU → ihGidN_vO8k4Yv_u6eOpR}/_buildManifest.js +0 -0
  56. /package/out/_next/static/{5Gm-p6vZlC7ybV6NrMmHU → ihGidN_vO8k4Yv_u6eOpR}/_ssgManifest.js +0 -0
package/dist/server.js CHANGED
@@ -3317,6 +3317,39 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
3317
3317
  });
3318
3318
  });
3319
3319
  // ===== CLI Auth API (for workspace-based provider authentication) =====
3320
+ /**
3321
+ * Middleware to validate workspace token for internal endpoints.
3322
+ * In cloud mode, requests to /auth/cli/* must include a valid WORKSPACE_TOKEN
3323
+ * to prevent unauthorized access to auth sessions.
3324
+ */
3325
+ const validateWorkspaceToken = (req, res, next) => {
3326
+ // Skip auth validation in local mode (no WORKSPACE_TOKEN set)
3327
+ const expectedToken = process.env.WORKSPACE_TOKEN;
3328
+ if (!expectedToken) {
3329
+ return next();
3330
+ }
3331
+ // Extract token from Authorization header
3332
+ const authHeader = req.headers.authorization;
3333
+ const token = authHeader?.startsWith('Bearer ')
3334
+ ? authHeader.substring(7)
3335
+ : null;
3336
+ // Use timing-safe comparison to prevent timing attacks
3337
+ if (!token) {
3338
+ console.warn('[dashboard] Unauthorized CLI auth request - missing workspace token');
3339
+ return res.status(401).json({ error: 'Unauthorized - invalid workspace token' });
3340
+ }
3341
+ const tokenBuffer = Buffer.from(token);
3342
+ const expectedBuffer = Buffer.from(expectedToken);
3343
+ const isValidToken = tokenBuffer.length === expectedBuffer.length &&
3344
+ crypto.timingSafeEqual(tokenBuffer, expectedBuffer);
3345
+ if (!isValidToken) {
3346
+ console.warn('[dashboard] Unauthorized CLI auth request - invalid workspace token');
3347
+ return res.status(401).json({ error: 'Unauthorized - invalid workspace token' });
3348
+ }
3349
+ next();
3350
+ };
3351
+ // Apply workspace token validation to all CLI auth endpoints
3352
+ app.use('/auth/cli', validateWorkspaceToken);
3320
3353
  /**
3321
3354
  * POST /auth/cli/:provider/start - Start CLI auth flow
3322
3355
  * Body: { useDeviceFlow?: boolean, userId?: string }
@@ -3575,9 +3608,13 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
3575
3608
  lastSeen: a.lastSeen ?? new Date().toISOString(),
3576
3609
  }));
3577
3610
  }
3578
- // Get messages for throughput calculation
3579
- const team = getTeamData();
3580
- const messages = team ? await getMessages(team.agents) : [];
3611
+ // Get messages for throughput calculation - use storage directly for metrics
3612
+ // (avoids daemon query timeouts that occur when daemon is busy)
3613
+ let messages = [];
3614
+ if (storage) {
3615
+ const rows = await storage.getMessages({ limit: 100, order: 'desc' });
3616
+ messages = rows.map(r => ({ timestamp: new Date(r.ts).toISOString() }));
3617
+ }
3581
3618
  // Get session data for lifecycle metrics
3582
3619
  const sessions = storage?.getSessions
3583
3620
  ? await storage.getSessions({ limit: 100 })
@@ -3608,9 +3645,13 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
3608
3645
  lastSeen: a.lastSeen ?? new Date().toISOString(),
3609
3646
  }));
3610
3647
  }
3611
- // Get messages for throughput calculation
3612
- const team = getTeamData();
3613
- const messages = team ? await getMessages(team.agents) : [];
3648
+ // Get messages for throughput calculation - use storage directly for metrics
3649
+ // (avoids daemon query timeouts that occur when daemon is busy)
3650
+ let messages = [];
3651
+ if (storage) {
3652
+ const rows = await storage.getMessages({ limit: 100, order: 'desc' });
3653
+ messages = rows.map(r => ({ timestamp: new Date(r.ts).toISOString() }));
3654
+ }
3614
3655
  // Get session data for lifecycle metrics
3615
3656
  const sessions = storage?.getSessions
3616
3657
  ? await storage.getSessions({ limit: 100 })