agent-relay 1.1.0 → 1.2.3
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/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
- package/.trajectories/index.json +314 -0
- package/ARCHITECTURE.md +1245 -0
- package/README.md +1 -1
- package/TESTING.md +278 -0
- package/deploy/init-db.sql +5 -0
- package/deploy/scripts/setup-fly-workspaces.sh +69 -0
- package/deploy/scripts/setup-railway.sh +75 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +348 -0
- package/deploy/workspace/git-credential-relay +111 -0
- package/dist/bridge/spawner.d.ts +53 -0
- package/dist/bridge/spawner.js +203 -19
- package/dist/bridge/types.d.ts +12 -0
- package/dist/cli/index.js +618 -5
- package/dist/cloud/api/auth.d.ts +3 -2
- package/dist/cloud/api/auth.js +10 -98
- package/dist/cloud/api/billing.js +30 -9
- package/dist/cloud/api/cli-pty-runner.d.ts +54 -0
- package/dist/cloud/api/cli-pty-runner.js +119 -0
- package/dist/cloud/api/codex-auth-helper.d.ts +15 -0
- package/dist/cloud/api/codex-auth-helper.js +100 -0
- package/dist/cloud/api/generic-webhooks.d.ts +8 -0
- package/dist/cloud/api/generic-webhooks.js +129 -0
- package/dist/cloud/api/git.d.ts +8 -0
- package/dist/cloud/api/git.js +152 -0
- package/dist/cloud/api/github-app.d.ts +11 -0
- package/dist/cloud/api/github-app.js +189 -0
- package/dist/cloud/api/middleware/planLimits.d.ts +7 -0
- package/dist/cloud/api/middleware/planLimits.js +39 -1
- package/dist/cloud/api/monitoring.d.ts +11 -0
- package/dist/cloud/api/monitoring.js +578 -0
- package/dist/cloud/api/nango-auth.d.ts +9 -0
- package/dist/cloud/api/nango-auth.js +377 -0
- package/dist/cloud/api/onboarding.d.ts +8 -1
- package/dist/cloud/api/onboarding.js +313 -119
- package/dist/cloud/api/policy.d.ts +8 -0
- package/dist/cloud/api/policy.js +229 -0
- package/dist/cloud/api/providers.js +114 -42
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +186 -0
- package/dist/cloud/api/test-helpers.d.ts +10 -0
- package/dist/cloud/api/test-helpers.js +575 -0
- package/dist/cloud/api/webhooks.d.ts +8 -0
- package/dist/cloud/api/webhooks.js +645 -0
- package/dist/cloud/api/workspaces.js +320 -12
- package/dist/cloud/billing/plans.js +32 -19
- package/dist/cloud/billing/types.d.ts +9 -3
- package/dist/cloud/config.d.ts +9 -2
- package/dist/cloud/config.js +13 -4
- package/dist/cloud/db/drizzle.d.ts +84 -1
- package/dist/cloud/db/drizzle.js +470 -0
- package/dist/cloud/db/index.d.ts +9 -4
- package/dist/cloud/db/index.js +11 -3
- package/dist/cloud/db/schema.d.ts +3283 -556
- package/dist/cloud/db/schema.js +314 -1
- package/dist/cloud/index.d.ts +1 -0
- package/dist/cloud/index.js +2 -0
- package/dist/cloud/provisioner/index.d.ts +56 -0
- package/dist/cloud/provisioner/index.js +676 -34
- package/dist/cloud/server.d.ts +1 -0
- package/dist/cloud/server.js +362 -13
- package/dist/cloud/services/auto-scaler.d.ts +152 -0
- package/dist/cloud/services/auto-scaler.js +439 -0
- package/dist/cloud/services/capacity-manager.d.ts +148 -0
- package/dist/cloud/services/capacity-manager.js +449 -0
- package/dist/cloud/services/ci-agent-spawner.d.ts +49 -0
- package/dist/cloud/services/ci-agent-spawner.js +373 -0
- package/dist/cloud/services/index.d.ts +12 -0
- package/dist/cloud/services/index.js +15 -0
- package/dist/cloud/services/mention-handler.d.ts +65 -0
- package/dist/cloud/services/mention-handler.js +405 -0
- package/dist/cloud/services/nango.d.ts +186 -0
- package/dist/cloud/services/nango.js +344 -0
- package/dist/cloud/services/persistence.d.ts +131 -0
- package/dist/cloud/services/persistence.js +200 -0
- package/dist/cloud/services/planLimits.d.ts +37 -0
- package/dist/cloud/services/planLimits.js +86 -5
- package/dist/cloud/services/scaling-orchestrator.d.ts +159 -0
- package/dist/cloud/services/scaling-orchestrator.js +502 -0
- package/dist/cloud/services/scaling-policy.d.ts +121 -0
- package/dist/cloud/services/scaling-policy.js +415 -0
- package/dist/cloud/vault/index.js +1 -1
- package/dist/cloud/webhooks/index.d.ts +24 -0
- package/dist/cloud/webhooks/index.js +29 -0
- package/dist/cloud/webhooks/parsers/github.d.ts +8 -0
- package/dist/cloud/webhooks/parsers/github.js +234 -0
- package/dist/cloud/webhooks/parsers/index.d.ts +23 -0
- package/dist/cloud/webhooks/parsers/index.js +30 -0
- package/dist/cloud/webhooks/parsers/linear.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/linear.js +258 -0
- package/dist/cloud/webhooks/parsers/slack.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/slack.js +214 -0
- package/dist/cloud/webhooks/responders/github.d.ts +8 -0
- package/dist/cloud/webhooks/responders/github.js +73 -0
- package/dist/cloud/webhooks/responders/index.d.ts +23 -0
- package/dist/cloud/webhooks/responders/index.js +30 -0
- package/dist/cloud/webhooks/responders/linear.d.ts +9 -0
- package/dist/cloud/webhooks/responders/linear.js +149 -0
- package/dist/cloud/webhooks/responders/slack.d.ts +20 -0
- package/dist/cloud/webhooks/responders/slack.js +178 -0
- package/dist/cloud/webhooks/router.d.ts +25 -0
- package/dist/cloud/webhooks/router.js +504 -0
- package/dist/cloud/webhooks/rules-engine.d.ts +24 -0
- package/dist/cloud/webhooks/rules-engine.js +287 -0
- package/dist/cloud/webhooks/types.d.ts +186 -0
- package/dist/cloud/webhooks/types.js +8 -0
- package/dist/continuity/formatter.d.ts +51 -0
- package/dist/continuity/formatter.js +313 -0
- package/dist/continuity/handoff-store.d.ts +67 -0
- package/dist/continuity/handoff-store.js +472 -0
- package/dist/continuity/index.d.ts +45 -0
- package/dist/continuity/index.js +48 -0
- package/dist/continuity/ledger-store.d.ts +110 -0
- package/dist/continuity/ledger-store.js +500 -0
- package/dist/continuity/manager.d.ts +178 -0
- package/dist/continuity/manager.js +562 -0
- package/dist/continuity/parser.d.ts +76 -0
- package/dist/continuity/parser.js +579 -0
- package/dist/continuity/types.d.ts +180 -0
- package/dist/continuity/types.js +9 -0
- package/dist/daemon/agent-manager.d.ts +27 -0
- package/dist/daemon/agent-manager.js +107 -6
- package/dist/daemon/agent-registry.d.ts +32 -0
- package/dist/daemon/agent-registry.js +42 -2
- package/dist/daemon/api.d.ts +12 -0
- package/dist/daemon/api.js +131 -2
- package/dist/daemon/cli-auth.d.ts +67 -0
- package/dist/daemon/cli-auth.js +537 -0
- package/dist/daemon/cloud-sync.js +9 -7
- package/dist/daemon/orchestrator.js +30 -0
- package/dist/daemon/router.d.ts +5 -0
- package/dist/daemon/router.js +78 -26
- package/dist/daemon/server.d.ts +5 -0
- package/dist/daemon/server.js +9 -1
- package/dist/daemon/services/browser-testing.d.ts +88 -0
- package/dist/daemon/services/browser-testing.js +244 -0
- package/dist/daemon/services/container-spawner.d.ts +135 -0
- package/dist/daemon/services/container-spawner.js +313 -0
- package/dist/daemon/types.d.ts +5 -1
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-3fdfa60e53f2810d.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-3538dfe0ffe984b8.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/{page-b6edd4dde8d08194.js → page-abb9ab2d329f56e9.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-c22d080201cbd9fb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-77e9c65420a06cfb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-b08ed1c34d14434a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-68d34f50baa8ab6b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
- package/dist/dashboard/out/_next/static/chunks/{main-app-5d692157a8eb1fd9.js → main-app-6e8e8d3ef4e0192a.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-c2f423b9c9f4591b.js → main-ed4e1fb6f29c34cf.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +1 -0
- package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -0
- package/dist/dashboard/out/app/onboarding.txt +7 -0
- package/dist/dashboard/out/app.html +1 -14
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/connect-repos.html +1 -0
- package/dist/dashboard/out/connect-repos.txt +7 -0
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +2 -2
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +6 -0
- package/dist/dashboard/out/login.txt +7 -0
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +2 -2
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +2 -2
- package/dist/dashboard/out/providers.html +1 -0
- package/dist/dashboard/out/providers.txt +7 -0
- package/dist/dashboard/out/signup.html +6 -0
- package/dist/dashboard/out/signup.txt +7 -0
- package/dist/dashboard-server/server.js +1308 -8
- package/dist/hooks/emitter.d.ts +40 -0
- package/dist/hooks/emitter.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/registry.d.ts +173 -0
- package/dist/hooks/registry.js +476 -0
- package/dist/hooks/trajectory-hooks.d.ts +52 -0
- package/dist/hooks/trajectory-hooks.js +183 -0
- package/dist/hooks/types.d.ts +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/memory/adapters/index.d.ts +8 -0
- package/dist/memory/adapters/index.js +8 -0
- package/dist/memory/adapters/inmemory.d.ts +59 -0
- package/dist/memory/adapters/inmemory.js +195 -0
- package/dist/memory/adapters/supermemory.d.ts +71 -0
- package/dist/memory/adapters/supermemory.js +338 -0
- package/dist/memory/factory.d.ts +48 -0
- package/dist/memory/factory.js +143 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.js +32 -0
- package/dist/memory/memory-hooks.d.ts +60 -0
- package/dist/memory/memory-hooks.js +313 -0
- package/dist/memory/service.d.ts +49 -0
- package/dist/memory/service.js +146 -0
- package/dist/memory/types.d.ts +195 -0
- package/dist/memory/types.js +8 -0
- package/dist/policy/agent-policy.d.ts +225 -0
- package/dist/policy/agent-policy.js +665 -0
- package/dist/policy/cloud-policy-fetcher.d.ts +12 -0
- package/dist/policy/cloud-policy-fetcher.js +64 -0
- package/dist/resiliency/crash-insights.d.ts +156 -0
- package/dist/resiliency/crash-insights.js +492 -0
- package/dist/resiliency/gossip-health.d.ts +137 -0
- package/dist/resiliency/gossip-health.js +241 -0
- package/dist/resiliency/index.d.ts +5 -0
- package/dist/resiliency/index.js +5 -0
- package/dist/resiliency/leader-watchdog.d.ts +109 -0
- package/dist/resiliency/leader-watchdog.js +189 -0
- package/dist/resiliency/memory-monitor.d.ts +172 -0
- package/dist/resiliency/memory-monitor.js +593 -0
- package/dist/resiliency/stateless-lead.d.ts +149 -0
- package/dist/resiliency/stateless-lead.js +308 -0
- package/dist/resiliency/supervisor.d.ts +38 -0
- package/dist/resiliency/supervisor.js +122 -0
- package/dist/shared/cli-auth-config.d.ts +91 -0
- package/dist/shared/cli-auth-config.js +264 -0
- package/dist/storage/adapter.d.ts +1 -1
- package/dist/trajectory/config.d.ts +84 -0
- package/dist/trajectory/config.js +163 -0
- package/dist/trajectory/index.d.ts +8 -0
- package/dist/trajectory/index.js +8 -0
- package/dist/trajectory/integration.d.ts +292 -0
- package/dist/trajectory/integration.js +834 -0
- package/dist/utils/logger.js +1 -1
- package/dist/utils/project-namespace.d.ts +24 -0
- package/dist/utils/project-namespace.js +84 -0
- package/dist/wrapper/parser.d.ts +10 -0
- package/dist/wrapper/parser.js +100 -33
- package/dist/wrapper/pty-wrapper.d.ts +197 -16
- package/dist/wrapper/pty-wrapper.js +943 -106
- package/dist/wrapper/shared.d.ts +165 -0
- package/dist/wrapper/shared.js +270 -0
- package/dist/wrapper/tmux-wrapper.d.ts +73 -11
- package/dist/wrapper/tmux-wrapper.js +541 -120
- package/package.json +16 -16
- package/scripts/postinstall.js +60 -0
- package/test-push.txt +1 -0
- package/bin/tmux +0 -0
- package/dist/bridge/config.d.ts.map +0 -1
- package/dist/bridge/config.js.map +0 -1
- package/dist/bridge/index.d.ts.map +0 -1
- package/dist/bridge/index.js.map +0 -1
- package/dist/bridge/multi-project-client.d.ts.map +0 -1
- package/dist/bridge/multi-project-client.js.map +0 -1
- package/dist/bridge/shadow-cli.d.ts.map +0 -1
- package/dist/bridge/shadow-cli.js.map +0 -1
- package/dist/bridge/shadow-config.d.ts.map +0 -1
- package/dist/bridge/shadow-config.js.map +0 -1
- package/dist/bridge/spawner.d.ts.map +0 -1
- package/dist/bridge/spawner.js.map +0 -1
- package/dist/bridge/teams-config.d.ts.map +0 -1
- package/dist/bridge/teams-config.js.map +0 -1
- package/dist/bridge/types.d.ts.map +0 -1
- package/dist/bridge/types.js.map +0 -1
- package/dist/bridge/utils.d.ts.map +0 -1
- package/dist/bridge/utils.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cloud/api/auth.d.ts.map +0 -1
- package/dist/cloud/api/auth.js.map +0 -1
- package/dist/cloud/api/billing.d.ts.map +0 -1
- package/dist/cloud/api/billing.js.map +0 -1
- package/dist/cloud/api/coordinators.d.ts.map +0 -1
- package/dist/cloud/api/coordinators.js.map +0 -1
- package/dist/cloud/api/daemons.d.ts.map +0 -1
- package/dist/cloud/api/daemons.js.map +0 -1
- package/dist/cloud/api/middleware/planLimits.d.ts.map +0 -1
- package/dist/cloud/api/middleware/planLimits.js.map +0 -1
- package/dist/cloud/api/onboarding.d.ts.map +0 -1
- package/dist/cloud/api/onboarding.js.map +0 -1
- package/dist/cloud/api/providers.d.ts.map +0 -1
- package/dist/cloud/api/providers.js.map +0 -1
- package/dist/cloud/api/repos.d.ts.map +0 -1
- package/dist/cloud/api/repos.js.map +0 -1
- package/dist/cloud/api/teams.d.ts.map +0 -1
- package/dist/cloud/api/teams.js.map +0 -1
- package/dist/cloud/api/usage.d.ts.map +0 -1
- package/dist/cloud/api/usage.js.map +0 -1
- package/dist/cloud/api/workspaces.d.ts.map +0 -1
- package/dist/cloud/api/workspaces.js.map +0 -1
- package/dist/cloud/billing/index.d.ts.map +0 -1
- package/dist/cloud/billing/index.js.map +0 -1
- package/dist/cloud/billing/plans.d.ts.map +0 -1
- package/dist/cloud/billing/plans.js.map +0 -1
- package/dist/cloud/billing/service.d.ts.map +0 -1
- package/dist/cloud/billing/service.js.map +0 -1
- package/dist/cloud/billing/types.d.ts.map +0 -1
- package/dist/cloud/billing/types.js.map +0 -1
- package/dist/cloud/config.d.ts.map +0 -1
- package/dist/cloud/config.js.map +0 -1
- package/dist/cloud/db/drizzle.d.ts.map +0 -1
- package/dist/cloud/db/drizzle.js.map +0 -1
- package/dist/cloud/db/index.d.ts.map +0 -1
- package/dist/cloud/db/index.js.map +0 -1
- package/dist/cloud/db/schema.d.ts.map +0 -1
- package/dist/cloud/db/schema.js.map +0 -1
- package/dist/cloud/index.d.ts.map +0 -1
- package/dist/cloud/index.js.map +0 -1
- package/dist/cloud/provisioner/index.d.ts.map +0 -1
- package/dist/cloud/provisioner/index.js.map +0 -1
- package/dist/cloud/server.d.ts.map +0 -1
- package/dist/cloud/server.js.map +0 -1
- package/dist/cloud/services/coordinator.d.ts.map +0 -1
- package/dist/cloud/services/coordinator.js.map +0 -1
- package/dist/cloud/services/planLimits.d.ts.map +0 -1
- package/dist/cloud/services/planLimits.js.map +0 -1
- package/dist/cloud/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.js.map +0 -1
- package/dist/daemon/agent-manager.d.ts.map +0 -1
- package/dist/daemon/agent-manager.js.map +0 -1
- package/dist/daemon/agent-registry.d.ts.map +0 -1
- package/dist/daemon/agent-registry.js.map +0 -1
- package/dist/daemon/api.d.ts.map +0 -1
- package/dist/daemon/api.js.map +0 -1
- package/dist/daemon/auth.d.ts.map +0 -1
- package/dist/daemon/auth.js.map +0 -1
- package/dist/daemon/cloud-sync.d.ts.map +0 -1
- package/dist/daemon/cloud-sync.js.map +0 -1
- package/dist/daemon/connection.d.ts.map +0 -1
- package/dist/daemon/connection.js.map +0 -1
- package/dist/daemon/index.d.ts.map +0 -1
- package/dist/daemon/index.js.map +0 -1
- package/dist/daemon/orchestrator.d.ts.map +0 -1
- package/dist/daemon/orchestrator.js.map +0 -1
- package/dist/daemon/registry.d.ts.map +0 -1
- package/dist/daemon/registry.js.map +0 -1
- package/dist/daemon/router.d.ts.map +0 -1
- package/dist/daemon/router.js.map +0 -1
- package/dist/daemon/server.d.ts.map +0 -1
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/workspace-manager.d.ts.map +0 -1
- package/dist/daemon/workspace-manager.js.map +0 -1
- package/dist/dashboard/out/_next/static/chunks/693-7b3301d8f6bc5014.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/713-f78477eb185f1f4d.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/766-e53e1cfe39b0b5b5.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/900-037c64bfd797fb2a.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e3d9e1f4466b9bae.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-e68825a81db67ba1.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/page-cc108bf68c8a657f.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-d80e03a5297f95b6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-a5acc2831d094776.js +0 -1
- package/dist/dashboard/out/_next/static/css/79b80143647a07d7.css +0 -1
- package/dist/dashboard/out/_next/static/css/8cf277370ad48cfe.css +0 -1
- package/dist/dashboard-server/metrics.d.ts.map +0 -1
- package/dist/dashboard-server/metrics.js.map +0 -1
- package/dist/dashboard-server/needs-attention.d.ts.map +0 -1
- package/dist/dashboard-server/needs-attention.js.map +0 -1
- package/dist/dashboard-server/server.d.ts.map +0 -1
- package/dist/dashboard-server/server.js.map +0 -1
- package/dist/dashboard-server/start.d.ts.map +0 -1
- package/dist/dashboard-server/start.js.map +0 -1
- package/dist/hooks/inbox-check/hook.d.ts.map +0 -1
- package/dist/hooks/inbox-check/hook.js.map +0 -1
- package/dist/hooks/inbox-check/index.d.ts.map +0 -1
- package/dist/hooks/inbox-check/index.js.map +0 -1
- package/dist/hooks/inbox-check/types.d.ts.map +0 -1
- package/dist/hooks/inbox-check/types.js.map +0 -1
- package/dist/hooks/inbox-check/utils.d.ts.map +0 -1
- package/dist/hooks/inbox-check/utils.js.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/protocol/framing.d.ts.map +0 -1
- package/dist/protocol/framing.js.map +0 -1
- package/dist/protocol/index.d.ts.map +0 -1
- package/dist/protocol/index.js.map +0 -1
- package/dist/protocol/types.d.ts.map +0 -1
- package/dist/protocol/types.js.map +0 -1
- package/dist/resiliency/context-persistence.d.ts.map +0 -1
- package/dist/resiliency/context-persistence.js.map +0 -1
- package/dist/resiliency/health-monitor.d.ts.map +0 -1
- package/dist/resiliency/health-monitor.js.map +0 -1
- package/dist/resiliency/index.d.ts.map +0 -1
- package/dist/resiliency/index.js.map +0 -1
- package/dist/resiliency/logger.d.ts.map +0 -1
- package/dist/resiliency/logger.js.map +0 -1
- package/dist/resiliency/metrics.d.ts.map +0 -1
- package/dist/resiliency/metrics.js.map +0 -1
- package/dist/resiliency/provider-context.d.ts.map +0 -1
- package/dist/resiliency/provider-context.js.map +0 -1
- package/dist/resiliency/supervisor.d.ts.map +0 -1
- package/dist/resiliency/supervisor.js.map +0 -1
- package/dist/state/agent-state.d.ts.map +0 -1
- package/dist/state/agent-state.js.map +0 -1
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/sqlite-adapter.d.ts.map +0 -1
- package/dist/storage/sqlite-adapter.js.map +0 -1
- package/dist/utils/agent-config.d.ts.map +0 -1
- package/dist/utils/agent-config.js.map +0 -1
- package/dist/utils/command-resolver.d.ts.map +0 -1
- package/dist/utils/command-resolver.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/name-generator.d.ts.map +0 -1
- package/dist/utils/name-generator.js.map +0 -1
- package/dist/utils/project-namespace.d.ts.map +0 -1
- package/dist/utils/project-namespace.js.map +0 -1
- package/dist/utils/tmux-resolver.d.ts.map +0 -1
- package/dist/utils/tmux-resolver.js.map +0 -1
- package/dist/utils/update-checker.d.ts.map +0 -1
- package/dist/utils/update-checker.js.map +0 -1
- package/dist/wrapper/client.d.ts.map +0 -1
- package/dist/wrapper/client.js.map +0 -1
- package/dist/wrapper/inbox.d.ts.map +0 -1
- package/dist/wrapper/inbox.js.map +0 -1
- package/dist/wrapper/index.d.ts.map +0 -1
- package/dist/wrapper/index.js.map +0 -1
- package/dist/wrapper/parser.d.ts.map +0 -1
- package/dist/wrapper/parser.js.map +0 -1
- package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
- package/dist/wrapper/pty-wrapper.js.map +0 -1
- package/dist/wrapper/tmux-wrapper.d.ts.map +0 -1
- package/dist/wrapper/tmux-wrapper.js.map +0 -1
- package/docs/AGENTS.md +0 -513
- package/docs/ARCHITECTURE_DECISIONS.md +0 -175
- package/docs/CHANGELOG.md +0 -11
- package/docs/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
- package/docs/CLOUD-ARCHITECTURE.md +0 -652
- package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
- package/docs/COMPETITIVE_ANALYSIS.md +0 -897
- package/docs/CONTRIBUTING.md +0 -151
- package/docs/DESIGN_BRIDGE_STAFFING.md +0 -878
- package/docs/DESIGN_V2.md +0 -1079
- package/docs/INTEGRATION-GUIDE.md +0 -926
- package/docs/MONETIZATION.md +0 -1679
- package/docs/PROPOSAL-trajectories.md +0 -1582
- package/docs/PROTOCOL.md +0 -325
- package/docs/SCALING_ANALYSIS.md +0 -280
- package/docs/TESTING_PRESENCE_FEATURES.md +0 -327
- package/docs/TMUX_IMPLEMENTATION_NOTES.md +0 -364
- package/docs/TMUX_IMPROVEMENTS.md +0 -968
- package/docs/agent-relay-snippet.md +0 -168
- package/docs/competitive-analysis-mcp-agent-mail.md +0 -389
- package/docs/dashboard-v2-plan.md +0 -179
- package/docs/guides/CLOUD.md +0 -236
- package/docs/guides/LOCAL.md +0 -535
- package/docs/guides/SELF-HOSTED.md +0 -494
- package/docs/proposals/shadow-as-subagent.md +0 -765
- package/docs/proposals/slack-bot-integration.md +0 -1457
- package/docs/removable-code-analysis.md +0 -24
- package/scripts/dev/PUBLIC_RELEASE_PLAN.md +0 -88
- package/scripts/dev/dev-team-setup.sh +0 -431
- package/scripts/e2e-test.sh +0 -119
- package/scripts/games/game-protocol.md +0 -79
- package/scripts/games/hearts-setup.sh +0 -264
- package/scripts/tictactoe-setup.sh +0 -181
- /package/dist/dashboard/out/_next/static/chunks/{117-b2cd8d6485aacf2b.js → 117-f7b8ab0809342e77.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-8f3f26864ce515e5.js → 648-5cc6e1921389a58a.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-0b990dbb71d72a98.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_ssgManifest.js +0 -0
package/dist/cloud/server.d.ts
CHANGED
package/dist/cloud/server.js
CHANGED
|
@@ -7,14 +7,18 @@ import cors from 'cors';
|
|
|
7
7
|
import helmet from 'helmet';
|
|
8
8
|
import crypto from 'crypto';
|
|
9
9
|
import path from 'node:path';
|
|
10
|
+
import http from 'node:http';
|
|
10
11
|
import { fileURLToPath } from 'node:url';
|
|
11
12
|
import { createClient } from 'redis';
|
|
12
13
|
import { RedisStore } from 'connect-redis';
|
|
14
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
13
15
|
import { getConfig } from './config.js';
|
|
16
|
+
import { runMigrations } from './db/index.js';
|
|
17
|
+
import { getScalingOrchestrator } from './services/index.js';
|
|
14
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
19
|
const __dirname = path.dirname(__filename);
|
|
16
20
|
// API routers
|
|
17
|
-
import { authRouter } from './api/auth.js';
|
|
21
|
+
import { authRouter, requireAuth } from './api/auth.js';
|
|
18
22
|
import { providersRouter } from './api/providers.js';
|
|
19
23
|
import { workspacesRouter } from './api/workspaces.js';
|
|
20
24
|
import { reposRouter } from './api/repos.js';
|
|
@@ -23,6 +27,43 @@ import { teamsRouter } from './api/teams.js';
|
|
|
23
27
|
import { billingRouter } from './api/billing.js';
|
|
24
28
|
import { usageRouter } from './api/usage.js';
|
|
25
29
|
import { coordinatorsRouter } from './api/coordinators.js';
|
|
30
|
+
import { daemonsRouter } from './api/daemons.js';
|
|
31
|
+
import { monitoringRouter } from './api/monitoring.js';
|
|
32
|
+
import { testHelpersRouter } from './api/test-helpers.js';
|
|
33
|
+
import { webhooksRouter } from './api/webhooks.js';
|
|
34
|
+
import { githubAppRouter } from './api/github-app.js';
|
|
35
|
+
import { nangoAuthRouter } from './api/nango-auth.js';
|
|
36
|
+
import { gitRouter } from './api/git.js';
|
|
37
|
+
import { codexAuthHelperRouter } from './api/codex-auth-helper.js';
|
|
38
|
+
import { db } from './db/index.js';
|
|
39
|
+
/**
|
|
40
|
+
* Proxy a request to the user's primary running workspace
|
|
41
|
+
*/
|
|
42
|
+
async function proxyToUserWorkspace(req, res, path) {
|
|
43
|
+
const userId = req.session.userId;
|
|
44
|
+
if (!userId) {
|
|
45
|
+
res.status(401).json({ error: 'Unauthorized' });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
// Find user's running workspace
|
|
50
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
51
|
+
const runningWorkspace = workspaces.find(w => w.status === 'running' && w.publicUrl);
|
|
52
|
+
if (!runningWorkspace || !runningWorkspace.publicUrl) {
|
|
53
|
+
res.status(404).json({ error: 'No running workspace found', success: false });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Proxy to workspace
|
|
57
|
+
const targetUrl = `${runningWorkspace.publicUrl}${path}`;
|
|
58
|
+
const proxyRes = await fetch(targetUrl);
|
|
59
|
+
const data = await proxyRes.json();
|
|
60
|
+
res.status(proxyRes.status).json(data);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('[trajectory-proxy] Error:', error);
|
|
64
|
+
res.status(500).json({ error: 'Failed to proxy request to workspace', success: false });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
26
67
|
export async function createServer() {
|
|
27
68
|
const config = getConfig();
|
|
28
69
|
const app = express();
|
|
@@ -37,16 +78,19 @@ export async function createServer() {
|
|
|
37
78
|
});
|
|
38
79
|
await redisClient.connect();
|
|
39
80
|
// Middleware
|
|
40
|
-
// Configure helmet to allow Next.js inline scripts
|
|
81
|
+
// Configure helmet to allow Next.js inline scripts and Nango Connect UI
|
|
41
82
|
app.use(helmet({
|
|
42
83
|
contentSecurityPolicy: {
|
|
43
84
|
directives: {
|
|
44
85
|
defaultSrc: ["'self'"],
|
|
45
|
-
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
|
|
46
|
-
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
|
|
47
|
-
fontSrc: ["'self'", "https://fonts.gstatic.com"],
|
|
48
|
-
imgSrc: ["'self'", "data:", "https:"],
|
|
49
|
-
connectSrc: ["'self'", "wss:", "ws:", "https:"],
|
|
86
|
+
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://connect.nango.dev"],
|
|
87
|
+
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com", "https://connect.nango.dev"],
|
|
88
|
+
fontSrc: ["'self'", "https://fonts.gstatic.com", "data:"],
|
|
89
|
+
imgSrc: ["'self'", "data:", "https:", "blob:"],
|
|
90
|
+
connectSrc: ["'self'", "wss:", "ws:", "https:", "https://api.nango.dev", "https://connect.nango.dev"],
|
|
91
|
+
frameSrc: ["'self'", "https://connect.nango.dev", "https://github.com"],
|
|
92
|
+
childSrc: ["'self'", "https://connect.nango.dev", "blob:"],
|
|
93
|
+
workerSrc: ["'self'", "blob:"],
|
|
50
94
|
},
|
|
51
95
|
},
|
|
52
96
|
}));
|
|
@@ -54,7 +98,15 @@ export async function createServer() {
|
|
|
54
98
|
origin: config.publicUrl,
|
|
55
99
|
credentials: true,
|
|
56
100
|
}));
|
|
57
|
-
|
|
101
|
+
// Custom JSON parser that preserves raw body for webhook signature verification
|
|
102
|
+
// Increase limit to 10mb for base64 image uploads (screenshots)
|
|
103
|
+
app.use(express.json({
|
|
104
|
+
limit: '10mb',
|
|
105
|
+
verify: (req, _res, buf) => {
|
|
106
|
+
// Store raw body for webhook signature verification
|
|
107
|
+
req.rawBody = buf.toString();
|
|
108
|
+
},
|
|
109
|
+
}));
|
|
58
110
|
// Session middleware
|
|
59
111
|
app.use(session({
|
|
60
112
|
store: new RedisStore({ client: redisClient }),
|
|
@@ -80,9 +132,17 @@ export async function createServer() {
|
|
|
80
132
|
});
|
|
81
133
|
// Simple in-memory rate limiting per IP
|
|
82
134
|
const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
83
|
-
|
|
135
|
+
// Higher limit in development mode
|
|
136
|
+
const RATE_LIMIT_MAX = process.env.NODE_ENV === 'development' ? 1000 : 300;
|
|
84
137
|
const rateLimits = new Map();
|
|
85
138
|
app.use((req, res, next) => {
|
|
139
|
+
// Skip rate limiting for localhost in development
|
|
140
|
+
if (process.env.NODE_ENV === 'development') {
|
|
141
|
+
const ip = req.ip || '';
|
|
142
|
+
if (ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1') {
|
|
143
|
+
return next();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
86
146
|
const now = Date.now();
|
|
87
147
|
const key = req.ip || 'unknown';
|
|
88
148
|
const entry = rateLimits.get(key);
|
|
@@ -111,18 +171,49 @@ export async function createServer() {
|
|
|
111
171
|
});
|
|
112
172
|
// Lightweight CSRF protection using session token
|
|
113
173
|
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
174
|
+
// Paths exempt from CSRF (webhooks from external services, workspace proxy, local auth callbacks)
|
|
175
|
+
const CSRF_EXEMPT_PATHS = [
|
|
176
|
+
'/api/webhooks/',
|
|
177
|
+
'/api/auth/nango/webhook',
|
|
178
|
+
'/api/auth/codex-helper/callback',
|
|
179
|
+
];
|
|
180
|
+
// Additional pattern for workspace proxy routes (contains /proxy/)
|
|
181
|
+
const isWorkspaceProxyRoute = (path) => /^\/api\/workspaces\/[^/]+\/proxy\//.test(path);
|
|
114
182
|
app.use((req, res, next) => {
|
|
183
|
+
// Skip CSRF for webhook endpoints and workspace proxy routes
|
|
184
|
+
if (CSRF_EXEMPT_PATHS.some(path => req.path.startsWith(path)) || isWorkspaceProxyRoute(req.path)) {
|
|
185
|
+
return next();
|
|
186
|
+
}
|
|
115
187
|
if (!req.session)
|
|
116
188
|
return res.status(500).json({ error: 'Session unavailable' });
|
|
189
|
+
// Generate CSRF token if not present
|
|
190
|
+
// Use session.save() to ensure the session is persisted even for unauthenticated users
|
|
191
|
+
// This is necessary because saveUninitialized: false won't auto-save new sessions
|
|
117
192
|
if (!req.session.csrfToken) {
|
|
118
193
|
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
|
|
194
|
+
// Explicitly save session to persist the CSRF token
|
|
195
|
+
req.session.save((err) => {
|
|
196
|
+
if (err) {
|
|
197
|
+
console.error('[csrf] Failed to save session:', err);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
119
200
|
}
|
|
120
201
|
res.setHeader('X-CSRF-Token', req.session.csrfToken);
|
|
121
202
|
if (SAFE_METHODS.has(req.method.toUpperCase())) {
|
|
122
203
|
return next();
|
|
123
204
|
}
|
|
205
|
+
// Skip CSRF for Bearer-authenticated endpoints (daemon API, test helpers)
|
|
206
|
+
const authHeader = req.get('authorization');
|
|
207
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
208
|
+
return next();
|
|
209
|
+
}
|
|
210
|
+
// Skip CSRF for test endpoints in non-production
|
|
211
|
+
if (process.env.NODE_ENV !== 'production' && req.path.startsWith('/api/test/')) {
|
|
212
|
+
return next();
|
|
213
|
+
}
|
|
124
214
|
const token = req.get('x-csrf-token');
|
|
125
215
|
if (!token || token !== req.session.csrfToken) {
|
|
216
|
+
console.log(`[csrf] Token mismatch: received=${token?.substring(0, 8)}... expected=${req.session.csrfToken?.substring(0, 8)}...`);
|
|
126
217
|
return res.status(403).json({
|
|
127
218
|
error: 'CSRF token invalid or missing',
|
|
128
219
|
code: 'CSRF_MISMATCH',
|
|
@@ -144,12 +235,39 @@ export async function createServer() {
|
|
|
144
235
|
app.use('/api/billing', billingRouter);
|
|
145
236
|
app.use('/api/usage', usageRouter);
|
|
146
237
|
app.use('/api/project-groups', coordinatorsRouter);
|
|
147
|
-
|
|
238
|
+
app.use('/api/daemons', daemonsRouter);
|
|
239
|
+
app.use('/api/monitoring', monitoringRouter);
|
|
240
|
+
app.use('/api/webhooks', webhooksRouter);
|
|
241
|
+
app.use('/api/github-app', githubAppRouter);
|
|
242
|
+
app.use('/api/auth/nango', nangoAuthRouter);
|
|
243
|
+
app.use('/api/auth/codex-helper', codexAuthHelperRouter);
|
|
244
|
+
app.use('/api/git', gitRouter);
|
|
245
|
+
// Test helper routes (only available in non-production)
|
|
246
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
247
|
+
app.use('/api/test', testHelpersRouter);
|
|
248
|
+
console.log('[cloud] Test helper routes enabled (non-production mode)');
|
|
249
|
+
}
|
|
250
|
+
// Trajectory proxy routes - auto-detect user's workspace and forward
|
|
251
|
+
// These are convenience routes so the dashboard doesn't need to know the workspace ID
|
|
252
|
+
app.get('/api/trajectory', requireAuth, async (req, res) => {
|
|
253
|
+
await proxyToUserWorkspace(req, res, '/api/trajectory');
|
|
254
|
+
});
|
|
255
|
+
app.get('/api/trajectory/steps', requireAuth, async (req, res) => {
|
|
256
|
+
const queryString = req.query.trajectoryId
|
|
257
|
+
? `?trajectoryId=${encodeURIComponent(req.query.trajectoryId)}`
|
|
258
|
+
: '';
|
|
259
|
+
await proxyToUserWorkspace(req, res, `/api/trajectory/steps${queryString}`);
|
|
260
|
+
});
|
|
261
|
+
app.get('/api/trajectory/history', requireAuth, async (req, res) => {
|
|
262
|
+
await proxyToUserWorkspace(req, res, '/api/trajectory/history');
|
|
263
|
+
});
|
|
148
264
|
// Serve static dashboard files (Next.js static export)
|
|
149
265
|
// Path: dist/cloud/server.js -> ../../src/dashboard/out
|
|
150
266
|
const dashboardPath = path.join(__dirname, '../../src/dashboard/out');
|
|
151
|
-
|
|
152
|
-
//
|
|
267
|
+
// Serve static files with .html extension fallback for clean URLs
|
|
268
|
+
// e.g., /signup will try /signup.html
|
|
269
|
+
app.use(express.static(dashboardPath, { extensions: ['html'] }));
|
|
270
|
+
// SPA fallback - serve index.html for all non-API routes that don't match static files
|
|
153
271
|
// Express 5 requires named wildcard params instead of bare '*'
|
|
154
272
|
app.get('/{*splat}', (req, res, next) => {
|
|
155
273
|
// Don't serve index.html for API routes
|
|
@@ -168,18 +286,249 @@ export async function createServer() {
|
|
|
168
286
|
});
|
|
169
287
|
// Server lifecycle
|
|
170
288
|
let server = null;
|
|
289
|
+
let scalingOrchestrator = null;
|
|
290
|
+
// Create HTTP server for WebSocket upgrade handling
|
|
291
|
+
const httpServer = http.createServer(app);
|
|
292
|
+
// ===== Presence WebSocket =====
|
|
293
|
+
const wssPresence = new WebSocketServer({
|
|
294
|
+
noServer: true,
|
|
295
|
+
perMessageDeflate: false,
|
|
296
|
+
maxPayload: 1024 * 1024, // 1MB - presence messages are small
|
|
297
|
+
});
|
|
298
|
+
const onlineUsers = new Map();
|
|
299
|
+
// Validation helpers
|
|
300
|
+
const isValidUsername = (username) => {
|
|
301
|
+
if (typeof username !== 'string')
|
|
302
|
+
return false;
|
|
303
|
+
return /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$/.test(username);
|
|
304
|
+
};
|
|
305
|
+
const isValidAvatarUrl = (url) => {
|
|
306
|
+
if (url === undefined || url === null)
|
|
307
|
+
return true;
|
|
308
|
+
if (typeof url !== 'string')
|
|
309
|
+
return false;
|
|
310
|
+
try {
|
|
311
|
+
const parsed = new URL(url);
|
|
312
|
+
return parsed.protocol === 'https:' &&
|
|
313
|
+
(parsed.hostname === 'avatars.githubusercontent.com' ||
|
|
314
|
+
parsed.hostname === 'github.com' ||
|
|
315
|
+
parsed.hostname.endsWith('.githubusercontent.com'));
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
// Handle HTTP upgrade for WebSocket
|
|
322
|
+
httpServer.on('upgrade', (request, socket, head) => {
|
|
323
|
+
const pathname = new URL(request.url || '', `http://${request.headers.host}`).pathname;
|
|
324
|
+
if (pathname === '/ws/presence') {
|
|
325
|
+
wssPresence.handleUpgrade(request, socket, head, (ws) => {
|
|
326
|
+
wssPresence.emit('connection', ws, request);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
// Unknown WebSocket path - destroy socket
|
|
331
|
+
socket.destroy();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
// Broadcast to all presence clients
|
|
335
|
+
const broadcastPresence = (message, exclude) => {
|
|
336
|
+
const payload = JSON.stringify(message);
|
|
337
|
+
wssPresence.clients.forEach((client) => {
|
|
338
|
+
if (client !== exclude && client.readyState === WebSocket.OPEN) {
|
|
339
|
+
client.send(payload);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
};
|
|
343
|
+
// Get online users list
|
|
344
|
+
const getOnlineUsersList = () => {
|
|
345
|
+
return Array.from(onlineUsers.values()).map((state) => state.info);
|
|
346
|
+
};
|
|
347
|
+
// Heartbeat interval to detect dead connections (30 seconds)
|
|
348
|
+
const PRESENCE_HEARTBEAT_INTERVAL = 30000;
|
|
349
|
+
const _PRESENCE_HEARTBEAT_TIMEOUT = 35000; // Allow 5s grace period (reserved for future use)
|
|
350
|
+
// Track connection health for heartbeat
|
|
351
|
+
const connectionHealth = new WeakMap();
|
|
352
|
+
// Heartbeat interval to clean up dead connections
|
|
353
|
+
const presenceHeartbeat = setInterval(() => {
|
|
354
|
+
const now = Date.now();
|
|
355
|
+
wssPresence.clients.forEach((ws) => {
|
|
356
|
+
const health = connectionHealth.get(ws);
|
|
357
|
+
if (!health) {
|
|
358
|
+
// New connection without health tracking - initialize it
|
|
359
|
+
connectionHealth.set(ws, { isAlive: true, lastPing: now });
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!health.isAlive) {
|
|
363
|
+
// Connection didn't respond to last ping - terminate it
|
|
364
|
+
ws.terminate();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
// Mark as not alive until we get a pong
|
|
368
|
+
health.isAlive = false;
|
|
369
|
+
health.lastPing = now;
|
|
370
|
+
ws.ping();
|
|
371
|
+
});
|
|
372
|
+
}, PRESENCE_HEARTBEAT_INTERVAL);
|
|
373
|
+
// Clean up interval on server close
|
|
374
|
+
wssPresence.on('close', () => {
|
|
375
|
+
clearInterval(presenceHeartbeat);
|
|
376
|
+
});
|
|
377
|
+
// Handle presence connections
|
|
378
|
+
wssPresence.on('connection', (ws) => {
|
|
379
|
+
// Initialize health tracking (no log - too noisy)
|
|
380
|
+
connectionHealth.set(ws, { isAlive: true, lastPing: Date.now() });
|
|
381
|
+
// Handle pong responses (heartbeat)
|
|
382
|
+
ws.on('pong', () => {
|
|
383
|
+
const health = connectionHealth.get(ws);
|
|
384
|
+
if (health) {
|
|
385
|
+
health.isAlive = true;
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
let clientUsername;
|
|
389
|
+
ws.on('message', (data) => {
|
|
390
|
+
try {
|
|
391
|
+
const msg = JSON.parse(data.toString());
|
|
392
|
+
if (msg.type === 'presence') {
|
|
393
|
+
if (msg.action === 'join' && msg.user?.username) {
|
|
394
|
+
const username = msg.user.username;
|
|
395
|
+
const avatarUrl = msg.user.avatarUrl;
|
|
396
|
+
if (!isValidUsername(username)) {
|
|
397
|
+
console.warn(`[cloud] Invalid username rejected: ${username}`);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (!isValidAvatarUrl(avatarUrl)) {
|
|
401
|
+
console.warn(`[cloud] Invalid avatar URL rejected for user ${username}`);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
clientUsername = username;
|
|
405
|
+
const now = new Date().toISOString();
|
|
406
|
+
const existing = onlineUsers.get(username);
|
|
407
|
+
if (existing) {
|
|
408
|
+
existing.connections.add(ws);
|
|
409
|
+
existing.info.lastSeen = now;
|
|
410
|
+
// Only log at milestones to reduce noise
|
|
411
|
+
const count = existing.connections.size;
|
|
412
|
+
if (count === 2 || count === 5 || count === 10 || count % 50 === 0) {
|
|
413
|
+
console.log(`[cloud] User ${username} has ${count} connections`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
onlineUsers.set(username, {
|
|
418
|
+
info: { username, avatarUrl, connectedAt: now, lastSeen: now },
|
|
419
|
+
connections: new Set([ws]),
|
|
420
|
+
});
|
|
421
|
+
console.log(`[cloud] User ${username} came online`);
|
|
422
|
+
broadcastPresence({
|
|
423
|
+
type: 'presence_join',
|
|
424
|
+
user: { username, avatarUrl, connectedAt: now, lastSeen: now },
|
|
425
|
+
}, ws);
|
|
426
|
+
}
|
|
427
|
+
ws.send(JSON.stringify({
|
|
428
|
+
type: 'presence_list',
|
|
429
|
+
users: getOnlineUsersList(),
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
else if (msg.action === 'leave') {
|
|
433
|
+
if (!clientUsername || msg.username !== clientUsername)
|
|
434
|
+
return;
|
|
435
|
+
const userState = onlineUsers.get(clientUsername);
|
|
436
|
+
if (userState) {
|
|
437
|
+
userState.connections.delete(ws);
|
|
438
|
+
if (userState.connections.size === 0) {
|
|
439
|
+
onlineUsers.delete(clientUsername);
|
|
440
|
+
console.log(`[cloud] User ${clientUsername} went offline`);
|
|
441
|
+
broadcastPresence({ type: 'presence_leave', username: clientUsername });
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
else if (msg.type === 'typing') {
|
|
447
|
+
if (!clientUsername || msg.username !== clientUsername)
|
|
448
|
+
return;
|
|
449
|
+
const userState = onlineUsers.get(clientUsername);
|
|
450
|
+
if (userState) {
|
|
451
|
+
userState.info.lastSeen = new Date().toISOString();
|
|
452
|
+
}
|
|
453
|
+
broadcastPresence({
|
|
454
|
+
type: 'typing',
|
|
455
|
+
username: clientUsername,
|
|
456
|
+
avatarUrl: userState?.info.avatarUrl,
|
|
457
|
+
isTyping: msg.isTyping,
|
|
458
|
+
}, ws);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
console.error('[cloud] Invalid presence message:', err);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
ws.on('close', () => {
|
|
466
|
+
if (clientUsername) {
|
|
467
|
+
const userState = onlineUsers.get(clientUsername);
|
|
468
|
+
if (userState) {
|
|
469
|
+
userState.connections.delete(ws);
|
|
470
|
+
if (userState.connections.size === 0) {
|
|
471
|
+
onlineUsers.delete(clientUsername);
|
|
472
|
+
console.log(`[cloud] User ${clientUsername} disconnected`);
|
|
473
|
+
broadcastPresence({ type: 'presence_leave', username: clientUsername });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
ws.on('error', (err) => {
|
|
479
|
+
console.error('[cloud] Presence WebSocket error:', err);
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
wssPresence.on('error', (err) => {
|
|
483
|
+
console.error('[cloud] Presence WebSocket server error:', err);
|
|
484
|
+
});
|
|
171
485
|
return {
|
|
172
486
|
app,
|
|
173
487
|
async start() {
|
|
488
|
+
// Run database migrations before accepting connections
|
|
489
|
+
console.log('[cloud] Running database migrations...');
|
|
490
|
+
await runMigrations();
|
|
491
|
+
// Initialize scaling orchestrator for auto-scaling
|
|
492
|
+
if (process.env.RELAY_CLOUD_ENABLED === 'true') {
|
|
493
|
+
try {
|
|
494
|
+
scalingOrchestrator = getScalingOrchestrator();
|
|
495
|
+
await scalingOrchestrator.initialize(config.redisUrl);
|
|
496
|
+
console.log('[cloud] Scaling orchestrator initialized');
|
|
497
|
+
// Log scaling events
|
|
498
|
+
scalingOrchestrator.on('scaling_started', (op) => {
|
|
499
|
+
console.log(`[scaling] Started: ${op.action} for user ${op.userId}`);
|
|
500
|
+
});
|
|
501
|
+
scalingOrchestrator.on('scaling_completed', (op) => {
|
|
502
|
+
console.log(`[scaling] Completed: ${op.action} for user ${op.userId}`);
|
|
503
|
+
});
|
|
504
|
+
scalingOrchestrator.on('scaling_error', ({ operation, error }) => {
|
|
505
|
+
console.error(`[scaling] Error: ${operation.action} for ${operation.userId}:`, error);
|
|
506
|
+
});
|
|
507
|
+
scalingOrchestrator.on('workspace_provisioned', (data) => {
|
|
508
|
+
console.log(`[scaling] Provisioned workspace ${data.workspaceId} for user ${data.userId}`);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
catch (error) {
|
|
512
|
+
console.warn('[cloud] Failed to initialize scaling orchestrator:', error);
|
|
513
|
+
// Non-fatal - server can run without auto-scaling
|
|
514
|
+
}
|
|
515
|
+
}
|
|
174
516
|
return new Promise((resolve) => {
|
|
175
|
-
server =
|
|
517
|
+
server = httpServer.listen(config.port, () => {
|
|
176
518
|
console.log(`Agent Relay Cloud running on port ${config.port}`);
|
|
177
519
|
console.log(`Public URL: ${config.publicUrl}`);
|
|
520
|
+
console.log(`WebSocket: ws://localhost:${config.port}/ws/presence`);
|
|
178
521
|
resolve();
|
|
179
522
|
});
|
|
180
523
|
});
|
|
181
524
|
},
|
|
182
525
|
async stop() {
|
|
526
|
+
// Shutdown scaling orchestrator
|
|
527
|
+
if (scalingOrchestrator) {
|
|
528
|
+
await scalingOrchestrator.shutdown();
|
|
529
|
+
}
|
|
530
|
+
// Close WebSocket server
|
|
531
|
+
wssPresence.close();
|
|
183
532
|
if (server) {
|
|
184
533
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
185
534
|
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Scaler Service
|
|
3
|
+
*
|
|
4
|
+
* Monitors workspace metrics and automatically scales instances based on
|
|
5
|
+
* defined policies. Uses Redis pub/sub for cross-server coordination to
|
|
6
|
+
* ensure only one scaling operation happens at a time.
|
|
7
|
+
*
|
|
8
|
+
* Key responsibilities:
|
|
9
|
+
* - Subscribe to metrics updates from monitoring service
|
|
10
|
+
* - Evaluate scaling policies periodically
|
|
11
|
+
* - Coordinate scaling decisions across multiple cloud servers
|
|
12
|
+
* - Execute scaling actions via workspace provisioner
|
|
13
|
+
* - Track scaling history and pending operations
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import { ScalingDecision, UserScalingContext, WorkspaceMetrics } from './scaling-policy.js';
|
|
17
|
+
export interface ScalingOperation {
|
|
18
|
+
id: string;
|
|
19
|
+
userId: string;
|
|
20
|
+
action: 'scale_up' | 'scale_down' | 'resize_up' | 'resize_down' | 'increase_agent_limit' | 'migrate_agents' | 'rebalance';
|
|
21
|
+
targetWorkspaceId?: string;
|
|
22
|
+
targetResourceTier?: 'small' | 'medium' | 'large' | 'xlarge';
|
|
23
|
+
targetAgentLimit?: number;
|
|
24
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
25
|
+
startedAt: Date;
|
|
26
|
+
completedAt?: Date;
|
|
27
|
+
error?: string;
|
|
28
|
+
triggeredBy: string;
|
|
29
|
+
metrics: Record<string, number>;
|
|
30
|
+
}
|
|
31
|
+
export interface AutoScalerConfig {
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
evaluationIntervalMs: number;
|
|
34
|
+
lockTimeoutMs: number;
|
|
35
|
+
maxConcurrentOperations: number;
|
|
36
|
+
redisKeyPrefix: string;
|
|
37
|
+
}
|
|
38
|
+
export interface MetricsSnapshot {
|
|
39
|
+
userId: string;
|
|
40
|
+
workspaces: WorkspaceMetrics[];
|
|
41
|
+
timestamp: Date;
|
|
42
|
+
}
|
|
43
|
+
export declare class AutoScaler extends EventEmitter {
|
|
44
|
+
private config;
|
|
45
|
+
private policyService;
|
|
46
|
+
private redis;
|
|
47
|
+
private subscriber;
|
|
48
|
+
private evaluationTimer;
|
|
49
|
+
private pendingOperations;
|
|
50
|
+
private metricsCache;
|
|
51
|
+
private isLeader;
|
|
52
|
+
private serverId;
|
|
53
|
+
private lastScalingActions;
|
|
54
|
+
constructor(config?: Partial<AutoScalerConfig>);
|
|
55
|
+
/**
|
|
56
|
+
* Initialize with Redis connection for cross-server coordination
|
|
57
|
+
*/
|
|
58
|
+
initialize(redisUrl: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Set up Redis pub/sub subscriptions
|
|
61
|
+
*/
|
|
62
|
+
private setupSubscriptions;
|
|
63
|
+
/**
|
|
64
|
+
* Handle channel message
|
|
65
|
+
*/
|
|
66
|
+
private handleChannelMessage;
|
|
67
|
+
/**
|
|
68
|
+
* Handle incoming pub/sub messages
|
|
69
|
+
*/
|
|
70
|
+
private handlePubSubMessage;
|
|
71
|
+
/**
|
|
72
|
+
* Handle metrics update from monitoring service
|
|
73
|
+
*/
|
|
74
|
+
private handleMetricsUpdate;
|
|
75
|
+
/**
|
|
76
|
+
* Handle scaling request (from any server)
|
|
77
|
+
*/
|
|
78
|
+
private handleScalingRequest;
|
|
79
|
+
/**
|
|
80
|
+
* Handle scaling completion
|
|
81
|
+
*/
|
|
82
|
+
private handleScalingComplete;
|
|
83
|
+
/**
|
|
84
|
+
* Handle leadership change
|
|
85
|
+
*/
|
|
86
|
+
private handleLeadershipChange;
|
|
87
|
+
/**
|
|
88
|
+
* Attempt to become the leader (only leader evaluates scaling)
|
|
89
|
+
*/
|
|
90
|
+
private attemptLeadership;
|
|
91
|
+
/**
|
|
92
|
+
* Schedule leadership lock renewal
|
|
93
|
+
*/
|
|
94
|
+
private scheduleLeadershipRenewal;
|
|
95
|
+
/**
|
|
96
|
+
* Start the periodic evaluation loop
|
|
97
|
+
*/
|
|
98
|
+
private startEvaluationLoop;
|
|
99
|
+
/**
|
|
100
|
+
* Evaluate scaling for all cached users
|
|
101
|
+
*/
|
|
102
|
+
private evaluateAllUsers;
|
|
103
|
+
/**
|
|
104
|
+
* Evaluate scaling for a specific user
|
|
105
|
+
*/
|
|
106
|
+
private evaluateUserScaling;
|
|
107
|
+
/**
|
|
108
|
+
* Build user context for policy evaluation
|
|
109
|
+
*/
|
|
110
|
+
private buildUserContext;
|
|
111
|
+
/**
|
|
112
|
+
* Request a scaling operation
|
|
113
|
+
*/
|
|
114
|
+
private requestScaling;
|
|
115
|
+
/**
|
|
116
|
+
* Execute the actual scaling operation
|
|
117
|
+
*/
|
|
118
|
+
private executeScaling;
|
|
119
|
+
/**
|
|
120
|
+
* Report metrics from monitoring service
|
|
121
|
+
*/
|
|
122
|
+
reportMetrics(userId: string, workspaces: WorkspaceMetrics[]): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Manually trigger scaling evaluation for a user
|
|
125
|
+
*/
|
|
126
|
+
triggerEvaluation(userId: string): Promise<ScalingDecision | null>;
|
|
127
|
+
/**
|
|
128
|
+
* Get current scaling status
|
|
129
|
+
*/
|
|
130
|
+
getStatus(): {
|
|
131
|
+
enabled: boolean;
|
|
132
|
+
isLeader: boolean;
|
|
133
|
+
serverId: string;
|
|
134
|
+
pendingOperations: number;
|
|
135
|
+
cachedUsers: number;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Get pending operations for a user
|
|
139
|
+
*/
|
|
140
|
+
getPendingOperations(userId?: string): ScalingOperation[];
|
|
141
|
+
/**
|
|
142
|
+
* Update user plan in cache
|
|
143
|
+
*/
|
|
144
|
+
setUserPlan(userId: string, plan: UserScalingContext['plan']): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* Clean shutdown
|
|
147
|
+
*/
|
|
148
|
+
shutdown(): Promise<void>;
|
|
149
|
+
}
|
|
150
|
+
export declare function getAutoScaler(): AutoScaler;
|
|
151
|
+
export declare function createAutoScaler(config?: Partial<AutoScalerConfig>): AutoScaler;
|
|
152
|
+
//# sourceMappingURL=auto-scaler.d.ts.map
|