@agent-relay/dashboard-server 2.0.83-beta.0 → 2.0.85
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.d.ts +3 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -23
- package/dist/index.js.map +1 -1
- package/dist/lib/attachment-storage.d.ts +10 -0
- package/dist/lib/attachment-storage.d.ts.map +1 -0
- package/dist/lib/attachment-storage.js +53 -0
- package/dist/lib/attachment-storage.js.map +1 -0
- package/dist/lib/broadcast.d.ts +18 -0
- package/dist/lib/broadcast.d.ts.map +1 -0
- package/dist/lib/broadcast.js +118 -0
- package/dist/lib/broadcast.js.map +1 -0
- package/dist/lib/channel-state.d.ts +32 -0
- package/dist/lib/channel-state.d.ts.map +1 -0
- package/dist/lib/channel-state.js +146 -0
- package/dist/lib/channel-state.js.map +1 -0
- package/dist/lib/cli-auth.d.ts +40 -0
- package/dist/lib/cli-auth.d.ts.map +1 -0
- package/dist/lib/cli-auth.js +144 -0
- package/dist/lib/cli-auth.js.map +1 -0
- package/dist/lib/cloud-persistence.d.ts +6 -0
- package/dist/lib/cloud-persistence.d.ts.map +1 -0
- package/dist/lib/cloud-persistence.js +130 -0
- package/dist/lib/cloud-persistence.js.map +1 -0
- package/dist/lib/data-assembly.d.ts +136 -0
- package/dist/lib/data-assembly.d.ts.map +1 -0
- package/dist/lib/data-assembly.js +550 -0
- package/dist/lib/data-assembly.js.map +1 -0
- package/dist/lib/file-search.d.ts +8 -0
- package/dist/lib/file-search.d.ts.map +1 -0
- package/dist/lib/file-search.js +90 -0
- package/dist/lib/file-search.js.map +1 -0
- package/dist/lib/identity.d.ts +54 -0
- package/dist/lib/identity.d.ts.map +1 -0
- package/dist/lib/identity.js +124 -0
- package/dist/lib/identity.js.map +1 -0
- package/dist/lib/log-line-cleaner.d.ts +20 -0
- package/dist/lib/log-line-cleaner.d.ts.map +1 -0
- package/dist/lib/log-line-cleaner.js +117 -0
- package/dist/lib/log-line-cleaner.js.map +1 -0
- package/dist/lib/log-reader.d.ts +14 -0
- package/dist/lib/log-reader.d.ts.map +1 -0
- package/dist/lib/log-reader.js +80 -0
- package/dist/lib/log-reader.js.map +1 -0
- package/dist/lib/message-id.d.ts +30 -0
- package/dist/lib/message-id.d.ts.map +1 -0
- package/dist/lib/message-id.js +50 -0
- package/dist/lib/message-id.js.map +1 -0
- package/dist/lib/process-metrics.d.ts +11 -0
- package/dist/lib/process-metrics.d.ts.map +1 -0
- package/dist/lib/process-metrics.js +252 -0
- package/dist/lib/process-metrics.js.map +1 -0
- package/dist/lib/proxy-route-table.d.ts +16 -0
- package/dist/lib/proxy-route-table.d.ts.map +1 -0
- package/dist/lib/proxy-route-table.js +73 -0
- package/dist/lib/proxy-route-table.js.map +1 -0
- package/dist/lib/send-strategy.d.ts +62 -0
- package/dist/lib/send-strategy.d.ts.map +1 -0
- package/dist/lib/send-strategy.js +136 -0
- package/dist/lib/send-strategy.js.map +1 -0
- package/dist/lib/server-state.d.ts +115 -0
- package/dist/lib/server-state.d.ts.map +1 -0
- package/dist/lib/server-state.js +138 -0
- package/dist/lib/server-state.js.map +1 -0
- package/dist/lib/spawned-agents.d.ts +35 -0
- package/dist/lib/spawned-agents.d.ts.map +1 -0
- package/dist/lib/spawned-agents.js +340 -0
- package/dist/lib/spawned-agents.js.map +1 -0
- package/dist/lib/types.d.ts +123 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +12 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +71 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +332 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/websocket-runtime.d.ts +17 -0
- package/dist/lib/websocket-runtime.d.ts.map +1 -0
- package/dist/lib/websocket-runtime.js +76 -0
- package/dist/lib/websocket-runtime.js.map +1 -0
- package/dist/mocks/fixtures.d.ts +2 -2
- package/dist/mocks/fixtures.js +1 -1
- package/dist/mocks/routes.d.ts.map +1 -1
- package/dist/mocks/routes.js +30 -3
- package/dist/mocks/routes.js.map +1 -1
- package/dist/mocks/types.d.ts +1 -1
- package/dist/mocks/types.js +1 -1
- package/dist/proxy-server.d.ts +7 -33
- package/dist/proxy-server.d.ts.map +1 -1
- package/dist/proxy-server.js +353 -201
- package/dist/proxy-server.js.map +1 -1
- package/dist/relaycast-provider-helpers.d.ts +41 -0
- package/dist/relaycast-provider-helpers.d.ts.map +1 -0
- package/dist/relaycast-provider-helpers.js +285 -0
- package/dist/relaycast-provider-helpers.js.map +1 -0
- package/dist/relaycast-provider-types.d.ts +117 -0
- package/dist/relaycast-provider-types.d.ts.map +1 -0
- package/dist/relaycast-provider-types.js +6 -0
- package/dist/relaycast-provider-types.js.map +1 -0
- package/dist/relaycast-provider.d.ts +48 -0
- package/dist/relaycast-provider.d.ts.map +1 -0
- package/dist/relaycast-provider.js +293 -0
- package/dist/relaycast-provider.js.map +1 -0
- package/dist/routes/agents.d.ts +7 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +180 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/auth.d.ts +45 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +261 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/broker-proxy.d.ts +7 -0
- package/dist/routes/broker-proxy.d.ts.map +1 -0
- package/dist/routes/broker-proxy.js +114 -0
- package/dist/routes/broker-proxy.js.map +1 -0
- package/dist/routes/channels-integrated.d.ts +84 -0
- package/dist/routes/channels-integrated.d.ts.map +1 -0
- package/dist/routes/channels-integrated.js +644 -0
- package/dist/routes/channels-integrated.js.map +1 -0
- package/dist/routes/channels.d.ts +7 -0
- package/dist/routes/channels.d.ts.map +1 -0
- package/dist/routes/channels.js +457 -0
- package/dist/routes/channels.js.map +1 -0
- package/dist/routes/data.d.ts +7 -0
- package/dist/routes/data.d.ts.map +1 -0
- package/dist/routes/data.js +108 -0
- package/dist/routes/data.js.map +1 -0
- package/dist/routes/decisions.d.ts +31 -0
- package/dist/routes/decisions.d.ts.map +1 -0
- package/dist/routes/decisions.js +109 -0
- package/dist/routes/decisions.js.map +1 -0
- package/dist/routes/fleet.d.ts +24 -0
- package/dist/routes/fleet.d.ts.map +1 -0
- package/dist/routes/fleet.js +131 -0
- package/dist/routes/fleet.js.map +1 -0
- package/dist/routes/health.d.ts +7 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +55 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/history-relaycast.d.ts +8 -0
- package/dist/routes/history-relaycast.d.ts.map +1 -0
- package/dist/routes/history-relaycast.js +165 -0
- package/dist/routes/history-relaycast.js.map +1 -0
- package/dist/routes/history.d.ts +13 -0
- package/dist/routes/history.d.ts.map +1 -0
- package/dist/routes/history.js +205 -0
- package/dist/routes/history.js.map +1 -0
- package/dist/routes/messaging.d.ts +34 -0
- package/dist/routes/messaging.d.ts.map +1 -0
- package/dist/routes/messaging.js +306 -0
- package/dist/routes/messaging.js.map +1 -0
- package/dist/routes/metrics.d.ts +26 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +276 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/reactions.d.ts +9 -0
- package/dist/routes/reactions.d.ts.map +1 -0
- package/dist/routes/reactions.js +76 -0
- package/dist/routes/reactions.js.map +1 -0
- package/dist/routes/relay-config.d.ts +4 -0
- package/dist/routes/relay-config.d.ts.map +1 -0
- package/dist/routes/relay-config.js +81 -0
- package/dist/routes/relay-config.js.map +1 -0
- package/dist/routes/settings.d.ts +6 -0
- package/dist/routes/settings.d.ts.map +1 -0
- package/dist/routes/settings.js +119 -0
- package/dist/routes/settings.js.map +1 -0
- package/dist/routes/spawn.d.ts +74 -0
- package/dist/routes/spawn.d.ts.map +1 -0
- package/dist/routes/spawn.js +520 -0
- package/dist/routes/spawn.js.map +1 -0
- package/dist/routes/system.d.ts +21 -0
- package/dist/routes/system.d.ts.map +1 -0
- package/dist/routes/system.js +186 -0
- package/dist/routes/system.js.map +1 -0
- package/dist/routes/tasks.d.ts +27 -0
- package/dist/routes/tasks.d.ts.map +1 -0
- package/dist/routes/tasks.js +103 -0
- package/dist/routes/tasks.js.map +1 -0
- package/dist/routes/thread-replies.d.ts +7 -0
- package/dist/routes/thread-replies.d.ts.map +1 -0
- package/dist/routes/thread-replies.js +178 -0
- package/dist/routes/thread-replies.js.map +1 -0
- package/dist/routes/ui.d.ts +6 -0
- package/dist/routes/ui.d.ts.map +1 -0
- package/dist/routes/ui.js +114 -0
- package/dist/routes/ui.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +304 -6152
- package/dist/server.js.map +1 -1
- package/dist/services/broker-spawn-reader.d.ts +1 -1
- package/dist/services/broker-spawn-reader.d.ts.map +1 -1
- package/dist/services/broker-spawn-reader.js +3 -2
- package/dist/services/broker-spawn-reader.js.map +1 -1
- package/dist/services/health-worker-manager.d.ts +9 -60
- package/dist/services/health-worker-manager.d.ts.map +1 -1
- package/dist/services/health-worker-manager.js +18 -148
- package/dist/services/health-worker-manager.js.map +1 -1
- package/dist/services/index.d.ts +3 -3
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -3
- package/dist/services/index.js.map +1 -1
- package/dist/services/metrics.d.ts +11 -104
- package/dist/services/metrics.d.ts.map +1 -1
- package/dist/services/metrics.js +21 -190
- package/dist/services/metrics.js.map +1 -1
- package/dist/services/needs-attention.d.ts +21 -22
- package/dist/services/needs-attention.d.ts.map +1 -1
- package/dist/services/needs-attention.js +46 -71
- package/dist/services/needs-attention.js.map +1 -1
- package/dist/services/user-bridge.d.ts +0 -3
- package/dist/services/user-bridge.d.ts.map +1 -1
- package/dist/services/user-bridge.js +0 -5
- package/dist/services/user-bridge.js.map +1 -1
- package/dist/start.d.ts +4 -4
- package/dist/start.js +97 -89
- package/dist/start.js.map +1 -1
- package/dist/types/index.d.ts +11 -21
- package/dist/types/index.d.ts.map +1 -1
- package/dist/websocket/bridge.d.ts +12 -0
- package/dist/websocket/bridge.d.ts.map +1 -0
- package/dist/websocket/bridge.js +33 -0
- package/dist/websocket/bridge.js.map +1 -0
- package/dist/websocket/logs.d.ts +30 -0
- package/dist/websocket/logs.d.ts.map +1 -0
- package/dist/websocket/logs.js +577 -0
- package/dist/websocket/logs.js.map +1 -0
- package/dist/websocket/main.d.ts +15 -0
- package/dist/websocket/main.d.ts.map +1 -0
- package/dist/websocket/main.js +84 -0
- package/dist/websocket/main.js.map +1 -0
- package/dist/websocket/mock.d.ts +6 -0
- package/dist/websocket/mock.d.ts.map +1 -0
- package/dist/websocket/mock.js +49 -0
- package/dist/websocket/mock.js.map +1 -0
- package/dist/websocket/presence.d.ts +74 -0
- package/dist/websocket/presence.d.ts.map +1 -0
- package/dist/websocket/presence.js +330 -0
- package/dist/websocket/presence.js.map +1 -0
- package/dist/websocket/proxy.d.ts +6 -0
- package/dist/websocket/proxy.d.ts.map +1 -0
- package/dist/websocket/proxy.js +39 -0
- package/dist/websocket/proxy.js.map +1 -0
- package/dist/websocket/standalone.d.ts +17 -0
- package/dist/websocket/standalone.d.ts.map +1 -0
- package/dist/websocket/standalone.js +268 -0
- package/dist/websocket/standalone.js.map +1 -0
- package/out/404.html +1 -1
- package/out/_next/static/{TnAI-TAQ4-bNJRL3Ln3NB → 49XhcS8k_e8607S7KBMwA}/_buildManifest.js +1 -1
- package/out/_next/static/chunks/1028-53c5a7e2453505f8.js +1 -0
- package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
- package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
- package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
- package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
- package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
- package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
- package/out/_next/static/chunks/5118-de1c8f968feab8e2.js +1 -0
- package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
- package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
- package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
- package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
- package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
- package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
- package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
- package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
- package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
- package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
- package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
- package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
- package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
- package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
- package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
- package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
- package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
- package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
- package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
- package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
- package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
- package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
- package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
- package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
- package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
- package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
- package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
- package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
- package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
- package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
- package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
- package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
- package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
- package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
- package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
- package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
- package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
- package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
- package/out/about.html +2 -2
- package/out/about.txt +2 -2
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +2 -2
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +2 -2
- package/out/changelog.html +2 -2
- package/out/changelog.txt +2 -2
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +2 -2
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +2 -2
- package/out/contact.html +2 -2
- package/out/contact.txt +2 -2
- package/out/dev/cli-tools.html +1 -0
- package/out/dev/cli-tools.txt +7 -0
- package/out/dev/log-viewer.html +23 -0
- package/out/dev/log-viewer.txt +7 -0
- package/out/docs.html +2 -2
- package/out/docs.txt +2 -2
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +2 -2
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +2 -2
- package/out/privacy.html +2 -2
- package/out/privacy.txt +2 -2
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +2 -2
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +2 -2
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +2 -2
- package/out/providers.html +1 -1
- package/out/providers.txt +2 -2
- package/out/security.html +2 -2
- package/out/security.txt +2 -2
- package/out/signup.html +2 -2
- package/out/signup.txt +2 -2
- package/out/terms.html +2 -2
- package/out/terms.txt +2 -2
- package/package.json +10 -11
- package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
- package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
- package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
- package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
- package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
- package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
- package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
- package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
- package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
- package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
- package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
- package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
- package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
- package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
- package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
- package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
- package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
- package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
- package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
- package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
- package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
- package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
- package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
- package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
- package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
- package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
- package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
- package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
- package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
- package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
- package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
- package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
- package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
- package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
- package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
- package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
- package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
- /package/out/_next/static/{TnAI-TAQ4-bNJRL3Ln3NB → 49XhcS8k_e8607S7KBMwA}/_ssgManifest.js +0 -0
package/dist/proxy-server.js
CHANGED
|
@@ -1,63 +1,113 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Relay Dashboard Server
|
|
3
3
|
*
|
|
4
|
-
* A flexible server that can operate in
|
|
5
|
-
* 1. Proxy mode (default):
|
|
6
|
-
* 2.
|
|
7
|
-
*
|
|
8
|
-
* This allows the dashboard to run independently without any external dependencies.
|
|
4
|
+
* A flexible server that can operate in three modes:
|
|
5
|
+
* 1. Proxy mode (default): static files + Relaycast data + broker proxy
|
|
6
|
+
* 2. Standalone mode: static files + Relaycast data (no broker proxy)
|
|
7
|
+
* 3. Mock mode: fixture-backed standalone mode for demos/tests
|
|
9
8
|
*/
|
|
10
9
|
import express from 'express';
|
|
11
10
|
import { createServer as createHttpServer } from 'http';
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
11
|
+
import { WebSocketServer } from 'ws';
|
|
12
|
+
import fs from 'fs';
|
|
14
13
|
import path from 'path';
|
|
15
14
|
import { fileURLToPath } from 'url';
|
|
16
15
|
import { registerMockRoutes } from './mocks/routes.js';
|
|
17
|
-
import {
|
|
16
|
+
import { fetchAgents, fetchChannels, loadRelaycastConfig, } from './relaycast-provider.js';
|
|
17
|
+
import { createSendStrategy } from './lib/send-strategy.js';
|
|
18
|
+
import { DASHBOARD_DISPLAY_NAME } from './relaycast-provider-types.js';
|
|
19
|
+
import { resolveIdentity } from './lib/identity.js';
|
|
20
|
+
import { EMPTY_DASHBOARD_SNAPSHOT } from './lib/types.js';
|
|
21
|
+
import { normalizeRelayUrl, normalizeName, isDirectRecipient, sendHtmlFileOrFallback, getBindHost, mapChannelForDashboard, } from './lib/utils.js';
|
|
22
|
+
import { filterPhantomAgents, mergeBrokerSpawnedAgents, createSpawnedAgentsCaches, } from './lib/spawned-agents.js';
|
|
23
|
+
import { handleMockWebSocket } from './websocket/mock.js';
|
|
24
|
+
import { handleStandaloneWebSocket, handleHybridWebSocket } from './websocket/standalone.js';
|
|
25
|
+
import { handleStandaloneLogWebSocket } from './websocket/logs.js';
|
|
26
|
+
import { registerHealthRoutes } from './routes/health.js';
|
|
27
|
+
import { registerDataRoutes } from './routes/data.js';
|
|
28
|
+
import { registerAgentRoutes } from './routes/agents.js';
|
|
29
|
+
import { registerChannelRoutes } from './routes/channels.js';
|
|
30
|
+
import { registerBrokerProxyRoutes } from './routes/broker-proxy.js';
|
|
31
|
+
import { registerMetricsRoutes } from './routes/metrics.js';
|
|
32
|
+
import { registerReactionRoutes } from './routes/reactions.js';
|
|
33
|
+
import { registerThreadReplyRoutes } from './routes/thread-replies.js';
|
|
34
|
+
import { registerRelayConfigRoutes } from './routes/relay-config.js';
|
|
35
|
+
import { registerRelaycastHistoryRoutes } from './routes/history-relaycast.js';
|
|
18
36
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
37
|
const __dirname = path.dirname(__filename);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
function resolveMetricsPagePath(staticDir) {
|
|
39
|
+
const candidates = [
|
|
40
|
+
path.join(staticDir, 'metrics.html'),
|
|
41
|
+
path.join(staticDir, 'metrics', 'index.html'),
|
|
42
|
+
path.join(staticDir, 'app.html'),
|
|
43
|
+
path.join(staticDir, 'index.html'),
|
|
44
|
+
];
|
|
45
|
+
for (const candidate of candidates) {
|
|
46
|
+
if (fs.existsSync(candidate)) {
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
30
49
|
}
|
|
31
|
-
|
|
32
|
-
// Fly.io internal network uses IPv6 (fdaa:...), so 0.0.0.0 won't work
|
|
33
|
-
const isCloudEnvironment = process.env.FLY_APP_NAME || // Fly.io
|
|
34
|
-
process.env.WORKSPACE_ID || // Agent Relay workspace
|
|
35
|
-
process.env.RELAY_WORKSPACE_ID || // Alternative workspace ID
|
|
36
|
-
process.env.RUNNING_IN_DOCKER === 'true'; // Docker container
|
|
37
|
-
return isCloudEnvironment ? '::' : undefined;
|
|
50
|
+
return candidates[0];
|
|
38
51
|
}
|
|
52
|
+
const asString = (value) => {
|
|
53
|
+
if (typeof value === 'string' && value.length > 0)
|
|
54
|
+
return value;
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
for (const item of value) {
|
|
57
|
+
if (typeof item === 'string' && item.length > 0)
|
|
58
|
+
return item;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
};
|
|
63
|
+
const getWorkspaceHeader = (headers) => {
|
|
64
|
+
if (!headers)
|
|
65
|
+
return undefined;
|
|
66
|
+
const direct = headers['x-workspace-id'];
|
|
67
|
+
if (typeof direct === 'string' && direct.length > 0)
|
|
68
|
+
return direct;
|
|
69
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
70
|
+
if (key.toLowerCase() === 'x-workspace-id' && typeof value === 'string' && value.length > 0) {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
};
|
|
39
76
|
/**
|
|
40
77
|
* Create the dashboard server without starting it
|
|
41
78
|
*/
|
|
42
79
|
export function createServer(options = {}) {
|
|
43
|
-
const {
|
|
80
|
+
const { relayUrl: relayUrlOption, staticDir = process.env.STATIC_DIR || path.join(__dirname, '..', 'out'), dataDir = process.env.DATA_DIR || path.join(process.cwd(), '.agent-relay'), verbose = process.env.VERBOSE === 'true', mock = process.env.MOCK === 'true', corsOrigins = process.env.CORS_ORIGINS || '', requestTimeout = parseInt(process.env.REQUEST_TIMEOUT || '60000', 10), relayApiKey: relayApiKeyOption, } = options;
|
|
81
|
+
// In-memory API key — highest priority, avoids any file I/O.
|
|
82
|
+
// Seeded from the option or RELAY_API_KEY env var, then updated dynamically
|
|
83
|
+
// via setRelayApiKey() when a workflow creates a new Relaycast workspace.
|
|
84
|
+
let inMemoryRelayApiKey = relayApiKeyOption?.trim() || process.env.RELAY_API_KEY?.trim() || undefined;
|
|
85
|
+
const resolvedDataDir = path.resolve(dataDir);
|
|
86
|
+
if (!process.env.AGENT_RELAY_PROJECT) {
|
|
87
|
+
process.env.AGENT_RELAY_PROJECT = path.dirname(resolvedDataDir);
|
|
88
|
+
}
|
|
89
|
+
const relayUrl = normalizeRelayUrl(relayUrlOption ?? process.env.RELAY_URL);
|
|
90
|
+
const mode = mock ? 'mock' : (relayUrl ? 'proxy' : 'standalone');
|
|
91
|
+
const brokerProxyEnabled = mode === 'proxy' && Boolean(relayUrl);
|
|
92
|
+
const defaultWorkspaceId = process.env.RELAY_WORKSPACE_ID ?? process.env.AGENT_RELAY_WORKSPACE_ID;
|
|
93
|
+
const resolveWorkspaceId = (req) => {
|
|
94
|
+
const fromQuery = asString(req.query?.workspaceId);
|
|
95
|
+
const fromBody = asString(req.body?.workspaceId);
|
|
96
|
+
const fromHeader = getWorkspaceHeader(req.headers);
|
|
97
|
+
return fromQuery || fromBody || fromHeader || defaultWorkspaceId;
|
|
98
|
+
};
|
|
44
99
|
const app = express();
|
|
45
100
|
const server = createHttpServer(app);
|
|
46
|
-
const mode = mock ? 'mock' : 'proxy';
|
|
47
|
-
// Set request timeout
|
|
48
101
|
server.timeout = requestTimeout;
|
|
49
|
-
// Parse JSON bodies
|
|
50
102
|
app.use(express.json({ limit: '10mb' }));
|
|
51
|
-
// CORS middleware - configurable for cross-origin deployments
|
|
52
103
|
if (corsOrigins) {
|
|
53
104
|
app.use((req, res, next) => {
|
|
54
105
|
const origin = req.headers.origin;
|
|
55
|
-
// Check if origin is allowed
|
|
56
106
|
if (corsOrigins === '*') {
|
|
57
107
|
res.header('Access-Control-Allow-Origin', '*');
|
|
58
108
|
}
|
|
59
109
|
else if (origin) {
|
|
60
|
-
const allowedOrigins = corsOrigins.split(',').map(
|
|
110
|
+
const allowedOrigins = corsOrigins.split(',').map((value) => value.trim());
|
|
61
111
|
if (allowedOrigins.includes(origin)) {
|
|
62
112
|
res.header('Access-Control-Allow-Origin', origin);
|
|
63
113
|
}
|
|
@@ -66,7 +116,6 @@ export function createServer(options = {}) {
|
|
|
66
116
|
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-CSRF-Token');
|
|
67
117
|
res.header('Access-Control-Allow-Credentials', 'true');
|
|
68
118
|
res.header('Access-Control-Expose-Headers', 'X-CSRF-Token');
|
|
69
|
-
// Handle preflight requests
|
|
70
119
|
if (req.method === 'OPTIONS') {
|
|
71
120
|
res.sendStatus(204);
|
|
72
121
|
return;
|
|
@@ -74,99 +123,268 @@ export function createServer(options = {}) {
|
|
|
74
123
|
next();
|
|
75
124
|
});
|
|
76
125
|
}
|
|
77
|
-
// Logging middleware
|
|
78
126
|
if (verbose) {
|
|
79
127
|
app.use((req, _res, next) => {
|
|
80
128
|
console.log(`[dashboard] ${req.method} ${req.url}`);
|
|
81
129
|
next();
|
|
82
130
|
});
|
|
83
131
|
}
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
132
|
+
// --- Build shared context ---
|
|
133
|
+
const resolveRelaycastConfig = () => {
|
|
134
|
+
// In-memory key (from option, env var, or dynamic update) takes priority over the file.
|
|
135
|
+
if (inMemoryRelayApiKey) {
|
|
136
|
+
const baseUrl = process.env.RELAYCAST_API_URL || 'https://api.relaycast.dev';
|
|
137
|
+
const projectDir = path.basename(path.resolve(dataDir, '..'));
|
|
138
|
+
return { apiKey: inMemoryRelayApiKey, baseUrl, projectIdentity: projectDir };
|
|
139
|
+
}
|
|
140
|
+
return loadRelaycastConfig(dataDir);
|
|
141
|
+
};
|
|
142
|
+
const setRelayApiKey = (apiKey) => {
|
|
143
|
+
inMemoryRelayApiKey = apiKey.trim();
|
|
144
|
+
};
|
|
145
|
+
const { getSpawnedAgents, getLocalAgentNames } = createSpawnedAgentsCaches({
|
|
146
|
+
brokerProxyEnabled,
|
|
147
|
+
relayUrl,
|
|
148
|
+
dataDir,
|
|
149
|
+
verbose,
|
|
96
150
|
});
|
|
151
|
+
const getRelaycastSnapshot = async () => {
|
|
152
|
+
const config = resolveRelaycastConfig();
|
|
153
|
+
if (!config) {
|
|
154
|
+
return { ...EMPTY_DASHBOARD_SNAPSHOT };
|
|
155
|
+
}
|
|
156
|
+
const [agents, spawnedAgents, localAgentNames] = await Promise.all([
|
|
157
|
+
fetchAgents(config),
|
|
158
|
+
brokerProxyEnabled ? getSpawnedAgents() : Promise.resolve({ names: null, agents: null }),
|
|
159
|
+
brokerProxyEnabled ? Promise.resolve(null) : Promise.resolve(getLocalAgentNames()),
|
|
160
|
+
]);
|
|
161
|
+
const filteredAgents = filterPhantomAgents(agents, spawnedAgents.names, localAgentNames);
|
|
162
|
+
const mergedAgents = mergeBrokerSpawnedAgents(filteredAgents, spawnedAgents.agents);
|
|
163
|
+
return {
|
|
164
|
+
agents: mergedAgents,
|
|
165
|
+
users: [],
|
|
166
|
+
messages: [],
|
|
167
|
+
activity: [],
|
|
168
|
+
sessions: [],
|
|
169
|
+
summaries: [],
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
const getRelaycastChannels = async () => {
|
|
173
|
+
const config = resolveRelaycastConfig();
|
|
174
|
+
if (!config) {
|
|
175
|
+
return { channels: [], archivedChannels: [] };
|
|
176
|
+
}
|
|
177
|
+
const channels = await fetchChannels(config);
|
|
178
|
+
const activeChannels = [];
|
|
179
|
+
const archivedChannels = [];
|
|
180
|
+
for (const channel of channels) {
|
|
181
|
+
const mapped = mapChannelForDashboard({ ...channel, is_archived: channel.is_archived ?? false });
|
|
182
|
+
if (mapped.status === 'archived') {
|
|
183
|
+
archivedChannels.push(mapped);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
activeChannels.push(mapped);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
activeChannels.sort((a, b) => a.name.localeCompare(b.name));
|
|
190
|
+
archivedChannels.sort((a, b) => a.name.localeCompare(b.name));
|
|
191
|
+
return { channels: activeChannels, archivedChannels };
|
|
192
|
+
};
|
|
193
|
+
const sendRelaycastMessage = async (params) => {
|
|
194
|
+
const sendTimeout = Math.max(requestTimeout - 5000, 10000);
|
|
195
|
+
const sendStart = Date.now();
|
|
196
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Send timed out')), sendTimeout));
|
|
197
|
+
try {
|
|
198
|
+
return await Promise.race([
|
|
199
|
+
(async () => {
|
|
200
|
+
const config = resolveRelaycastConfig();
|
|
201
|
+
const rawTarget = params.to.trim();
|
|
202
|
+
const message = params.message.trim();
|
|
203
|
+
let resolvedTarget = rawTarget;
|
|
204
|
+
if (isDirectRecipient(rawTarget) && config) {
|
|
205
|
+
const relayAgents = await fetchAgents(config);
|
|
206
|
+
const relayMatch = relayAgents.find((agent) => normalizeName(agent.name) === normalizeName(rawTarget));
|
|
207
|
+
if (relayMatch) {
|
|
208
|
+
resolvedTarget = relayMatch.name;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const projectIdentity = config?.agentName?.trim()
|
|
212
|
+
|| path.basename(path.resolve(dataDir, '..'))
|
|
213
|
+
|| DASHBOARD_DISPLAY_NAME;
|
|
214
|
+
const senderInput = params.from?.trim() ?? '';
|
|
215
|
+
const senderName = mode === 'proxy'
|
|
216
|
+
? resolveIdentity(senderInput || projectIdentity, {
|
|
217
|
+
projectIdentity: projectIdentity.trim(),
|
|
218
|
+
relayAgentName: config?.agentName?.trim(),
|
|
219
|
+
})
|
|
220
|
+
: (senderInput || projectIdentity);
|
|
221
|
+
const strategy = createSendStrategy({
|
|
222
|
+
brokerProxyEnabled,
|
|
223
|
+
brokerUrl: relayUrl,
|
|
224
|
+
relaycastConfig: config,
|
|
225
|
+
dataDir,
|
|
226
|
+
});
|
|
227
|
+
if (!strategy) {
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
status: 503,
|
|
231
|
+
error: `Relaycast credentials not found in ${path.join(dataDir, 'relaycast.json')}`,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
console.log(`[dashboard] /api/send request: to=${resolvedTarget}, from=${senderName}, relayUrl=${relayUrl}, timeoutMs=${sendTimeout}`);
|
|
235
|
+
const outcome = await strategy.send({
|
|
236
|
+
to: resolvedTarget,
|
|
237
|
+
message,
|
|
238
|
+
from: senderName,
|
|
239
|
+
thread: params.thread,
|
|
240
|
+
});
|
|
241
|
+
console.log(`[dashboard] /api/send completed in ${Date.now() - sendStart}ms with status=${outcome.success ? 200 : outcome.status}`);
|
|
242
|
+
// Enrich "agent not found" errors with available agent names
|
|
243
|
+
if (!outcome.success && isDirectRecipient(params.to) && config) {
|
|
244
|
+
if (/agent\s+\".+\"\s+not\s+found/i.test(outcome.error)) {
|
|
245
|
+
const relayAgents = await fetchAgents(config);
|
|
246
|
+
const available = relayAgents.map((agent) => agent.name).sort();
|
|
247
|
+
const suffix = available.length > 0
|
|
248
|
+
? ` Available relay agents: ${available.join(', ')}.`
|
|
249
|
+
: ' No relay agents are currently online.';
|
|
250
|
+
return {
|
|
251
|
+
success: false,
|
|
252
|
+
status: 404,
|
|
253
|
+
error: `${outcome.error}.${suffix}`,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return outcome;
|
|
258
|
+
})(),
|
|
259
|
+
timeoutPromise,
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
console.error(`[dashboard] /api/send failed after ${Date.now() - sendStart}ms: ${err.message}`);
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
status: 504,
|
|
267
|
+
error: err.message || 'Send request timed out',
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const ctx = {
|
|
272
|
+
mode,
|
|
273
|
+
dataDir,
|
|
274
|
+
staticDir,
|
|
275
|
+
verbose,
|
|
276
|
+
relayUrl,
|
|
277
|
+
brokerProxyEnabled,
|
|
278
|
+
resolveRelaycastConfig,
|
|
279
|
+
setRelayApiKey,
|
|
280
|
+
getRelaycastSnapshot,
|
|
281
|
+
getRelaycastChannels,
|
|
282
|
+
sendRelaycastMessage,
|
|
283
|
+
getSpawnedAgents,
|
|
284
|
+
getLocalAgentNames,
|
|
285
|
+
filterPhantomAgents,
|
|
286
|
+
};
|
|
287
|
+
// --- Register routes ---
|
|
288
|
+
registerHealthRoutes(app, ctx);
|
|
97
289
|
if (mock) {
|
|
98
|
-
|
|
99
|
-
// Register mock API routes for standalone operation
|
|
100
|
-
console.log('[dashboard] Running in MOCK mode - no relay daemon required');
|
|
290
|
+
console.log('[dashboard] Running in MOCK mode - no relay broker required');
|
|
101
291
|
registerMockRoutes(app, verbose);
|
|
102
292
|
}
|
|
103
293
|
else {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
app.use('/api', createProxyMiddleware(apiProxyOptions));
|
|
126
|
-
app.use('/auth', createProxyMiddleware(apiProxyOptions));
|
|
127
|
-
app.use('/metrics', createProxyMiddleware(apiProxyOptions));
|
|
294
|
+
if (mode === 'proxy' && relayUrl) {
|
|
295
|
+
console.log(`[dashboard] Running in PROXY mode - relaycast + broker proxy (${relayUrl})`);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
console.log('[dashboard] Running in STANDALONE mode - relaycast only (read-only broker surface)');
|
|
299
|
+
}
|
|
300
|
+
registerAgentRoutes(app, ctx);
|
|
301
|
+
registerDataRoutes(app, ctx);
|
|
302
|
+
registerRelayConfigRoutes(app, ctx);
|
|
303
|
+
registerChannelRoutes(app, ctx);
|
|
304
|
+
registerReactionRoutes(app, ctx);
|
|
305
|
+
registerThreadReplyRoutes(app, ctx);
|
|
306
|
+
registerMetricsRoutes(app, {
|
|
307
|
+
teamDir: path.join(dataDir, 'team'),
|
|
308
|
+
resolveWorkspaceId,
|
|
309
|
+
});
|
|
310
|
+
registerRelaycastHistoryRoutes(app, ctx);
|
|
311
|
+
registerBrokerProxyRoutes(app, ctx);
|
|
128
312
|
}
|
|
129
|
-
//
|
|
313
|
+
// --- Static files and SPA fallback ---
|
|
314
|
+
const fallbackHtml = `<!doctype html>
|
|
315
|
+
<html lang="en">
|
|
316
|
+
<head>
|
|
317
|
+
<meta charset="utf-8" />
|
|
318
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
319
|
+
<title>Relay Dashboard</title>
|
|
320
|
+
</head>
|
|
321
|
+
<body>
|
|
322
|
+
<h1>Relay Dashboard</h1>
|
|
323
|
+
<p>Dashboard static build not found.</p>
|
|
324
|
+
</body>
|
|
325
|
+
</html>`;
|
|
326
|
+
app.get('/metrics', (_req, res) => {
|
|
327
|
+
const metricsPath = resolveMetricsPagePath(staticDir);
|
|
328
|
+
sendHtmlFileOrFallback(res, metricsPath, fallbackHtml, 200);
|
|
329
|
+
});
|
|
330
|
+
app.get('/app', (_req, res) => {
|
|
331
|
+
const appHtmlPath = path.join(staticDir, 'app.html');
|
|
332
|
+
sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
|
|
333
|
+
});
|
|
334
|
+
app.get('/app/{*path}', (_req, res) => {
|
|
335
|
+
const appHtmlPath = path.join(staticDir, 'app.html');
|
|
336
|
+
sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
|
|
337
|
+
});
|
|
130
338
|
app.use(express.static(staticDir, {
|
|
131
339
|
extensions: ['html'],
|
|
132
340
|
}));
|
|
133
|
-
|
|
134
|
-
|
|
341
|
+
app.get('/', (_req, res) => {
|
|
342
|
+
const indexPath = path.join(staticDir, 'index.html');
|
|
343
|
+
sendHtmlFileOrFallback(res, indexPath, fallbackHtml, 200);
|
|
344
|
+
});
|
|
135
345
|
app.get('/{*path}', (req, res) => {
|
|
136
|
-
//
|
|
346
|
+
// WebSocket endpoints require upgrade - return 426 for regular HTTP requests
|
|
347
|
+
if (req.path === '/ws' || req.path.startsWith('/ws/')) {
|
|
348
|
+
res.status(426).json({ error: 'Upgrade Required', message: 'WebSocket upgrade required' });
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
137
351
|
if (req.path.startsWith('/api') || req.path.startsWith('/auth') || req.path.includes('.')) {
|
|
138
352
|
res.status(404).json({ error: 'Not found' });
|
|
139
353
|
return;
|
|
140
354
|
}
|
|
141
|
-
// For /app/* routes (including /app/channel/*, /app/agent/*, /app/dm/*, /app/settings/*),
|
|
142
|
-
// serve the app.html which handles client-side routing
|
|
143
355
|
if (req.path.startsWith('/app')) {
|
|
144
|
-
|
|
356
|
+
const appHtmlPath = path.join(staticDir, 'app.html');
|
|
357
|
+
sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
|
|
145
358
|
return;
|
|
146
359
|
}
|
|
147
|
-
|
|
148
|
-
res
|
|
360
|
+
const indexPath = path.join(staticDir, 'index.html');
|
|
361
|
+
sendHtmlFileOrFallback(res, indexPath, fallbackHtml, 200);
|
|
149
362
|
});
|
|
150
|
-
// WebSocket
|
|
363
|
+
// --- WebSocket ---
|
|
151
364
|
const wss = new WebSocketServer({ noServer: true });
|
|
152
|
-
// Handle WebSocket upgrade
|
|
153
365
|
server.on('upgrade', (request, socket, head) => {
|
|
154
366
|
const pathname = request.url ? new URL(request.url, `http://${request.headers.host}`).pathname : '';
|
|
155
367
|
if (pathname === '/ws') {
|
|
156
368
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
157
|
-
if (mock) {
|
|
158
|
-
// Mock WebSocket - send periodic updates with fixture data
|
|
369
|
+
if (mode === 'mock') {
|
|
159
370
|
handleMockWebSocket(ws, verbose);
|
|
160
371
|
}
|
|
372
|
+
else if (mode === 'proxy' && relayUrl) {
|
|
373
|
+
handleHybridWebSocket(ws, getRelaycastSnapshot, relayUrl, verbose);
|
|
374
|
+
}
|
|
161
375
|
else {
|
|
162
|
-
|
|
163
|
-
handleProxyWebSocket(ws, relayUrl, verbose);
|
|
376
|
+
handleStandaloneWebSocket(ws, getRelaycastSnapshot, verbose);
|
|
164
377
|
}
|
|
165
378
|
});
|
|
379
|
+
return;
|
|
166
380
|
}
|
|
167
|
-
|
|
168
|
-
|
|
381
|
+
if (mode !== 'mock' && (pathname === '/ws/logs' || pathname.startsWith('/ws/logs/'))) {
|
|
382
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
383
|
+
handleStandaloneLogWebSocket(ws, pathname, dataDir, getLocalAgentNames, verbose);
|
|
384
|
+
});
|
|
385
|
+
return;
|
|
169
386
|
}
|
|
387
|
+
socket.destroy();
|
|
170
388
|
});
|
|
171
389
|
const close = () => {
|
|
172
390
|
return new Promise((resolve) => {
|
|
@@ -177,113 +395,10 @@ export function createServer(options = {}) {
|
|
|
177
395
|
});
|
|
178
396
|
});
|
|
179
397
|
};
|
|
180
|
-
return { app, server, wss, close, mode };
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Handle mock WebSocket connections
|
|
184
|
-
* Sends periodic updates with fixture data
|
|
185
|
-
*/
|
|
186
|
-
function handleMockWebSocket(ws, verbose) {
|
|
187
|
-
if (verbose) {
|
|
188
|
-
console.log('[dashboard] Mock WebSocket client connected');
|
|
189
|
-
}
|
|
190
|
-
// Send initial data
|
|
191
|
-
const sendData = () => {
|
|
192
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
193
|
-
ws.send(JSON.stringify({
|
|
194
|
-
agents: mockAgents,
|
|
195
|
-
messages: mockMessages,
|
|
196
|
-
sessions: mockSessions,
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
// Send initial data immediately
|
|
201
|
-
sendData();
|
|
202
|
-
// Send updates every 5 seconds
|
|
203
|
-
const interval = setInterval(sendData, 5000);
|
|
204
|
-
// Handle messages from client
|
|
205
|
-
ws.on('message', (data) => {
|
|
206
|
-
try {
|
|
207
|
-
const msg = JSON.parse(data.toString());
|
|
208
|
-
if (verbose) {
|
|
209
|
-
console.log('[dashboard] Mock WS received:', msg);
|
|
210
|
-
}
|
|
211
|
-
// Echo back acknowledgment for certain message types
|
|
212
|
-
if (msg.type === 'ping') {
|
|
213
|
-
ws.send(JSON.stringify({ type: 'pong' }));
|
|
214
|
-
}
|
|
215
|
-
else if (msg.type === 'subscribe') {
|
|
216
|
-
// Send current data when client subscribes
|
|
217
|
-
sendData();
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
// Ignore parse errors
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
ws.on('close', () => {
|
|
225
|
-
if (verbose) {
|
|
226
|
-
console.log('[dashboard] Mock WebSocket client disconnected');
|
|
227
|
-
}
|
|
228
|
-
clearInterval(interval);
|
|
229
|
-
});
|
|
230
|
-
ws.on('error', (err) => {
|
|
231
|
-
console.error('[dashboard] Mock WebSocket error:', err.message);
|
|
232
|
-
clearInterval(interval);
|
|
233
|
-
});
|
|
398
|
+
return { app, server, wss, close, mode, setRelayApiKey };
|
|
234
399
|
}
|
|
235
400
|
/**
|
|
236
|
-
*
|
|
237
|
-
* Forwards messages bidirectionally to relay daemon
|
|
238
|
-
*/
|
|
239
|
-
function handleProxyWebSocket(ws, relayUrl, verbose) {
|
|
240
|
-
const relayUrlObj = new URL(relayUrl);
|
|
241
|
-
const wsRelayUrl = `ws://${relayUrlObj.host}`;
|
|
242
|
-
// Create connection to relay daemon
|
|
243
|
-
const relayWs = new WebSocket(`${wsRelayUrl}/ws`);
|
|
244
|
-
relayWs.on('open', () => {
|
|
245
|
-
if (verbose) {
|
|
246
|
-
console.log('[dashboard] WebSocket connected to relay daemon');
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
// Forward messages from client to relay
|
|
250
|
-
ws.on('message', (data) => {
|
|
251
|
-
if (relayWs.readyState === WebSocket.OPEN) {
|
|
252
|
-
relayWs.send(data);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
// Forward messages from relay to client
|
|
256
|
-
relayWs.on('message', (data) => {
|
|
257
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
258
|
-
ws.send(data);
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
// Handle client disconnect
|
|
262
|
-
ws.on('close', () => {
|
|
263
|
-
if (verbose) {
|
|
264
|
-
console.log('[dashboard] Client WebSocket closed');
|
|
265
|
-
}
|
|
266
|
-
relayWs.close();
|
|
267
|
-
});
|
|
268
|
-
// Handle relay disconnect
|
|
269
|
-
relayWs.on('close', () => {
|
|
270
|
-
if (verbose) {
|
|
271
|
-
console.log('[dashboard] Relay WebSocket closed');
|
|
272
|
-
}
|
|
273
|
-
ws.close();
|
|
274
|
-
});
|
|
275
|
-
// Handle errors
|
|
276
|
-
ws.on('error', (err) => {
|
|
277
|
-
console.error('[dashboard] Client WebSocket error:', err.message);
|
|
278
|
-
relayWs.close();
|
|
279
|
-
});
|
|
280
|
-
relayWs.on('error', (err) => {
|
|
281
|
-
console.error('[dashboard] Relay WebSocket error:', err.message);
|
|
282
|
-
ws.close();
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Try to listen on a port, returns the port if successful or null if in use
|
|
401
|
+
* Try to listen on a port, returns the port if successful or null if in use.
|
|
287
402
|
*/
|
|
288
403
|
function tryListen(server, port) {
|
|
289
404
|
return new Promise((resolve) => {
|
|
@@ -310,7 +425,7 @@ function tryListen(server, port) {
|
|
|
310
425
|
});
|
|
311
426
|
}
|
|
312
427
|
/**
|
|
313
|
-
* Find an available port starting from the preferred port
|
|
428
|
+
* Find an available port starting from the preferred port.
|
|
314
429
|
*/
|
|
315
430
|
async function findAvailablePort(server, preferredPort, maxAttempts = 10) {
|
|
316
431
|
for (let i = 0; i < maxAttempts; i++) {
|
|
@@ -319,19 +434,47 @@ async function findAvailablePort(server, preferredPort, maxAttempts = 10) {
|
|
|
319
434
|
if (result !== null) {
|
|
320
435
|
return result;
|
|
321
436
|
}
|
|
322
|
-
// Close and recreate listener for next attempt
|
|
323
437
|
server.close();
|
|
324
438
|
}
|
|
325
439
|
throw new Error(`Could not find available port after ${maxAttempts} attempts starting from ${preferredPort}`);
|
|
326
440
|
}
|
|
327
441
|
/**
|
|
328
|
-
*
|
|
329
|
-
*
|
|
442
|
+
* Bootstrap Relaycast credentials from the broker's authenticated /api/config
|
|
443
|
+
* endpoint. The workspace key is on an authenticated route (not /health) so it
|
|
444
|
+
* is not exposed to unauthenticated callers.
|
|
445
|
+
*/
|
|
446
|
+
async function bootstrapRelayApiKeyFromBroker(relayUrl, setRelayApiKey) {
|
|
447
|
+
const brokerApiKey = process.env.RELAY_BROKER_API_KEY?.trim();
|
|
448
|
+
const headers = {};
|
|
449
|
+
if (brokerApiKey) {
|
|
450
|
+
headers['x-api-key'] = brokerApiKey;
|
|
451
|
+
}
|
|
452
|
+
// Retry a few times to allow the broker to fully start up.
|
|
453
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
454
|
+
try {
|
|
455
|
+
const res = await fetch(`${relayUrl}/api/config`, { headers });
|
|
456
|
+
if (!res.ok)
|
|
457
|
+
break;
|
|
458
|
+
const json = await res.json();
|
|
459
|
+
const key = typeof json.workspaceKey === 'string' ? json.workspaceKey.trim() : '';
|
|
460
|
+
if (key) {
|
|
461
|
+
setRelayApiKey(key);
|
|
462
|
+
console.log('[dashboard] Relaycast workspace key bootstrapped from broker');
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
// Broker not yet ready — wait and retry.
|
|
468
|
+
}
|
|
469
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Start the dashboard server.
|
|
330
474
|
*/
|
|
331
475
|
export async function startServer(options = {}) {
|
|
332
476
|
const preferredPort = options.port || parseInt(process.env.PORT || '3888', 10);
|
|
333
477
|
const dashboard = createServer(options);
|
|
334
|
-
// Try preferred port first, then search for available port
|
|
335
478
|
const actualPort = await findAvailablePort(dashboard.server, preferredPort);
|
|
336
479
|
if (actualPort !== preferredPort) {
|
|
337
480
|
console.log(`[dashboard] Port ${preferredPort} in use, using port ${actualPort}`);
|
|
@@ -340,8 +483,17 @@ export async function startServer(options = {}) {
|
|
|
340
483
|
if (dashboard.mode === 'mock') {
|
|
341
484
|
console.log('[dashboard] Using mock data - ready for standalone testing');
|
|
342
485
|
}
|
|
486
|
+
else if (dashboard.mode === 'proxy') {
|
|
487
|
+
console.log(`[dashboard] Proxy mode enabled - broker URL ${normalizeRelayUrl(options.relayUrl ?? process.env.RELAY_URL)}`);
|
|
488
|
+
}
|
|
343
489
|
else {
|
|
344
|
-
console.log(
|
|
490
|
+
console.log('[dashboard] Standalone mode enabled - relaycast data only');
|
|
491
|
+
}
|
|
492
|
+
// Best-effort: fetch workspace key from the broker health endpoint so the
|
|
493
|
+
// dashboard uses the same Relaycast workspace as the broker (no relaycast.json needed).
|
|
494
|
+
const resolvedRelayUrl = normalizeRelayUrl(options.relayUrl ?? process.env.RELAY_URL);
|
|
495
|
+
if (resolvedRelayUrl && !options.mock) {
|
|
496
|
+
bootstrapRelayApiKeyFromBroker(resolvedRelayUrl, dashboard.setRelayApiKey).catch(() => { });
|
|
345
497
|
}
|
|
346
498
|
return dashboard;
|
|
347
499
|
}
|