@withbuddi/buddi 0.1.0-pre.37 → 0.1.0-pre.38
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/extension/background.js +130 -12
- package/extension/manifest.json +2 -2
- package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/cli/dist/access-cmd.d.ts +10 -0
- package/node_modules/@buddi/cli/dist/access-cmd.d.ts.map +1 -0
- package/node_modules/@buddi/cli/dist/access-cmd.js +160 -0
- package/node_modules/@buddi/cli/dist/access-cmd.js.map +1 -0
- package/node_modules/@buddi/cli/dist/args.d.ts +10 -0
- package/node_modules/@buddi/cli/dist/args.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/args.js +29 -1
- package/node_modules/@buddi/cli/dist/args.js.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.js +28 -2
- package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.js +54 -29
- package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.d.ts +36 -12
- package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.js +32 -9
- package/node_modules/@buddi/cli/dist/doctor.js.map +1 -1
- package/node_modules/@buddi/cli/dist/main.d.ts +2 -0
- package/node_modules/@buddi/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/main.js +18 -1
- package/node_modules/@buddi/cli/dist/main.js.map +1 -1
- package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts +2 -0
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.js +1 -0
- package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/edit.d.ts +2 -0
- package/node_modules/@buddi/core/dist/agents/edit.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/edit.js +3 -1
- package/node_modules/@buddi/core/dist/agents/edit.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts +11 -0
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.js +7 -0
- package/node_modules/@buddi/core/dist/agents/frontmatter.js.map +1 -1
- package/node_modules/@buddi/core/dist/index.d.ts +1 -0
- package/node_modules/@buddi/core/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/index.js +1 -0
- package/node_modules/@buddi/core/dist/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.d.ts +3 -0
- package/node_modules/@buddi/core/dist/plugin/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.js +3 -0
- package/node_modules/@buddi/core/dist/plugin/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
- package/node_modules/@buddi/core/dist/questions/store.d.ts +12 -0
- package/node_modules/@buddi/core/dist/questions/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/questions/store.js +11 -1
- package/node_modules/@buddi/core/dist/questions/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/questions/types.d.ts +8 -0
- package/node_modules/@buddi/core/dist/questions/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/questions/types.js +15 -0
- package/node_modules/@buddi/core/dist/questions/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts +8 -0
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.js +9 -3
- package/node_modules/@buddi/core/dist/queue/jobs.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.d.ts +2 -0
- package/node_modules/@buddi/core/dist/queue/worker.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.js +2 -1
- package/node_modules/@buddi/core/dist/queue/worker.js.map +1 -1
- package/node_modules/@buddi/core/dist/registry.d.ts +7 -1
- package/node_modules/@buddi/core/dist/registry.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/registry.js +73 -11
- package/node_modules/@buddi/core/dist/registry.js.map +1 -1
- package/node_modules/@buddi/core/dist/routes.d.ts +153 -0
- package/node_modules/@buddi/core/dist/routes.d.ts.map +1 -0
- package/node_modules/@buddi/core/dist/routes.js +47 -0
- package/node_modules/@buddi/core/dist/routes.js.map +1 -0
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts +5 -3
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/missions.js +9 -7
- package/node_modules/@buddi/core/dist/scheduler/missions.js.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts +7 -0
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.js +1 -0
- package/node_modules/@buddi/core/dist/scheduler/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/tools.d.ts +59 -2
- package/node_modules/@buddi/core/dist/tools.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/tools.js.map +1 -1
- package/node_modules/@buddi/core/migrations/075_access_providers.sql +43 -0
- package/node_modules/@buddi/core/migrations/076_mission_browser.sql +7 -0
- package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/gateway/dist/agents/canvas.d.ts +12 -12
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts +38 -20
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js +6 -0
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts +10 -0
- package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/delegation.js +1 -0
- package/node_modules/@buddi/gateway/dist/agents/delegation.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts +7 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js +15 -6
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.js +8 -0
- package/node_modules/@buddi/gateway/dist/bootstrap.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/browser-host.d.ts +30 -1
- package/node_modules/@buddi/gateway/dist/browser-host.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/browser-host.js +56 -1
- package/node_modules/@buddi/gateway/dist/browser-host.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/chat/session.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/chat/session.js +9 -5
- package/node_modules/@buddi/gateway/dist/chat/session.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts +2 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.js +2 -1
- package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts +34 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.js +92 -8
- package/node_modules/@buddi/gateway/dist/missions/execute.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts +133 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js +249 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/serve.d.ts +7 -0
- package/node_modules/@buddi/gateway/dist/serve.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/serve.js +49 -9
- package/node_modules/@buddi/gateway/dist/serve.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts +18 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js +42 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts +6 -0
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js +7 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/system-context.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/system-context.js +6 -7
- package/node_modules/@buddi/gateway/dist/system-context.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts +17 -17
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.js +33 -37
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.js +17 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.js +11 -3
- package/node_modules/@buddi/gateway/dist/telegram/main.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.js +10 -0
- package/node_modules/@buddi/gateway/dist/telegram/surface.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/facts.d.ts +8 -0
- package/node_modules/@buddi/gateway/dist/tips/facts.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/facts.js +8 -2
- package/node_modules/@buddi/gateway/dist/tips/facts.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/rules.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/tips/rules.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/rules.js +15 -0
- package/node_modules/@buddi/gateway/dist/tips/rules.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts +24 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.js +18 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js +206 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js +438 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js +74 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts +145 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js +474 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.d.ts +9 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.js +9 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts +30 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.js +76 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts +173 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.js +11 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts +33 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.js +32 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
- package/node_modules/@buddi/gateway/dist/web/access/tailscale.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
- package/node_modules/@buddi/gateway/dist/web/access/tailscale.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/agents.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/web/agents.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/agents.js +19 -1
- package/node_modules/@buddi/gateway/dist/web/agents.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts +4 -3
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.js +96 -17
- package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/attention.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/attention.js +11 -3
- package/node_modules/@buddi/gateway/dist/web/attention.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts +23 -0
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/chat.js +62 -2
- package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts +3 -0
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.js +8 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts +9 -1
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/extension.js +61 -1
- package/node_modules/@buddi/gateway/dist/web/extension.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/http.d.ts +7 -0
- package/node_modules/@buddi/gateway/dist/web/http.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/http.js +15 -1
- package/node_modules/@buddi/gateway/dist/web/http.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.d.ts +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.js +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/onboarding.js +1 -1
- package/node_modules/@buddi/gateway/dist/web/onboarding.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.d.ts +38 -2
- package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.js +576 -145
- package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/sessions.d.ts +24 -14
- package/node_modules/@buddi/gateway/dist/web/sessions.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/sessions.js +42 -14
- package/node_modules/@buddi/gateway/dist/web/sessions.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts +10 -0
- package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/signed-out.js +47 -0
- package/node_modules/@buddi/gateway/dist/web/signed-out.js.map +1 -1
- package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.d.ts +8 -0
- package/node_modules/@buddi/runtime/dist/delegate.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.js +19 -1
- package/node_modules/@buddi/runtime/dist/delegate.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.d.ts +2 -0
- package/node_modules/@buddi/runtime/dist/loop.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.js +18 -4
- package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/availability.d.ts +2 -2
- package/node_modules/@buddi/tool-browser/dist/availability.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/availability.js +2 -2
- package/node_modules/@buddi/tool-browser/dist/availability.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/controller.d.ts +76 -58
- package/node_modules/@buddi/tool-browser/dist/controller.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/controller.js +751 -219
- package/node_modules/@buddi/tool-browser/dist/controller.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts +12 -0
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.js +8 -0
- package/node_modules/@buddi/tool-browser/dist/extension.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.d.ts +13 -5
- package/node_modules/@buddi/tool-browser/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.js +29 -12
- package/node_modules/@buddi/tool-browser/dist/index.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/manager.d.ts +39 -21
- package/node_modules/@buddi/tool-browser/dist/manager.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/manager.js +229 -136
- package/node_modules/@buddi/tool-browser/dist/manager.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/routes.d.ts +130 -0
- package/node_modules/@buddi/tool-browser/dist/routes.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js +283 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/service.d.ts +157 -114
- package/node_modules/@buddi/tool-browser/dist/service.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/service.js +379 -390
- package/node_modules/@buddi/tool-browser/dist/service.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/settings.d.ts +88 -0
- package/node_modules/@buddi/tool-browser/dist/settings.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/settings.js +86 -0
- package/node_modules/@buddi/tool-browser/dist/settings.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts +203 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.js +142 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/types.d.ts +14 -3
- package/node_modules/@buddi/tool-browser/dist/types.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/types.js +9 -9
- package/node_modules/@buddi/tool-browser/dist/types.js.map +1 -1
- package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
- package/node_modules/imapflow/CHANGELOG.md +15 -0
- package/node_modules/imapflow/dist/cjs/package-info.d.ts +1 -1
- package/node_modules/imapflow/dist/cjs/package-info.js +1 -1
- package/node_modules/imapflow/dist/cjs/search-compiler.js +21 -31
- package/node_modules/imapflow/dist/esm/package-info.d.ts +1 -1
- package/node_modules/imapflow/dist/esm/package-info.js +1 -1
- package/node_modules/imapflow/dist/esm/search-compiler.js +21 -31
- package/node_modules/imapflow/package.json +2 -2
- package/node_modules/pino/CONTRIBUTING.md +1 -5
- package/node_modules/pino/LICENSE +1 -1
- package/node_modules/pino/README.md +1 -1
- package/node_modules/pino/SECURITY.md +2 -18
- package/node_modules/pino/browser.js +8 -68
- package/node_modules/pino/docs/api.md +4 -75
- package/node_modules/pino/docs/asynchronous.md +3 -18
- package/node_modules/pino/docs/browser.md +0 -63
- package/node_modules/pino/docs/child-loggers.md +1 -22
- package/node_modules/pino/docs/ecosystem.md +0 -1
- package/node_modules/pino/docs/help.md +3 -11
- package/node_modules/pino/docs/lts.md +0 -29
- package/node_modules/pino/docs/pretty.md +0 -3
- package/node_modules/pino/docs/redaction.md +8 -3
- package/node_modules/pino/docs/transports.md +0 -71
- package/node_modules/pino/docs/web.md +14 -11
- package/node_modules/pino/eslint.config.js +7 -15
- package/node_modules/pino/lib/caller.js +0 -10
- package/node_modules/pino/lib/meta.js +1 -1
- package/node_modules/pino/lib/multistream.js +7 -15
- package/node_modules/pino/lib/redaction.js +3 -8
- package/node_modules/pino/lib/symbols.js +1 -3
- package/node_modules/pino/lib/tools.js +2 -2
- package/node_modules/pino/lib/transport.js +1 -14
- package/node_modules/pino/lib/worker.js +1 -4
- package/node_modules/pino/package.json +22 -14
- package/node_modules/pino/pino.d.ts +736 -709
- package/node_modules/pino/pino.js +2 -27
- package/node_modules/pino/test/basic.test.js +0 -66
- package/node_modules/pino/test/escaping.test.js +0 -17
- package/node_modules/pino/test/fixtures/ts/transpile.cjs +3 -3
- package/node_modules/pino/test/helper.js +2 -6
- package/node_modules/pino/test/multistream.test.js +0 -64
- package/node_modules/pino/test/redact.test.js +0 -30
- package/node_modules/pino/test/transport/core.test.js +0 -85
- package/node_modules/pino/test/transport/sync-false.test.js +0 -12
- package/node_modules/pino/test/transport/uses-pino-config.test.js +4 -4
- package/node_modules/pino/test/types/pino-import.test-d.cts +30 -0
- package/node_modules/pino/test/types/pino-multistream.test-d.ts +28 -0
- package/node_modules/pino/test/types/pino-top-export.test-d.ts +34 -0
- package/node_modules/pino/test/types/{pino-transport.tst.ts → pino-transport.test-d.ts} +70 -85
- package/node_modules/pino/test/types/pino-type-only.test-d.ts +75 -0
- package/node_modules/pino/test/types/{pino.tst.ts → pino.test-d.ts} +137 -135
- package/node_modules/pino/test/types/pino.ts +7 -14
- package/node_modules/pino/tsconfig.json +6 -6
- package/node_modules/real-require/README.md +6 -6
- package/node_modules/real-require/package.json +21 -10
- package/node_modules/real-require/src/index.js +2 -2
- package/node_modules/thread-stream/node_modules/real-require/LICENSE.md +21 -0
- package/node_modules/thread-stream/node_modules/real-require/README.md +51 -0
- package/node_modules/thread-stream/node_modules/real-require/package.json +38 -0
- package/node_modules/thread-stream/node_modules/real-require/src/index.js +14 -0
- package/package.json +2 -2
- package/packages/cli/dist/.tsbuildinfo +1 -1
- package/packages/cli/dist/access-cmd.d.ts +10 -0
- package/packages/cli/dist/access-cmd.d.ts.map +1 -0
- package/packages/cli/dist/access-cmd.js +160 -0
- package/packages/cli/dist/access-cmd.js.map +1 -0
- package/packages/cli/dist/args.d.ts +10 -0
- package/packages/cli/dist/args.d.ts.map +1 -1
- package/packages/cli/dist/args.js +29 -1
- package/packages/cli/dist/args.js.map +1 -1
- package/packages/cli/dist/commands.d.ts.map +1 -1
- package/packages/cli/dist/commands.js +28 -2
- package/packages/cli/dist/commands.js.map +1 -1
- package/packages/cli/dist/doctor-probes.d.ts.map +1 -1
- package/packages/cli/dist/doctor-probes.js +54 -29
- package/packages/cli/dist/doctor-probes.js.map +1 -1
- package/packages/cli/dist/doctor.d.ts +36 -12
- package/packages/cli/dist/doctor.d.ts.map +1 -1
- package/packages/cli/dist/doctor.js +32 -9
- package/packages/cli/dist/doctor.js.map +1 -1
- package/packages/cli/dist/main.d.ts +2 -0
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +18 -1
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/core/dist/.tsbuildinfo +1 -1
- package/packages/core/dist/agents/catalog.d.ts +2 -0
- package/packages/core/dist/agents/catalog.d.ts.map +1 -1
- package/packages/core/dist/agents/catalog.js +1 -0
- package/packages/core/dist/agents/catalog.js.map +1 -1
- package/packages/core/dist/agents/edit.d.ts +2 -0
- package/packages/core/dist/agents/edit.d.ts.map +1 -1
- package/packages/core/dist/agents/edit.js +3 -1
- package/packages/core/dist/agents/edit.js.map +1 -1
- package/packages/core/dist/agents/frontmatter.d.ts +11 -0
- package/packages/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/packages/core/dist/agents/frontmatter.js +7 -0
- package/packages/core/dist/agents/frontmatter.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/plugin/index.d.ts +3 -0
- package/packages/core/dist/plugin/index.d.ts.map +1 -1
- package/packages/core/dist/plugin/index.js +3 -0
- package/packages/core/dist/plugin/index.js.map +1 -1
- package/packages/core/dist/plugin/version.d.ts +1 -1
- package/packages/core/dist/plugin/version.js +1 -1
- package/packages/core/dist/questions/store.d.ts +12 -0
- package/packages/core/dist/questions/store.d.ts.map +1 -1
- package/packages/core/dist/questions/store.js +11 -1
- package/packages/core/dist/questions/store.js.map +1 -1
- package/packages/core/dist/questions/types.d.ts +8 -0
- package/packages/core/dist/questions/types.d.ts.map +1 -1
- package/packages/core/dist/questions/types.js +15 -0
- package/packages/core/dist/questions/types.js.map +1 -1
- package/packages/core/dist/queue/jobs.d.ts +8 -0
- package/packages/core/dist/queue/jobs.d.ts.map +1 -1
- package/packages/core/dist/queue/jobs.js +9 -3
- package/packages/core/dist/queue/jobs.js.map +1 -1
- package/packages/core/dist/queue/worker.d.ts +2 -0
- package/packages/core/dist/queue/worker.d.ts.map +1 -1
- package/packages/core/dist/queue/worker.js +2 -1
- package/packages/core/dist/queue/worker.js.map +1 -1
- package/packages/core/dist/registry.d.ts +7 -1
- package/packages/core/dist/registry.d.ts.map +1 -1
- package/packages/core/dist/registry.js +73 -11
- package/packages/core/dist/registry.js.map +1 -1
- package/packages/core/dist/routes.d.ts +153 -0
- package/packages/core/dist/routes.d.ts.map +1 -0
- package/packages/core/dist/routes.js +47 -0
- package/packages/core/dist/routes.js.map +1 -0
- package/packages/core/dist/scheduler/missions.d.ts +5 -3
- package/packages/core/dist/scheduler/missions.d.ts.map +1 -1
- package/packages/core/dist/scheduler/missions.js +9 -7
- package/packages/core/dist/scheduler/missions.js.map +1 -1
- package/packages/core/dist/scheduler/types.d.ts +7 -0
- package/packages/core/dist/scheduler/types.d.ts.map +1 -1
- package/packages/core/dist/scheduler/types.js +1 -0
- package/packages/core/dist/scheduler/types.js.map +1 -1
- package/packages/core/dist/tools.d.ts +59 -2
- package/packages/core/dist/tools.d.ts.map +1 -1
- package/packages/core/dist/tools.js.map +1 -1
- package/packages/core/migrations/075_access_providers.sql +43 -0
- package/packages/core/migrations/076_mission_browser.sql +7 -0
- package/packages/gateway/dist/.tsbuildinfo +1 -1
- package/packages/gateway/dist/agents/canvas.d.ts +12 -12
- package/packages/gateway/dist/agents/catalogue-package.d.ts +38 -20
- package/packages/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
- package/packages/gateway/dist/agents/catalogue-package.js +6 -0
- package/packages/gateway/dist/agents/catalogue-package.js.map +1 -1
- package/packages/gateway/dist/agents/delegation.d.ts +10 -0
- package/packages/gateway/dist/agents/delegation.d.ts.map +1 -1
- package/packages/gateway/dist/agents/delegation.js +1 -0
- package/packages/gateway/dist/agents/delegation.js.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts +7 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.js +15 -6
- package/packages/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/packages/gateway/dist/bootstrap.d.ts.map +1 -1
- package/packages/gateway/dist/bootstrap.js +8 -0
- package/packages/gateway/dist/bootstrap.js.map +1 -1
- package/packages/gateway/dist/browser-host.d.ts +30 -1
- package/packages/gateway/dist/browser-host.d.ts.map +1 -1
- package/packages/gateway/dist/browser-host.js +56 -1
- package/packages/gateway/dist/browser-host.js.map +1 -1
- package/packages/gateway/dist/chat/session.d.ts.map +1 -1
- package/packages/gateway/dist/chat/session.js +9 -5
- package/packages/gateway/dist/chat/session.js.map +1 -1
- package/packages/gateway/dist/index.d.ts +2 -1
- package/packages/gateway/dist/index.d.ts.map +1 -1
- package/packages/gateway/dist/index.js +2 -1
- package/packages/gateway/dist/index.js.map +1 -1
- package/packages/gateway/dist/missions/execute.d.ts +34 -1
- package/packages/gateway/dist/missions/execute.d.ts.map +1 -1
- package/packages/gateway/dist/missions/execute.js +92 -8
- package/packages/gateway/dist/missions/execute.js.map +1 -1
- package/packages/gateway/dist/missions/parked.d.ts +133 -0
- package/packages/gateway/dist/missions/parked.d.ts.map +1 -0
- package/packages/gateway/dist/missions/parked.js +249 -0
- package/packages/gateway/dist/missions/parked.js.map +1 -0
- package/packages/gateway/dist/serve.d.ts +7 -0
- package/packages/gateway/dist/serve.d.ts.map +1 -1
- package/packages/gateway/dist/serve.js +49 -9
- package/packages/gateway/dist/serve.js.map +1 -1
- package/packages/gateway/dist/surfaces/browser-cards.d.ts +18 -0
- package/packages/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
- package/packages/gateway/dist/surfaces/browser-cards.js +42 -0
- package/packages/gateway/dist/surfaces/browser-cards.js.map +1 -0
- package/packages/gateway/dist/surfaces/browser-continuation.js +1 -1
- package/packages/gateway/dist/surfaces/browser-continuation.js.map +1 -1
- package/packages/gateway/dist/surfaces/owner-request.d.ts +6 -0
- package/packages/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
- package/packages/gateway/dist/surfaces/owner-request.js +7 -1
- package/packages/gateway/dist/surfaces/owner-request.js.map +1 -1
- package/packages/gateway/dist/system-context.d.ts.map +1 -1
- package/packages/gateway/dist/system-context.js +6 -7
- package/packages/gateway/dist/system-context.js.map +1 -1
- package/packages/gateway/dist/telegram/browser-view.d.ts +17 -17
- package/packages/gateway/dist/telegram/browser-view.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/browser-view.js +33 -37
- package/packages/gateway/dist/telegram/browser-view.js.map +1 -1
- package/packages/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/channel.js +17 -1
- package/packages/gateway/dist/telegram/channel.js.map +1 -1
- package/packages/gateway/dist/telegram/main.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/main.js +11 -3
- package/packages/gateway/dist/telegram/main.js.map +1 -1
- package/packages/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/surface.js +10 -0
- package/packages/gateway/dist/telegram/surface.js.map +1 -1
- package/packages/gateway/dist/tips/facts.d.ts +8 -0
- package/packages/gateway/dist/tips/facts.d.ts.map +1 -1
- package/packages/gateway/dist/tips/facts.js +8 -2
- package/packages/gateway/dist/tips/facts.js.map +1 -1
- package/packages/gateway/dist/tips/rules.d.ts +2 -0
- package/packages/gateway/dist/tips/rules.d.ts.map +1 -1
- package/packages/gateway/dist/tips/rules.js +15 -0
- package/packages/gateway/dist/tips/rules.js.map +1 -1
- package/packages/gateway/dist/web/access/arrival.d.ts +24 -0
- package/packages/gateway/dist/web/access/arrival.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/arrival.js +18 -0
- package/packages/gateway/dist/web/access/arrival.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
- package/packages/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-api.js +206 -0
- package/packages/gateway/dist/web/access/cloudflare-api.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.js +438 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
- package/packages/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-token.js +74 -0
- package/packages/gateway/dist/web/access/cloudflare-token.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare.d.ts +145 -0
- package/packages/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare.js +474 -0
- package/packages/gateway/dist/web/access/cloudflare.js.map +1 -0
- package/packages/gateway/dist/web/access/index.d.ts +9 -0
- package/packages/gateway/dist/web/access/index.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/index.js +9 -0
- package/packages/gateway/dist/web/access/index.js.map +1 -0
- package/packages/gateway/dist/web/access/ingress.d.ts +30 -0
- package/packages/gateway/dist/web/access/ingress.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/ingress.js +76 -0
- package/packages/gateway/dist/web/access/ingress.js.map +1 -0
- package/packages/gateway/dist/web/access/provider.d.ts +173 -0
- package/packages/gateway/dist/web/access/provider.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/provider.js +11 -0
- package/packages/gateway/dist/web/access/provider.js.map +1 -0
- package/packages/gateway/dist/web/access/registry.d.ts +33 -0
- package/packages/gateway/dist/web/access/registry.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/registry.js +32 -0
- package/packages/gateway/dist/web/access/registry.js.map +1 -0
- package/packages/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
- package/packages/gateway/dist/web/access/tailscale.d.ts.map +1 -0
- package/packages/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
- package/packages/gateway/dist/web/access/tailscale.js.map +1 -0
- package/packages/gateway/dist/web/agents.d.ts +2 -0
- package/packages/gateway/dist/web/agents.d.ts.map +1 -1
- package/packages/gateway/dist/web/agents.js +19 -1
- package/packages/gateway/dist/web/agents.js.map +1 -1
- package/packages/gateway/dist/web/api-routes.d.ts +4 -3
- package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/packages/gateway/dist/web/api-routes.js +96 -17
- package/packages/gateway/dist/web/api-routes.js.map +1 -1
- package/packages/gateway/dist/web/attention.d.ts.map +1 -1
- package/packages/gateway/dist/web/attention.js +11 -3
- package/packages/gateway/dist/web/attention.js.map +1 -1
- package/packages/gateway/dist/web/chat.d.ts +23 -0
- package/packages/gateway/dist/web/chat.d.ts.map +1 -1
- package/packages/gateway/dist/web/chat.js +62 -2
- package/packages/gateway/dist/web/chat.js.map +1 -1
- package/packages/gateway/dist/web/client-key.d.ts +3 -0
- package/packages/gateway/dist/web/client-key.d.ts.map +1 -1
- package/packages/gateway/dist/web/client-key.js +8 -1
- package/packages/gateway/dist/web/client-key.js.map +1 -1
- package/packages/gateway/dist/web/extension.d.ts +9 -1
- package/packages/gateway/dist/web/extension.d.ts.map +1 -1
- package/packages/gateway/dist/web/extension.js +61 -1
- package/packages/gateway/dist/web/extension.js.map +1 -1
- package/packages/gateway/dist/web/http.d.ts +7 -0
- package/packages/gateway/dist/web/http.d.ts.map +1 -1
- package/packages/gateway/dist/web/http.js +15 -1
- package/packages/gateway/dist/web/http.js.map +1 -1
- package/packages/gateway/dist/web/index.d.ts +1 -1
- package/packages/gateway/dist/web/index.d.ts.map +1 -1
- package/packages/gateway/dist/web/index.js +1 -1
- package/packages/gateway/dist/web/index.js.map +1 -1
- package/packages/gateway/dist/web/onboarding.js +1 -1
- package/packages/gateway/dist/web/onboarding.js.map +1 -1
- package/packages/gateway/dist/web/server.d.ts +38 -2
- package/packages/gateway/dist/web/server.d.ts.map +1 -1
- package/packages/gateway/dist/web/server.js +576 -145
- package/packages/gateway/dist/web/server.js.map +1 -1
- package/packages/gateway/dist/web/sessions.d.ts +24 -14
- package/packages/gateway/dist/web/sessions.d.ts.map +1 -1
- package/packages/gateway/dist/web/sessions.js +42 -14
- package/packages/gateway/dist/web/sessions.js.map +1 -1
- package/packages/gateway/dist/web/signed-out.d.ts +10 -0
- package/packages/gateway/dist/web/signed-out.d.ts.map +1 -1
- package/packages/gateway/dist/web/signed-out.js +47 -0
- package/packages/gateway/dist/web/signed-out.js.map +1 -1
- package/packages/install/dist/.tsbuildinfo +1 -1
- package/packages/runtime/dist/.tsbuildinfo +1 -1
- package/packages/runtime/dist/delegate.d.ts +8 -0
- package/packages/runtime/dist/delegate.d.ts.map +1 -1
- package/packages/runtime/dist/delegate.js +19 -1
- package/packages/runtime/dist/delegate.js.map +1 -1
- package/packages/runtime/dist/loop.d.ts +2 -0
- package/packages/runtime/dist/loop.d.ts.map +1 -1
- package/packages/runtime/dist/loop.js +18 -4
- package/packages/runtime/dist/loop.js.map +1 -1
- package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/availability.d.ts +2 -2
- package/packages/tools/browser/dist/availability.d.ts.map +1 -1
- package/packages/tools/browser/dist/availability.js +2 -2
- package/packages/tools/browser/dist/availability.js.map +1 -1
- package/packages/tools/browser/dist/controller.d.ts +76 -58
- package/packages/tools/browser/dist/controller.d.ts.map +1 -1
- package/packages/tools/browser/dist/controller.js +751 -219
- package/packages/tools/browser/dist/controller.js.map +1 -1
- package/packages/tools/browser/dist/extension.d.ts +12 -0
- package/packages/tools/browser/dist/extension.d.ts.map +1 -1
- package/packages/tools/browser/dist/extension.js +8 -0
- package/packages/tools/browser/dist/extension.js.map +1 -1
- package/packages/tools/browser/dist/index.d.ts +13 -5
- package/packages/tools/browser/dist/index.d.ts.map +1 -1
- package/packages/tools/browser/dist/index.js +29 -12
- package/packages/tools/browser/dist/index.js.map +1 -1
- package/packages/tools/browser/dist/manager.d.ts +39 -21
- package/packages/tools/browser/dist/manager.d.ts.map +1 -1
- package/packages/tools/browser/dist/manager.js +229 -136
- package/packages/tools/browser/dist/manager.js.map +1 -1
- package/packages/tools/browser/dist/routes.d.ts +130 -0
- package/packages/tools/browser/dist/routes.d.ts.map +1 -0
- package/packages/tools/browser/dist/routes.js +283 -0
- package/packages/tools/browser/dist/routes.js.map +1 -0
- package/packages/tools/browser/dist/service.d.ts +157 -114
- package/packages/tools/browser/dist/service.d.ts.map +1 -1
- package/packages/tools/browser/dist/service.js +379 -390
- package/packages/tools/browser/dist/service.js.map +1 -1
- package/packages/tools/browser/dist/settings.d.ts +88 -0
- package/packages/tools/browser/dist/settings.d.ts.map +1 -0
- package/packages/tools/browser/dist/settings.js +86 -0
- package/packages/tools/browser/dist/settings.js.map +1 -0
- package/packages/tools/browser/dist/telemetry.d.ts +203 -0
- package/packages/tools/browser/dist/telemetry.d.ts.map +1 -0
- package/packages/tools/browser/dist/telemetry.js +142 -0
- package/packages/tools/browser/dist/telemetry.js.map +1 -0
- package/packages/tools/browser/dist/types.d.ts +14 -3
- package/packages/tools/browser/dist/types.d.ts.map +1 -1
- package/packages/tools/browser/dist/types.js +9 -9
- package/packages/tools/browser/dist/types.js.map +1 -1
- package/packages/tools/email/dist/.tsbuildinfo +1 -1
- package/packages/tools/host/dist/.tsbuildinfo +1 -1
- package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/.tsbuildinfo +1 -1
- package/packages/tools/web/dist/.tsbuildinfo +1 -1
- package/packages/web/dist/assets/index-Bac-CdD-.css +1 -0
- package/packages/web/dist/assets/index-DI8bp_D7.js +146 -0
- package/packages/web/dist/assets/{lottie_light-CKJ88Yuk.js → lottie_light-CuiSMqnl.js} +1 -1
- package/packages/web/dist/build.json +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/precache.json +4 -4
- package/node_modules/@buddi/gateway/dist/web/apps.d.ts +0 -18
- package/node_modules/@buddi/gateway/dist/web/apps.d.ts.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/apps.js +0 -84
- package/node_modules/@buddi/gateway/dist/web/apps.js.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/tailscale.d.ts.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/tailscale.js.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/computer.d.ts +0 -153
- package/node_modules/@buddi/tool-browser/dist/computer.d.ts.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/computer.js +0 -392
- package/node_modules/@buddi/tool-browser/dist/computer.js.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/native/buddi-computer +0 -0
- package/node_modules/pino/test/browser-bindings.test.js +0 -114
- package/node_modules/pino/test/browser-redaction.test.js +0 -264
- package/node_modules/pino/test/browser-set-bindings.test.js +0 -99
- package/node_modules/pino/test/caller.test.js +0 -20
- package/node_modules/pino/test/fixtures/caller-loop.js +0 -6
- package/node_modules/pino/test/smoke.js +0 -59
- package/node_modules/pino/test/types/pino-import.tst.cts +0 -30
- package/node_modules/pino/test/types/pino-import.tst.js +0 -73
- package/node_modules/pino/test/types/pino-multistream.tst.ts +0 -49
- package/node_modules/pino/test/types/pino-top-export.tst.ts +0 -32
- package/node_modules/pino/test/types/pino-type-only.tst.ts +0 -77
- package/node_modules/pino/test/types/tsconfig.json +0 -10
- package/packages/gateway/dist/web/apps.d.ts +0 -18
- package/packages/gateway/dist/web/apps.d.ts.map +0 -1
- package/packages/gateway/dist/web/apps.js +0 -84
- package/packages/gateway/dist/web/apps.js.map +0 -1
- package/packages/gateway/dist/web/tailscale.d.ts.map +0 -1
- package/packages/gateway/dist/web/tailscale.js.map +0 -1
- package/packages/tools/browser/dist/computer.d.ts +0 -153
- package/packages/tools/browser/dist/computer.d.ts.map +0 -1
- package/packages/tools/browser/dist/computer.js +0 -392
- package/packages/tools/browser/dist/computer.js.map +0 -1
- package/packages/tools/browser/dist/native/buddi-computer +0 -0
- package/packages/web/dist/assets/index-CN1AXMI1.css +0 -1
- package/packages/web/dist/assets/index-CQRE9LJX.js +0 -145
|
@@ -56,7 +56,6 @@ import { carryOverDeps } from '../surfaces/carry-over.js';
|
|
|
56
56
|
import { deleteCarryOver } from '../surfaces/browser-handoff.js';
|
|
57
57
|
import { ProviderSettingsError } from '../providers.js';
|
|
58
58
|
import { ProviderAccountError } from '../provider-accounts.js';
|
|
59
|
-
import { listBrowserProfiles, listInstalledApps } from './apps.js';
|
|
60
59
|
import { agentSearchPath, EXAMPLES_AGENTS_DIR } from '../agents/catalog.js';
|
|
61
60
|
import { setDelegatesFromWeb } from './write.js';
|
|
62
61
|
import { mlxhBaseUrl, probeMlxh } from '../mlxh.js';
|
|
@@ -77,6 +76,7 @@ import { hostService } from '@buddi/tool-host';
|
|
|
77
76
|
import { listToolPermissions, revokeToolPermission, getArtifact, readArtifactBytes, artifactBytesExist, discardUnreferencedUpload, listLibrary, getLibraryEntry, decodeCursor, filterKey, textPreviewable, readArtifactPrefix, FILE_FAMILIES, LIBRARY_PAGE_MAX, getOwnerProfile, saveOwnerProfile, isKnownTimezone, listGroups, getGroup, createGroup, updateGroup, archiveGroup, deleteGroup, restoreGroup, clearGroupHistory, groupHistorySize, GROUP_UNDO_MS, GroupRefusal, createGroupConversation, listGroupConversations, latestGroupConversation, openGroupRequest, conversationGroup } from '@buddi/core';
|
|
78
77
|
import { EXPORT_MIME, MAX_EXPORT_SOURCE_BYTES, exportFormats, exportName } from '../export/document.js';
|
|
79
78
|
import { ExportRefused, runExport } from '../export/convert.js';
|
|
79
|
+
import { createVault } from '@buddi/core';
|
|
80
80
|
import { beginOnboarding, completeOnboarding, markStepDone, setOnboardingDetails, skipOnboarding, readWebSetting, writeWebSetting, isAssetKey, readPluginAsset } from '@buddi/core';
|
|
81
81
|
import { listMemory, setPreference, forgetPreference, updateNote, forgetNote } from '@buddi/tool-memory';
|
|
82
82
|
import { purgeGroups, stopGroupWork } from './group-lifecycle.js';
|
|
@@ -94,7 +94,14 @@ import { ATTACHMENTS_UNAVAILABLE, CHAT_CONVERSATIONS_LIMIT, CHAT_UNAVAILABLE, WE
|
|
|
94
94
|
import { readAgentAttention, streamAttention } from './attention.js';
|
|
95
95
|
import { PreviewApp, PreviewTickets, parsePreviewApiPath } from './preview.js';
|
|
96
96
|
import { allowedOrigins, isLoopback, webAssetsDir, webUrl } from './config.js';
|
|
97
|
-
import { TAILSCALE_SETTING_KEY, daemonWhois,
|
|
97
|
+
import { TAILSCALE_SETTING_KEY, daemonWhois, plausibleLogin, proxiedThroughTailscale, tailscaleProvider, tailscaleSelf, tailscaleServeCommand, } from './access/tailscale.js';
|
|
98
|
+
import { CLOUDFLARE_SETTING_KEY, cloudflareProvider, createJwks, normalizeTeamDomain, plausibleTeamDomain, validateCloudflareInput, } from './access/cloudflare.js';
|
|
99
|
+
import { arrivalOf } from './access/arrival.js';
|
|
100
|
+
import { CloudflareApiError, createCloudflareApi, CLOUDFLARE_PERMISSION_LINES, CLOUDFLARE_TOKEN_URL } from './access/cloudflare-api.js';
|
|
101
|
+
import { CLOUDFLARE_SETUP_KEY, checkSetupInput, claimSetupOperation, freshProgress, setupBusySentence, setupOperation, removeCloudflareSetup, runCloudflareSetup, } from './access/cloudflare-setup.js';
|
|
102
|
+
import { ownerSecretTokenStore } from './access/cloudflare-token.js';
|
|
103
|
+
import { createAccessRegistry } from './access/registry.js';
|
|
104
|
+
import { createIngress } from './access/ingress.js';
|
|
98
105
|
import { clientKey } from './client-key.js';
|
|
99
106
|
import { retryHref, sendSignedOut, wantsSignedOutPage } from './signed-out.js';
|
|
100
107
|
import { extensionEndpoint } from './extension.js';
|
|
@@ -116,6 +123,7 @@ import { createRequirements } from '../plugins/requires.js';
|
|
|
116
123
|
import { placesList, placesRoute } from './places.js';
|
|
117
124
|
import { peopleRoute } from './people.js';
|
|
118
125
|
import { syncDateMissions } from '../missions/dates.js';
|
|
126
|
+
import { resumeParkedForPage } from '../missions/parked.js';
|
|
119
127
|
import { OWNER_DATE_FORMATS, OWNER_TIME_FORMATS, validDayMonth } from '@buddi/core';
|
|
120
128
|
import { readFacts, webSettingsStore } from '../tips/facts.js';
|
|
121
129
|
import { dismissAgentOffer, isPendingAccept, raiseAgentOffers, readAgentOffers } from './agent-offers.js';
|
|
@@ -160,6 +168,21 @@ const PREVIEW_APPS = new WeakMap();
|
|
|
160
168
|
* reloads once the next process answers `/_buddi/ready` with a new `boot`.
|
|
161
169
|
*/
|
|
162
170
|
const CLOSING_SAYS = new WeakMap();
|
|
171
|
+
/** Each server's ingress listener (web/access/ingress.ts). */
|
|
172
|
+
const INGRESS_OF = new WeakMap();
|
|
173
|
+
/** Each server's request handler, for a listener without a socket of its own (the relay, provider 3). */
|
|
174
|
+
const DISPATCH_OF = new WeakMap();
|
|
175
|
+
/** The ingress listener belonging to a server built by `createWebApp`. */
|
|
176
|
+
export function ingressOf(server) {
|
|
177
|
+
return INGRESS_OF.get(server);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The request handler of a server built by `createWebApp`: what an in-process
|
|
181
|
+
* listener hands a request to after tagging its arrival (`markRequestArrival`).
|
|
182
|
+
*/
|
|
183
|
+
export function dispatchOf(server) {
|
|
184
|
+
return DISPATCH_OF.get(server);
|
|
185
|
+
}
|
|
163
186
|
/** How long a closing frame may take to reach the pages before the sockets go. */
|
|
164
187
|
const CLOSING_FLUSH_MS = 250;
|
|
165
188
|
/** The chat surface this server is running, if any. */
|
|
@@ -270,13 +293,13 @@ export function createWebApp(deps) {
|
|
|
270
293
|
// A locked dashboard drives nothing (docs/dashboard.md, "Lock screen").
|
|
271
294
|
if (await lock.locked(session))
|
|
272
295
|
return null;
|
|
273
|
-
if (session.via === '
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
296
|
+
if (session.via === 'provider') {
|
|
297
|
+
const confirmed = await access.confirm(session, req, now);
|
|
298
|
+
// "Could not ask", or a stray request without the provider's proof:
|
|
299
|
+
// no socket now, but the session stays.
|
|
300
|
+
if (confirmed.answer === 'unanswered' || confirmed.answer === 'refuse')
|
|
301
|
+
return null;
|
|
302
|
+
if (confirmed.answer === 'end') {
|
|
280
303
|
await sessions.destroy(session.id).catch(() => { });
|
|
281
304
|
return null;
|
|
282
305
|
}
|
|
@@ -427,6 +450,7 @@ export function createWebApp(deps) {
|
|
|
427
450
|
now: deps.now,
|
|
428
451
|
get timezone() { return deps.timezone; },
|
|
429
452
|
log,
|
|
453
|
+
browser: deps.browser ?? browserHost(deps.env ?? process.env),
|
|
430
454
|
...deps.chat,
|
|
431
455
|
})
|
|
432
456
|
: undefined;
|
|
@@ -438,6 +462,18 @@ export function createWebApp(deps) {
|
|
|
438
462
|
* Failures are the recovery's own business and land in the log.
|
|
439
463
|
*/
|
|
440
464
|
void chat?.recoverPendingInput().catch((err) => log(`web chat: recovering queued input failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
465
|
+
/*
|
|
466
|
+
* Give it back: the run that waited on the page carries on. A mission parked
|
|
467
|
+
* on it wakes (missions/parked.ts); otherwise the conversation the take-over
|
|
468
|
+
* held gets its turn. Either way with no message from the owner.
|
|
469
|
+
*/
|
|
470
|
+
const offGiveBack = (deps.browser ?? browserHost(deps.env ?? process.env)).onGiveBack?.((info) => {
|
|
471
|
+
void (async () => {
|
|
472
|
+
if (await resumeParkedForPage(deps.pool, info.conversationId, deps.now()))
|
|
473
|
+
return;
|
|
474
|
+
await chat?.continueAfterGiveBack({ conversationId: info.conversationId, agentId: info.agentId });
|
|
475
|
+
})().catch((err) => log(`browser: carrying on after the page was given back failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
476
|
+
});
|
|
441
477
|
const streams = new StreamBudget();
|
|
442
478
|
// A bundle script's run asks every time: its card offers no standing permission (`asksEachTime`).
|
|
443
479
|
const permissionScopes = (tool, envelope) => deps.registry.lookup(tool)?.reusableApproval && !asksEachTime(envelope)
|
|
@@ -483,55 +519,204 @@ export function createWebApp(deps) {
|
|
|
483
519
|
// ticket-and-session gate. The override is a test seam, nothing more.
|
|
484
520
|
const openAccess = deps.openAccess ?? (deps.env?.BUDDI_WEB_REQUIRE_AUTH !== '1' && isLoopback(deps.config.host));
|
|
485
521
|
/*
|
|
486
|
-
*
|
|
522
|
+
* Trusted access providers (web/access/): something in front of buddi
|
|
523
|
+
* proves who is knocking, buddi checks the proof itself, and its own
|
|
524
|
+
* `remote` session rules apply. Tailscale (provider 1) asks the local
|
|
525
|
+
* daemon; Cloudflare Access (provider 2) verifies the JWT Access signs.
|
|
487
526
|
*
|
|
488
527
|
* Which sessions were established that way is a field on the session itself
|
|
489
|
-
* (`via`), not a map beside it
|
|
490
|
-
*
|
|
491
|
-
* keeps a tailnet session from widening its own access (`PUT /api/tailscale`
|
|
528
|
+
* (`via: 'provider'` and `provider`), not a map beside it. It is what keeps
|
|
529
|
+
* a provider session from widening its own access (changing a provider
|
|
492
530
|
* wants a session from this machine) and what lets `/api/session` say how
|
|
493
531
|
* the browser got in.
|
|
494
532
|
*/
|
|
495
533
|
const whois = deps.tailscale?.whois ?? daemonWhois();
|
|
496
534
|
const tailscaleSelfOf = deps.tailscale?.self ?? (() => tailscaleSelf());
|
|
535
|
+
const jwks = deps.cloudflare?.jwks ?? createJwks({ log });
|
|
536
|
+
const boundPort = () => server.address()?.port ?? deps.config.port;
|
|
537
|
+
const accessCtx = {
|
|
538
|
+
dashboardPort: boundPort,
|
|
539
|
+
ingressPort: () => ingress.port(),
|
|
540
|
+
publicOrigin: () => deps.config.publicOrigin,
|
|
541
|
+
};
|
|
542
|
+
const tailscale = tailscaleProvider({ whois, self: tailscaleSelfOf, log });
|
|
543
|
+
const cloudflare = cloudflareProvider({ jwks, log, ingressProblem: () => ingress.problem() });
|
|
544
|
+
const access = createAccessRegistry({
|
|
545
|
+
providers: [tailscale, cloudflare],
|
|
546
|
+
readSetting: (key) => readWebSetting(deps.pool, key),
|
|
547
|
+
});
|
|
548
|
+
/** The command that publishes this dashboard on the tailnet, with this installation's own ports. */
|
|
549
|
+
const serveCommand = () => tailscaleServeCommand(boundPort(), deps.config.publicOrigin);
|
|
550
|
+
const readTailscaleSetting = async () => access.settingOf(tailscale);
|
|
551
|
+
/*
|
|
552
|
+
* The Cloudflare setting as last read, so the synchronous Origin check can
|
|
553
|
+
* honour the public address the panel stored. Refreshed on every read.
|
|
554
|
+
*/
|
|
555
|
+
let cloudflareSeen = null;
|
|
556
|
+
const readCloudflareSetting = async () => {
|
|
557
|
+
cloudflareSeen = await access.settingOf(cloudflare);
|
|
558
|
+
return cloudflareSeen;
|
|
559
|
+
};
|
|
560
|
+
/** Did this request come through a provider, or does it hold a session one minted? Then the block is read-only. */
|
|
561
|
+
const throughProvider = (req, session) => session.via === 'provider' || arrivalOf(req) !== 'main' || proxiedThroughTailscale(req);
|
|
562
|
+
/** The Tailscale panel's whole payload (unchanged by the move behind the provider interface). */
|
|
563
|
+
const tailscaleView = async (req, session) => {
|
|
564
|
+
const stored = await readTailscaleSetting();
|
|
565
|
+
const daemon = await tailscaleSelfOf();
|
|
566
|
+
return {
|
|
567
|
+
enabled: stored.enabled,
|
|
568
|
+
login: stored.login,
|
|
569
|
+
available: daemon.available,
|
|
570
|
+
self: daemon.self,
|
|
571
|
+
proxied: throughProvider(req, session),
|
|
572
|
+
// What the owner has to run on this machine, with this installation's own two ports in it.
|
|
573
|
+
serveCommand: serveCommand(),
|
|
574
|
+
};
|
|
575
|
+
};
|
|
576
|
+
/** The Cloudflare panel's payload: the stored fields, the status, the setup copy with the real ingress port. */
|
|
577
|
+
const cloudflareView = async (req, session) => {
|
|
578
|
+
const stored = await readCloudflareSetting();
|
|
579
|
+
const status = await cloudflare.status(stored, accessCtx);
|
|
580
|
+
const visit = cloudflare.lastVisit();
|
|
581
|
+
return {
|
|
582
|
+
enabled: stored.enabled,
|
|
583
|
+
teamDomain: stored.teamDomain,
|
|
584
|
+
aud: stored.aud,
|
|
585
|
+
email: stored.email,
|
|
586
|
+
publicOrigin: stored.publicOrigin,
|
|
587
|
+
status,
|
|
588
|
+
ingressPort: ingress.port() ?? accessCtx.dashboardPort() + 2,
|
|
589
|
+
listening: ingress.port() !== null,
|
|
590
|
+
lastVisit: visit ? { at: visit.at.toISOString(), email: visit.email } : null,
|
|
591
|
+
setup: cloudflare.setup(stored, accessCtx),
|
|
592
|
+
proxied: throughProvider(req, session),
|
|
593
|
+
};
|
|
594
|
+
};
|
|
497
595
|
/**
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
596
|
+
* Store a Cloudflare setting and do what a Save does: end the sessions it
|
|
597
|
+
* admitted unless the same person, team and application stay on, then bind
|
|
598
|
+
* or close the ingress listener. The panel's Save and "Set it up for me"
|
|
599
|
+
* both come through here.
|
|
501
600
|
*/
|
|
502
|
-
const
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
601
|
+
const applyCloudflareSetting = async (value) => {
|
|
602
|
+
const before = await readCloudflareSetting();
|
|
603
|
+
await writeWebSetting(deps.pool, CLOUDFLARE_SETTING_KEY, value);
|
|
604
|
+
await readCloudflareSetting();
|
|
605
|
+
const same = before.enabled && value.enabled && before.email.toLowerCase() === value.email.toLowerCase()
|
|
606
|
+
&& before.teamDomain === value.teamDomain && before.aud === value.aud;
|
|
607
|
+
if (!same) {
|
|
608
|
+
const forgotten = new Set();
|
|
609
|
+
await sessions.forget((s) => { const drop = s.via === 'provider' && s.provider === 'cloudflare-access'; if (drop && s.id)
|
|
610
|
+
forgotten.add(s.id); return drop; });
|
|
611
|
+
hand.revoke((lease) => forgotten.has(lease), 'Cloudflare access changed. Sign in again.');
|
|
509
612
|
}
|
|
510
|
-
|
|
613
|
+
await ingress.sync();
|
|
511
614
|
};
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
615
|
+
/*
|
|
616
|
+
* "Set it up for me" (access/cloudflare-setup.ts): one run at a time, in
|
|
617
|
+
* the background — the health wait lasts as long as the owner takes to run
|
|
618
|
+
* one command — and its progress kept here for the panel to poll. The token
|
|
619
|
+
* is an owner secret, read once per run.
|
|
620
|
+
*/
|
|
621
|
+
let cfTokens = deps.cloudflare?.tokens ?? null;
|
|
622
|
+
const tokenStore = () => (cfTokens ??= ownerSecretTokenStore(deps.pool, createVault({ env: deps.env ?? process.env })));
|
|
623
|
+
let setupRun = null;
|
|
624
|
+
const readSetupRecord = async () => {
|
|
625
|
+
const row = await readWebSetting(deps.pool, CLOUDFLARE_SETUP_KEY);
|
|
626
|
+
return row && typeof row === 'object' && typeof row.host === 'string' ? row : null;
|
|
627
|
+
};
|
|
628
|
+
const setupDepsFor = (token, lease, signal) => ({
|
|
629
|
+
api: createCloudflareApi({ token, transport: deps.cloudflare?.api?.transport, baseUrl: deps.cloudflare?.api?.baseUrl }),
|
|
630
|
+
ingressPort: ingress.port() ?? (askedIngressPort() || null) ?? accessCtx.dashboardPort() + 2,
|
|
631
|
+
platform: deps.cloudflare?.platform ?? process.platform,
|
|
632
|
+
readSetting: readCloudflareSetting,
|
|
633
|
+
saveSetting: applyCloudflareSetting,
|
|
634
|
+
readRecord: readSetupRecord,
|
|
635
|
+
saveRecord: (record) => writeWebSetting(deps.pool, CLOUDFLARE_SETUP_KEY, record),
|
|
636
|
+
test: (team) => jwks.refresh(team),
|
|
637
|
+
...(deps.cloudflare?.setup ?? {}),
|
|
638
|
+
signal,
|
|
639
|
+
lease,
|
|
640
|
+
});
|
|
641
|
+
const setupView = async () => {
|
|
642
|
+
const record = await readSetupRecord();
|
|
643
|
+
return {
|
|
644
|
+
progress: setupRun?.progress ?? freshProgress(record?.host ?? '', record?.email ?? ''),
|
|
645
|
+
tokenStored: await tokenStore().has().catch(() => false),
|
|
646
|
+
record: record ? { host: record.host, email: record.email, zone: record.zone.name, teamDomain: record.teamDomain } : null,
|
|
647
|
+
permissions: CLOUDFLARE_PERMISSION_LINES,
|
|
648
|
+
tokenUrl: CLOUDFLARE_TOKEN_URL,
|
|
649
|
+
ingressPort: ingress.port() ?? (askedIngressPort() || null) ?? accessCtx.dashboardPort() + 2,
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
/** Run in the background; the lease (claimed by the caller) goes when the run ends. */
|
|
653
|
+
const startSetup = (lease, job, first) => {
|
|
654
|
+
const abort = new AbortController();
|
|
655
|
+
const run = { progress: first, abort, done: Promise.resolve() };
|
|
656
|
+
setupRun = run;
|
|
657
|
+
run.done = job((p) => { run.progress = p; }, abort.signal)
|
|
658
|
+
.then((p) => { run.progress = p; })
|
|
659
|
+
.catch(() => { run.progress = { ...run.progress, state: 'failed', error: 'The setup stopped unexpectedly. Try again.' }; })
|
|
660
|
+
.finally(() => lease.release());
|
|
661
|
+
};
|
|
662
|
+
/*
|
|
663
|
+
* A setting written elsewhere (`buddi access cloudflare setup` writes the
|
|
664
|
+
* database directly) reaches the ingress listener here: bound or closed
|
|
665
|
+
* within a quarter of a minute.
|
|
666
|
+
*/
|
|
667
|
+
const ingressResync = setInterval(() => {
|
|
668
|
+
void readCloudflareSetting().then((setting) => {
|
|
669
|
+
if (setting.enabled !== (ingress.port() !== null))
|
|
670
|
+
return ingress.sync();
|
|
671
|
+
return undefined;
|
|
672
|
+
}).catch(() => undefined);
|
|
673
|
+
}, 15_000);
|
|
674
|
+
ingressResync.unref?.();
|
|
675
|
+
/** Every provider's row, for "Sign in from elsewhere". */
|
|
676
|
+
const accessView = async (req, session) => ({
|
|
677
|
+
proxied: throughProvider(req, session),
|
|
678
|
+
providers: await Promise.all(access.providers.map(async (p) => {
|
|
679
|
+
const setting = await access.settingOf(p);
|
|
680
|
+
return { id: p.id, title: p.title, identity: p.identity, proxy: p.proxy, enabled: p.enabled(setting), status: await p.status(setting, accessCtx) };
|
|
681
|
+
})),
|
|
682
|
+
});
|
|
683
|
+
/*
|
|
684
|
+
* The ingress listener (specs/trusted-access.md §3.3): a second loopback
|
|
685
|
+
* listener, the dashboard's port + 2 (or `BUDDI_INGRESS_PORT`), bound only
|
|
686
|
+
* while a this-machine provider other than Tailscale is on. Every request
|
|
687
|
+
* on it is remote, whatever its headers or Host say, and it never passes a
|
|
688
|
+
* loopback-only check. cloudflared points here, never at the dashboard's
|
|
689
|
+
* own port, so a tunnel arrival can never be mistaken for this machine.
|
|
517
690
|
*/
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
691
|
+
/** `BUDDI_INGRESS_PORT`, when it names a port. */
|
|
692
|
+
function askedIngressPort() {
|
|
693
|
+
const raw = (deps.env ?? process.env).BUDDI_INGRESS_PORT?.trim();
|
|
694
|
+
const asked = raw ? Number(raw) : NaN;
|
|
695
|
+
return Number.isInteger(asked) && asked >= 0 && asked <= 65535 ? asked : null;
|
|
696
|
+
}
|
|
697
|
+
const ingress = createIngress({
|
|
698
|
+
onRequest: (req, res) => onRequest(req, res),
|
|
699
|
+
onUpgrade: (req, socket, head) => { server.emit('upgrade', req, socket, head); },
|
|
700
|
+
port: () => askedIngressPort() ?? (deps.config.port === 0 ? 0 : boundPort() + 2),
|
|
701
|
+
wanted: async () => (await readCloudflareSetting()).enabled,
|
|
521
702
|
log,
|
|
522
|
-
now: () => now,
|
|
523
|
-
onRefusal,
|
|
524
703
|
});
|
|
525
704
|
/**
|
|
526
705
|
* The pair a browser holds: the HttpOnly session and the readable CSRF value
|
|
527
706
|
* the page has to echo back in a header. Both carry the same `Max-Age`, which
|
|
528
707
|
* is the lifetime this session's scope earned it.
|
|
529
708
|
*/
|
|
709
|
+
/*
|
|
710
|
+
* Secure cookies for a remote session behind an HTTPS proxy: the configured
|
|
711
|
+
* public origin, or anything on the ingress listener (Cloudflare's edge
|
|
712
|
+
* always speaks HTTPS to the browser).
|
|
713
|
+
*/
|
|
714
|
+
const secureCookies = (req, scope) => scope === 'remote' && (!!deps.config.publicOrigin || arrivalOf(req) === 'ingress');
|
|
530
715
|
const sessionCookies = (req, session) => {
|
|
531
716
|
const maxAgeSeconds = SessionStore.maxAgeSeconds(session);
|
|
532
717
|
return [
|
|
533
|
-
cookieHeader(sessionCookieName(cookiePort(req)), session.id, { httpOnly: true, maxAgeSeconds, secure: session.scope
|
|
534
|
-
cookieHeader(csrfCookieName(cookiePort(req)), session.csrf, { httpOnly: false, maxAgeSeconds, secure: session.scope
|
|
718
|
+
cookieHeader(sessionCookieName(cookiePort(req)), session.id, { httpOnly: true, maxAgeSeconds, secure: secureCookies(req, session.scope) }),
|
|
719
|
+
cookieHeader(csrfCookieName(cookiePort(req)), session.csrf, { httpOnly: false, maxAgeSeconds, secure: secureCookies(req, session.scope) }),
|
|
535
720
|
];
|
|
536
721
|
};
|
|
537
722
|
/**
|
|
@@ -540,7 +725,7 @@ export function createWebApp(deps) {
|
|
|
540
725
|
* polling page then sends no credential at all, which counts as nothing.
|
|
541
726
|
*/
|
|
542
727
|
const expiredCookies = (req) => {
|
|
543
|
-
const secure = requestScope(req)
|
|
728
|
+
const secure = secureCookies(req, requestScope(req));
|
|
544
729
|
return [
|
|
545
730
|
cookieHeader(sessionCookieName(cookiePort(req)), '', { httpOnly: true, maxAgeSeconds: 0, secure }),
|
|
546
731
|
cookieHeader(csrfCookieName(cookiePort(req)), '', { httpOnly: false, maxAgeSeconds: 0, secure }),
|
|
@@ -548,9 +733,23 @@ export function createWebApp(deps) {
|
|
|
548
733
|
};
|
|
549
734
|
/**
|
|
550
735
|
* What the signed-out page should offer this request: how it arrived,
|
|
551
|
-
*
|
|
736
|
+
* which provider can sign it in, why it could not, and whether a lockout is
|
|
737
|
+
* running.
|
|
552
738
|
*/
|
|
553
|
-
const signedOutFor = async (req, pathname, search, now,
|
|
739
|
+
const signedOutFor = async (req, pathname, search, now, refused, key) => {
|
|
740
|
+
const lockedForMs = limiter.retryAfterMs(key, now);
|
|
741
|
+
const locked = lockedForMs > 0 ? { lockedForMs } : {};
|
|
742
|
+
if (arrivalOf(req) === 'ingress') {
|
|
743
|
+
return {
|
|
744
|
+
retry: retryHref(pathname, search),
|
|
745
|
+
arrived: 'remote',
|
|
746
|
+
provider: {
|
|
747
|
+
title: cloudflare.title,
|
|
748
|
+
...(refused?.provider === 'cloudflare-access' ? { refusal: refused.refusal.refusal, kind: refused.refusal.kind } : { refusal: 'no-assertion', kind: 'other' }),
|
|
749
|
+
},
|
|
750
|
+
...locked,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
554
753
|
const proxied = proxiedThroughTailscale(req);
|
|
555
754
|
let publicHost;
|
|
556
755
|
try {
|
|
@@ -569,14 +768,14 @@ export function createWebApp(deps) {
|
|
|
569
768
|
const scope = requestScope(req);
|
|
570
769
|
const arrived = proxied || (publicHost !== undefined && host === publicHost) ? 'tailnet' : scope === 'local' ? 'local' : 'remote';
|
|
571
770
|
const setting = arrived === 'tailnet' ? await readTailscaleSetting() : null;
|
|
572
|
-
const
|
|
771
|
+
const tailscaleRefusal = refused?.provider === 'tailscale' ? refused.refusal : undefined;
|
|
573
772
|
return {
|
|
574
773
|
retry: retryHref(pathname, search),
|
|
575
774
|
arrived,
|
|
576
|
-
tailscaleSignIn: !!setting?.enabled &&
|
|
577
|
-
...(
|
|
578
|
-
...(
|
|
579
|
-
...
|
|
775
|
+
tailscaleSignIn: !!setting?.enabled && tailscaleRefusal?.kind !== 'login',
|
|
776
|
+
...(tailscaleRefusal?.kind === 'login' ? { tailscaleRefusal: tailscaleRefusal.sentence } : {}),
|
|
777
|
+
...(tailscaleRefusal?.kind === 'unanswered' ? { tailscaleUnanswered: true } : {}),
|
|
778
|
+
...locked,
|
|
580
779
|
};
|
|
581
780
|
};
|
|
582
781
|
/**
|
|
@@ -585,7 +784,16 @@ export function createWebApp(deps) {
|
|
|
585
784
|
* loopback page and the tailnet page each keep their own pair. Set, read and
|
|
586
785
|
* checked through this one function.
|
|
587
786
|
*/
|
|
588
|
-
const cookiePort = (req) =>
|
|
787
|
+
const cookiePort = (req) => {
|
|
788
|
+
// Cloudflare's edge serves the page on HTTPS's own port, whatever
|
|
789
|
+
// cloudflared says on the way in; the page names its cookie by it.
|
|
790
|
+
if (arrivalOf(req) === 'ingress') {
|
|
791
|
+
const host = req.headers.host ?? '';
|
|
792
|
+
if (!/:\d+$/.test(host.replace(/^\[[^\]]*\]/, '')))
|
|
793
|
+
return 443;
|
|
794
|
+
}
|
|
795
|
+
return requestPort(req, server.address()?.port ?? deps.config.port, deps.config.publicOrigin);
|
|
796
|
+
};
|
|
589
797
|
/**
|
|
590
798
|
* The origins a write may claim, resolved against the port actually bound.
|
|
591
799
|
*
|
|
@@ -596,8 +804,13 @@ export function createWebApp(deps) {
|
|
|
596
804
|
let originCache;
|
|
597
805
|
const allowed = () => {
|
|
598
806
|
const bound = server.address()?.port ?? deps.config.port;
|
|
599
|
-
|
|
600
|
-
|
|
807
|
+
// The public address the Cloudflare panel stored, while that provider is on.
|
|
808
|
+
const extra = cloudflareSeen?.enabled ? cloudflareSeen.publicOrigin : '';
|
|
809
|
+
if (originCache?.port !== bound || originCache.extra !== extra) {
|
|
810
|
+
const set = new Set(allowedOrigins({ ...deps.config, port: bound }));
|
|
811
|
+
if (extra)
|
|
812
|
+
set.add(extra);
|
|
813
|
+
originCache = { port: bound, extra, set };
|
|
601
814
|
}
|
|
602
815
|
return originCache.set;
|
|
603
816
|
};
|
|
@@ -605,7 +818,7 @@ export function createWebApp(deps) {
|
|
|
605
818
|
// caller that needs to drain it on shutdown (or in a test) can, without
|
|
606
819
|
// `createWebApp` growing a second return value every existing caller would
|
|
607
820
|
// have to unpack.
|
|
608
|
-
|
|
821
|
+
function onRequest(req, res) {
|
|
609
822
|
handle(req, res).catch((err) => {
|
|
610
823
|
// The lock could not say whether this request may pass: refused, never let in (web/lock.ts).
|
|
611
824
|
if (err instanceof LockUnavailable) {
|
|
@@ -622,9 +835,14 @@ export function createWebApp(deps) {
|
|
|
622
835
|
else
|
|
623
836
|
res.end();
|
|
624
837
|
});
|
|
625
|
-
}
|
|
838
|
+
}
|
|
839
|
+
const server = createServer(onRequest);
|
|
626
840
|
if (chat)
|
|
627
841
|
WEB_CHATS.set(server, chat);
|
|
842
|
+
INGRESS_OF.set(server, ingress);
|
|
843
|
+
// The seam the relay (provider 3) hands its in-process requests to,
|
|
844
|
+
// tagged `markRequestArrival(req, 'relay')` first. Never replayed as HTTP to 127.0.0.1.
|
|
845
|
+
DISPATCH_OF.set(server, onRequest);
|
|
628
846
|
PREVIEW_APPS.set(server, previews);
|
|
629
847
|
CLOSING_SAYS.set(server, async () => {
|
|
630
848
|
const said = frame('closing', goingAway === undefined ? {} : { for: goingAway });
|
|
@@ -655,13 +873,25 @@ export function createWebApp(deps) {
|
|
|
655
873
|
// rather than in `startWebServer` so every caller, tests included, has it.
|
|
656
874
|
extension.attach(server);
|
|
657
875
|
extension.attachPath(REMOTE_HAND_SOCKET_PATH, (req, socket, head) => hand.upgrade(req, socket, head));
|
|
658
|
-
server.once('close', () => { extension.shutdown(); hand.shutdown(); clearInterval(idleSweep); });
|
|
876
|
+
server.once('close', () => { extension.shutdown(); hand.shutdown(); clearInterval(idleSweep); clearInterval(ingressResync); setupRun?.abort.abort(); void ingress.close(); });
|
|
877
|
+
server.once('close', () => offGiveBack?.());
|
|
659
878
|
return server;
|
|
660
879
|
async function handle(req, res) {
|
|
661
880
|
const now = deps.now();
|
|
662
881
|
const method = (req.method ?? 'GET').toUpperCase();
|
|
663
882
|
const url = parseUrl(req);
|
|
664
|
-
|
|
883
|
+
/*
|
|
884
|
+
* The bucket failed sign-ins count against (client-key.ts, §7.5): by the
|
|
885
|
+
* arrival path, so a stranger behind a tunnel can never lock out this
|
|
886
|
+
* machine or the tailnet. A request on the ingress listener is asked of
|
|
887
|
+
* its provider at once — a JWT check against cached keys — because its
|
|
888
|
+
* bucket depends on it: `cf:unverified` until it verifies, then the
|
|
889
|
+
* client's own address.
|
|
890
|
+
*/
|
|
891
|
+
let key = access.bucketOf(req) ?? clientKey(req);
|
|
892
|
+
const early = arrivalOf(req) === 'main' ? null : await access.identify(req, now);
|
|
893
|
+
if (early?.result.ok && early.result.identity.bucket)
|
|
894
|
+
key = early.result.identity.bucket;
|
|
665
895
|
// No CORS, and therefore no preflight.
|
|
666
896
|
if (method === 'OPTIONS')
|
|
667
897
|
return sendEmpty(res, 405);
|
|
@@ -763,12 +993,12 @@ export function createWebApp(deps) {
|
|
|
763
993
|
const presentedSession = cookies[sessionCookieName(cookiePort(req))];
|
|
764
994
|
let session = await sessions.resolve(presentedSession, scope, now);
|
|
765
995
|
/*
|
|
766
|
-
* Why
|
|
767
|
-
* "this
|
|
768
|
-
* says; every other reason is the ordinary "you're
|
|
996
|
+
* Why a provider gave this request no identity, when it was asked. Only
|
|
997
|
+
* "this person is not the one allowed" and "could not ask" change what
|
|
998
|
+
* the signed-out page says; every other reason is the ordinary "you're
|
|
999
|
+
* signed out".
|
|
769
1000
|
*/
|
|
770
|
-
let refusal;
|
|
771
|
-
const noteRefusal = (reason) => { refusal = reason; };
|
|
1001
|
+
let refused = early && !early.result.ok ? { provider: early.provider.id, refusal: early.result } : undefined;
|
|
772
1002
|
/*
|
|
773
1003
|
* Set when the browser presented a session that is gone: the refusal then
|
|
774
1004
|
* expires its cookies, so it stops presenting them (and stops counting).
|
|
@@ -777,7 +1007,7 @@ export function createWebApp(deps) {
|
|
|
777
1007
|
/*
|
|
778
1008
|
* The answer to a refused request: the signed-out page for a person
|
|
779
1009
|
* opening a page, the empty status for everything else (docs/web.md).
|
|
780
|
-
* 401 is "signed out", 429 "too many tries from here", 503 "
|
|
1010
|
+
* 401 is "signed out", 429 "too many tries from here", 503 "the provider
|
|
781
1011
|
* could not be asked; the session is still good, try again".
|
|
782
1012
|
*/
|
|
783
1013
|
const refuse = async (status = 401) => {
|
|
@@ -788,33 +1018,40 @@ export function createWebApp(deps) {
|
|
|
788
1018
|
headers['Retry-After'] = '5';
|
|
789
1019
|
if (!wantsSignedOutPage(req, method, url.pathname))
|
|
790
1020
|
return sendEmpty(res, status, headers);
|
|
791
|
-
return sendSignedOut(res, await signedOutFor(req, url.pathname, url.search, now,
|
|
1021
|
+
return sendSignedOut(res, await signedOutFor(req, url.pathname, url.search, now, refused, key), headers, status);
|
|
792
1022
|
};
|
|
793
|
-
/* A
|
|
1023
|
+
/* A provider session this request ended: not a guess, so never a failed sign-in. */
|
|
794
1024
|
let revoked = false;
|
|
795
1025
|
/*
|
|
796
|
-
* A
|
|
1026
|
+
* A provider session is re-confirmed on every single request.
|
|
797
1027
|
*
|
|
798
|
-
* A cookie on its own would be a bearer token the
|
|
799
|
-
* loosely related to: it would outlive the setting being turned off,
|
|
800
|
-
* allowed login being changed, and the device being handed to somebody
|
|
801
|
-
* else. So the
|
|
802
|
-
* reused for a minute
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
* can only do if it is still the person the owner allowed.
|
|
1028
|
+
* A cookie on its own would be a bearer token the provider's identity is
|
|
1029
|
+
* only loosely related to: it would outlive the setting being turned off,
|
|
1030
|
+
* the allowed login being changed, and the device being handed to somebody
|
|
1031
|
+
* else. So the provider is asked again — Tailscale's daemon (a whois
|
|
1032
|
+
* answer is reused for a minute), Cloudflare's JWT on this very request —
|
|
1033
|
+
* and the person it names now must be the one this session was minted
|
|
1034
|
+
* for. Anything else and the session is gone, not merely ignored.
|
|
806
1035
|
*/
|
|
807
|
-
if (session?.via === '
|
|
808
|
-
const confirmed = await
|
|
809
|
-
if (
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1036
|
+
if (session?.via === 'provider') {
|
|
1037
|
+
const confirmed = await access.confirm(session, req, now);
|
|
1038
|
+
if (confirmed.refusal)
|
|
1039
|
+
refused = { provider: session.provider, refusal: confirmed.refusal };
|
|
1040
|
+
/*
|
|
1041
|
+
* The provider could not be asked (a daemon busy or starting, keys that
|
|
1042
|
+
* could not be fetched). That is not an answer about anyone, so the
|
|
1043
|
+
* session is not ended for it and nothing is counted. This request waits.
|
|
1044
|
+
*/
|
|
1045
|
+
if (confirmed.answer === 'unanswered')
|
|
1046
|
+
return refuse(503);
|
|
1047
|
+
/*
|
|
1048
|
+
* This request lacks the provider's proof (Cloudflare's header), but
|
|
1049
|
+
* the session is not ended for it: a stray request without the header
|
|
1050
|
+
* must not sign the owner out. Nothing is counted either.
|
|
1051
|
+
*/
|
|
1052
|
+
if (confirmed.answer === 'refuse')
|
|
1053
|
+
return refuse(401);
|
|
1054
|
+
if (confirmed.answer === 'end') {
|
|
818
1055
|
const ended = session.id;
|
|
819
1056
|
// A hand this session was holding does not outlive the session.
|
|
820
1057
|
hand.revoke((lease) => lease === ended);
|
|
@@ -823,7 +1060,7 @@ export function createWebApp(deps) {
|
|
|
823
1060
|
revoked = true;
|
|
824
1061
|
forgetCookies = true;
|
|
825
1062
|
// The identity on this very request may still earn a new session below.
|
|
826
|
-
|
|
1063
|
+
refused = undefined;
|
|
827
1064
|
}
|
|
828
1065
|
}
|
|
829
1066
|
/*
|
|
@@ -848,26 +1085,32 @@ export function createWebApp(deps) {
|
|
|
848
1085
|
res.setHeader('Set-Cookie', sessionCookies(req, session));
|
|
849
1086
|
}
|
|
850
1087
|
/*
|
|
851
|
-
* Signed in through
|
|
1088
|
+
* Signed in through a trusted access provider.
|
|
852
1089
|
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
*
|
|
858
|
-
*
|
|
859
|
-
*
|
|
1090
|
+
* Tailscale: the proxy runs on this machine and the daemon confirms who
|
|
1091
|
+
* is behind the forwarded address. Cloudflare Access: the JWT Access
|
|
1092
|
+
* signed verifies against the team's keys, for this application, naming
|
|
1093
|
+
* the allowed email, and it arrived on the ingress listener. When that
|
|
1094
|
+
* agrees with the person the owner allowed, the request gets a `remote`
|
|
1095
|
+
* session exactly as the ticket exchange would have minted one — same
|
|
1096
|
+
* cookies, same 12 hours, same CSRF on every write. Anything less falls
|
|
1097
|
+
* through to the 401 below. A provider identity signs in during a lockout.
|
|
860
1098
|
*/
|
|
861
1099
|
if (!session) {
|
|
862
|
-
const
|
|
863
|
-
if (
|
|
1100
|
+
const asked = early ?? await access.identify(req, now);
|
|
1101
|
+
if (asked && !asked.result.ok)
|
|
1102
|
+
refused = { provider: asked.provider.id, refusal: asked.result };
|
|
1103
|
+
if (asked?.result.ok) {
|
|
1104
|
+
const identity = asked.result.identity;
|
|
864
1105
|
limiter.reset(key);
|
|
865
1106
|
const locked = await lock.startLocked('browser');
|
|
1107
|
+
const capMs = Math.min(asked.provider.absoluteCapMs, identity.expiresAt ? Math.max(0, identity.expiresAt.getTime() - now.getTime()) : asked.provider.absoluteCapMs);
|
|
866
1108
|
session = sessions.create('remote', now, {
|
|
867
|
-
via: '
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1109
|
+
via: 'provider',
|
|
1110
|
+
provider: identity.provider,
|
|
1111
|
+
providerSubject: identity.subject,
|
|
1112
|
+
...(identity.detail ? { providerDetail: identity.detail } : {}),
|
|
1113
|
+
absoluteCapMs: capMs,
|
|
871
1114
|
}, locked ? { locked } : {});
|
|
872
1115
|
res.setHeader('Set-Cookie', sessionCookies(req, session));
|
|
873
1116
|
}
|
|
@@ -882,14 +1125,26 @@ export function createWebApp(deps) {
|
|
|
882
1125
|
// the same stale cookie counts once however often it is sent: all tailnet
|
|
883
1126
|
// and tunnel traffic shares 127.0.0.1, so a forgotten tab must not be
|
|
884
1127
|
// able to lock the owner out of every way in.
|
|
885
|
-
|
|
1128
|
+
//
|
|
1129
|
+
// A provider's credential that failed (a Cloudflare assertion that does
|
|
1130
|
+
// not verify) is an attempt too, cookie or not, in the bucket the
|
|
1131
|
+
// provider names (per Cf-Connecting-Ip). No assertion at all, or keys
|
|
1132
|
+
// that could not be fetched, carry no attempt.
|
|
1133
|
+
const tried = refused?.refusal.attempt;
|
|
1134
|
+
if (!presentedSession && !tried)
|
|
886
1135
|
return refuse();
|
|
887
|
-
|
|
1136
|
+
if (tried)
|
|
1137
|
+
key = tried.bucket;
|
|
1138
|
+
if (presentedSession)
|
|
1139
|
+
forgetCookies = true;
|
|
888
1140
|
if (revoked)
|
|
889
1141
|
return refuse();
|
|
890
1142
|
if (limiter.blocked(key, now))
|
|
891
1143
|
return refuse(429);
|
|
892
|
-
|
|
1144
|
+
if (tried)
|
|
1145
|
+
limiter.failCredential(key, tried.credential, now);
|
|
1146
|
+
if (presentedSession)
|
|
1147
|
+
limiter.failCredential(key, presentedSession, now);
|
|
893
1148
|
return refuse();
|
|
894
1149
|
}
|
|
895
1150
|
/*
|
|
@@ -1088,6 +1343,10 @@ export function createWebApp(deps) {
|
|
|
1088
1343
|
now: deps.now,
|
|
1089
1344
|
agents: () => deps.catalog.list(),
|
|
1090
1345
|
plugins: () => deps.registry.manifests().map((m) => m.name),
|
|
1346
|
+
appsWithoutPlugin: () => {
|
|
1347
|
+
const apps = browser.status().routes?.find((route) => route.kind === 'apps');
|
|
1348
|
+
return apps !== undefined && apps.installed === false && apps.mode !== undefined && apps.mode !== 'off';
|
|
1349
|
+
},
|
|
1091
1350
|
needsSetup: async () => {
|
|
1092
1351
|
const out = [];
|
|
1093
1352
|
for (const manifest of deps.registry.manifests()) {
|
|
@@ -1387,15 +1646,16 @@ export function createWebApp(deps) {
|
|
|
1387
1646
|
const permissions = (await listToolPermissions(deps.pool, deps.ctx.ownerId)).filter(p => p.tool === 'host.exec' && (!agentId || p.agentId === agentId) && (!conversationId || !p.conversationId || p.conversationId === conversationId));
|
|
1388
1647
|
return sendJson(res, 200, { permissions, runs: host.runs(deps.ctx.ownerId, agentId, conversationId) });
|
|
1389
1648
|
}
|
|
1390
|
-
case '/api/host/apps':
|
|
1391
|
-
return sendJson(res, 200, { apps: await listInstalledApps() });
|
|
1392
|
-
case '/api/host/browser-profiles':
|
|
1393
|
-
return sendJson(res, 200, { profiles: await listBrowserProfiles(q.get('app') ?? '') });
|
|
1394
1649
|
case '/api/extension':
|
|
1395
1650
|
return sendJson(res, 200, await extension.view());
|
|
1396
1651
|
case '/api/browser':
|
|
1397
1652
|
return sendJson(res, 200, q.has('conversationId') && q.has('agentId')
|
|
1398
1653
|
? browser.status({ agentId: q.get('agentId'), conversationId: q.get('conversationId') }) : browser.status());
|
|
1654
|
+
case '/api/browser/telemetry': {
|
|
1655
|
+
// Stops by cause, cards and routes over the last week: how flakiness is seen to fall.
|
|
1656
|
+
const summary = browser.telemetrySummary?.(Number(q.get('days') ?? '7') || 7);
|
|
1657
|
+
return sendJson(res, 200, summary ?? { days: 7, tasks: 0, stops: 0, cards: 0, byCause: [], routes: {}, stopsPerTask: 0 });
|
|
1658
|
+
}
|
|
1399
1659
|
case '/api/browser/screenshot': {
|
|
1400
1660
|
const expectedSession = url.searchParams.get('sessionId');
|
|
1401
1661
|
const current = browser.status(expectedSession !== null ? { sessionId: expectedSession } : undefined);
|
|
@@ -1434,10 +1694,14 @@ export function createWebApp(deps) {
|
|
|
1434
1694
|
// from the page rather than implied by a number in a source file.
|
|
1435
1695
|
scope: session.scope,
|
|
1436
1696
|
// How this browser got in. `local` is the open loopback mint,
|
|
1437
|
-
// `ticket` the five-minute ticket exchange,
|
|
1438
|
-
//
|
|
1439
|
-
|
|
1440
|
-
|
|
1697
|
+
// `ticket` the five-minute ticket exchange, or the provider that
|
|
1698
|
+
// verified it (`tailscale`, `cloudflare-access`) — and then the
|
|
1699
|
+
// name to greet.
|
|
1700
|
+
signedInThrough: session.via === 'provider' ? session.provider : session.via,
|
|
1701
|
+
...(session.via === 'provider' ? { provider: session.provider, providerSubject: session.providerSubject } : {}),
|
|
1702
|
+
...(session.via === 'provider' && session.provider === 'tailscale'
|
|
1703
|
+
? { tailscaleName: session.providerDetail?.name ?? session.providerSubject, tailscaleLogin: session.providerSubject }
|
|
1704
|
+
: {}),
|
|
1441
1705
|
expiresAt: session.expiresAt.toISOString(),
|
|
1442
1706
|
// What this gateway is running. The page keeps it across an
|
|
1443
1707
|
// upgrade so that "it came back" can be told from "it is still
|
|
@@ -1452,20 +1716,24 @@ export function createWebApp(deps) {
|
|
|
1452
1716
|
* memory), and whether this very request came through the proxy —
|
|
1453
1717
|
* which is what disables the switch on a tailnet browser.
|
|
1454
1718
|
*/
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
return sendJson(res, 200,
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1719
|
+
// `/api/tailscale` stays one release as an alias (docs/api.md).
|
|
1720
|
+
case '/api/tailscale':
|
|
1721
|
+
case '/api/access/tailscale':
|
|
1722
|
+
return sendJson(res, 200, await tailscaleView(req, session));
|
|
1723
|
+
/*
|
|
1724
|
+
* "Sign in from elsewhere": every provider's row — its status in one
|
|
1725
|
+
* line — and whether this very request came through one, which makes
|
|
1726
|
+
* the whole block read-only.
|
|
1727
|
+
*/
|
|
1728
|
+
case '/api/access':
|
|
1729
|
+
return sendJson(res, 200, await accessView(req, session));
|
|
1730
|
+
case '/api/access/cloudflare-access':
|
|
1731
|
+
return sendJson(res, 200, await cloudflareView(req, session));
|
|
1732
|
+
case '/api/access/cloudflare-access/setup':
|
|
1733
|
+
// The install line holds the tunnel's connector token: this machine only.
|
|
1734
|
+
if (session.via !== 'local')
|
|
1735
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
1736
|
+
return sendJson(res, 200, await setupView());
|
|
1469
1737
|
case '/api/overview':
|
|
1470
1738
|
return sendJson(res, 200, {
|
|
1471
1739
|
...(await readOverview({
|
|
@@ -2225,7 +2493,7 @@ export function createWebApp(deps) {
|
|
|
2225
2493
|
* everything else.
|
|
2226
2494
|
*/
|
|
2227
2495
|
if (method === 'PUT') {
|
|
2228
|
-
const puttable = ['/api/backups/schedule', '/api/backups/passphrase', '/api/version/check', '/api/tailscale', '/api/notifications/settings', '/api/notifications/focus'];
|
|
2496
|
+
const puttable = ['/api/backups/schedule', '/api/backups/passphrase', '/api/version/check', '/api/tailscale', '/api/access/tailscale', '/api/access/cloudflare-access', '/api/notifications/settings', '/api/notifications/focus'];
|
|
2229
2497
|
if (!puttable.includes(path))
|
|
2230
2498
|
return sendEmpty(res, 405);
|
|
2231
2499
|
let put;
|
|
@@ -2235,7 +2503,20 @@ export function createWebApp(deps) {
|
|
|
2235
2503
|
catch {
|
|
2236
2504
|
return sendJson(res, 400, { error: 'request body must be JSON' });
|
|
2237
2505
|
}
|
|
2238
|
-
if (path === '/api/
|
|
2506
|
+
if (path === '/api/access/cloudflare-access') {
|
|
2507
|
+
// Who may widen access: only a browser on this machine, as for Tailscale below.
|
|
2508
|
+
if (session.via !== 'local') {
|
|
2509
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2510
|
+
}
|
|
2511
|
+
const checked = validateCloudflareInput(put);
|
|
2512
|
+
if (!checked.ok)
|
|
2513
|
+
return sendJson(res, 400, { error: checked.error });
|
|
2514
|
+
await applyCloudflareSetting(checked.value);
|
|
2515
|
+
// On Save buddi fetches the team's keys once and says whether it worked.
|
|
2516
|
+
const test = checked.value.enabled ? await jwks.refresh(checked.value.teamDomain) : null;
|
|
2517
|
+
return sendJson(res, 200, { ...(await cloudflareView(req, session)), ...(test ? { test } : {}) });
|
|
2518
|
+
}
|
|
2519
|
+
if (path === '/api/tailscale' || path === '/api/access/tailscale') {
|
|
2239
2520
|
/*
|
|
2240
2521
|
* Who may widen access: only a browser that is already on this
|
|
2241
2522
|
* machine.
|
|
@@ -2272,20 +2553,11 @@ export function createWebApp(deps) {
|
|
|
2272
2553
|
* in a browser on the far side of the tailnet.
|
|
2273
2554
|
*/
|
|
2274
2555
|
const forgotten = new Set();
|
|
2275
|
-
await sessions.forget((s) => { const drop = s.via === 'tailscale'; if (drop && s.id)
|
|
2556
|
+
await sessions.forget((s) => { const drop = s.via === 'provider' && s.provider === 'tailscale'; if (drop && s.id)
|
|
2276
2557
|
forgotten.add(s.id); return drop; });
|
|
2277
2558
|
// Including whichever of them had a hand on the owner's browser.
|
|
2278
2559
|
hand.revoke((lease) => forgotten.has(lease), 'Tailscale access changed. Sign in again.');
|
|
2279
|
-
|
|
2280
|
-
const stored = toTailscaleSetting({ enabled, login });
|
|
2281
|
-
return sendJson(res, 200, {
|
|
2282
|
-
enabled: stored.enabled,
|
|
2283
|
-
login: stored.login,
|
|
2284
|
-
available: daemon.available,
|
|
2285
|
-
self: daemon.self,
|
|
2286
|
-
proxied: false,
|
|
2287
|
-
serveCommand: serveCommand(),
|
|
2288
|
-
});
|
|
2560
|
+
return sendJson(res, 200, await tailscaleView(req, session));
|
|
2289
2561
|
}
|
|
2290
2562
|
if (path === '/api/version/check')
|
|
2291
2563
|
return reply(res, await versionCheckRoute(versionDeps(), 'PUT', put));
|
|
@@ -2299,6 +2571,135 @@ export function createWebApp(deps) {
|
|
|
2299
2571
|
}
|
|
2300
2572
|
if (method !== 'POST')
|
|
2301
2573
|
return sendEmpty(res, 405);
|
|
2574
|
+
/*
|
|
2575
|
+
* "Test my setup": fetch the team's signing keys for the domain in the
|
|
2576
|
+
* form (saved or not) and say what came back. Nothing is stored. From
|
|
2577
|
+
* this machine only, like the setting itself: it makes this computer
|
|
2578
|
+
* fetch a URL the caller names part of.
|
|
2579
|
+
*/
|
|
2580
|
+
/*
|
|
2581
|
+
* "Set it up for me": start a run (202, then poll GET …/setup), stop the
|
|
2582
|
+
* health wait, or remove what buddi made. From this machine only, like the
|
|
2583
|
+
* setting it fills in.
|
|
2584
|
+
*/
|
|
2585
|
+
if (path === '/api/access/cloudflare-access/setup' || path === '/api/access/cloudflare-access/setup/stop' || path === '/api/access/cloudflare-access/setup/remove') {
|
|
2586
|
+
if (session.via !== 'local')
|
|
2587
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2588
|
+
/*
|
|
2589
|
+
* One operation at a time (cloudflare-setup's lock, claimed before the
|
|
2590
|
+
* first await and held to the end): a second setup or a removal while
|
|
2591
|
+
* one runs is a 409, and so is Stop while a removal runs.
|
|
2592
|
+
*/
|
|
2593
|
+
if (path.endsWith('/stop')) {
|
|
2594
|
+
const going = setupOperation();
|
|
2595
|
+
if (going === 'remove')
|
|
2596
|
+
return sendJson(res, 409, { error: setupBusySentence(going) });
|
|
2597
|
+
const lease = going === null ? claimSetupOperation('setup') : null;
|
|
2598
|
+
try {
|
|
2599
|
+
setupRun?.abort.abort();
|
|
2600
|
+
await setupRun?.done;
|
|
2601
|
+
return sendJson(res, 200, await setupView());
|
|
2602
|
+
}
|
|
2603
|
+
finally {
|
|
2604
|
+
lease?.release();
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
const lease = claimSetupOperation(path.endsWith('/remove') ? 'remove' : 'setup');
|
|
2608
|
+
if (!lease)
|
|
2609
|
+
return sendJson(res, 409, { error: setupBusySentence(setupOperation()) });
|
|
2610
|
+
let handedOff = false;
|
|
2611
|
+
try {
|
|
2612
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2613
|
+
const str = (v) => (typeof v === 'string' ? v.trim() : '');
|
|
2614
|
+
const tokens = tokenStore();
|
|
2615
|
+
const pasted = str(body.token);
|
|
2616
|
+
if (path.endsWith('/remove')) {
|
|
2617
|
+
const token = pasted || await tokens.use().catch(() => null);
|
|
2618
|
+
if (!token)
|
|
2619
|
+
return sendJson(res, 400, { error: 'Paste the Cloudflare API token again: buddi needs it to remove what it made.' });
|
|
2620
|
+
const run = {
|
|
2621
|
+
progress: { ...freshProgress(), state: 'removing', steps: [] }, abort: new AbortController(), done: Promise.resolve(),
|
|
2622
|
+
};
|
|
2623
|
+
setupRun = run;
|
|
2624
|
+
const progress = await removeCloudflareSetup({ ...setupDepsFor(token, lease), host: str(body.host) || undefined }, (p) => { run.progress = p; });
|
|
2625
|
+
run.progress = progress;
|
|
2626
|
+
if (!progress.error)
|
|
2627
|
+
await tokens.remove().catch(() => undefined);
|
|
2628
|
+
return sendJson(res, 200, await setupView());
|
|
2629
|
+
}
|
|
2630
|
+
const input = { host: str(body.host), email: str(body.email), zone: str(body.zone) || undefined, adopt: body.adopt === true };
|
|
2631
|
+
const invalid = checkSetupInput(input);
|
|
2632
|
+
if (invalid)
|
|
2633
|
+
return sendJson(res, 400, { error: invalid });
|
|
2634
|
+
if (pasted) {
|
|
2635
|
+
if (/\s/.test(pasted) || pasted.length < 20 || pasted.length > 400)
|
|
2636
|
+
return sendJson(res, 400, { error: 'That doesn’t look like a Cloudflare API token.' });
|
|
2637
|
+
try {
|
|
2638
|
+
await tokens.put(pasted);
|
|
2639
|
+
}
|
|
2640
|
+
catch {
|
|
2641
|
+
return sendJson(res, 409, { error: 'The token could not be kept in the vault. Check that the vault is unlocked, then try again.' });
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const token = pasted || await tokens.use().catch(() => null);
|
|
2645
|
+
if (!token)
|
|
2646
|
+
return sendJson(res, 400, { error: 'Paste a Cloudflare API token.' });
|
|
2647
|
+
const first = { ...freshProgress(input.host, input.email), state: 'running' };
|
|
2648
|
+
startSetup(lease, (onProgress, signal) => runCloudflareSetup(input, setupDepsFor(token, lease, signal), onProgress), first);
|
|
2649
|
+
handedOff = true;
|
|
2650
|
+
return sendJson(res, 202, await setupView());
|
|
2651
|
+
}
|
|
2652
|
+
finally {
|
|
2653
|
+
if (!handedOff)
|
|
2654
|
+
lease.release();
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
/*
|
|
2658
|
+
* The setup form's domain choice: check the token and list the zones it
|
|
2659
|
+
* can see. The pasted token is only used for these two calls — keeping it
|
|
2660
|
+
* stays with setup — and never goes back out, not even in an error.
|
|
2661
|
+
*/
|
|
2662
|
+
if (path === '/api/access/cloudflare-access/zones') {
|
|
2663
|
+
if (session.via !== 'local')
|
|
2664
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2665
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2666
|
+
const pasted = typeof body?.token === 'string' ? body.token.trim() : '';
|
|
2667
|
+
if (pasted && (/\s/.test(pasted) || pasted.length < 20 || pasted.length > 400))
|
|
2668
|
+
return sendJson(res, 400, { error: 'That doesn’t look like a Cloudflare API token.' });
|
|
2669
|
+
const token = pasted || await tokenStore().use().catch(() => null);
|
|
2670
|
+
if (!token)
|
|
2671
|
+
return sendJson(res, 400, { error: 'Paste a Cloudflare API token.' });
|
|
2672
|
+
const api = createCloudflareApi({ token, transport: deps.cloudflare?.api?.transport, baseUrl: deps.cloudflare?.api?.baseUrl });
|
|
2673
|
+
try {
|
|
2674
|
+
if (await api.verifyToken() === 'inactive')
|
|
2675
|
+
return sendJson(res, 400, { error: 'Cloudflare says this API token is not active. Check that it has not expired or been turned off.' });
|
|
2676
|
+
const zones = await api.zones();
|
|
2677
|
+
return sendJson(res, 200, { zones: zones.map((z) => ({ id: z.id, name: z.name })) });
|
|
2678
|
+
}
|
|
2679
|
+
catch (error) {
|
|
2680
|
+
if (!(error instanceof CloudflareApiError))
|
|
2681
|
+
throw error;
|
|
2682
|
+
const refused = error.status === 401 || error.permission !== undefined || (error.status >= 400 && error.status < 500 && error.status !== 429);
|
|
2683
|
+
return sendJson(res, refused ? 400 : 502, { error: error.message });
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
if (path === '/api/access/cloudflare-access/test') {
|
|
2687
|
+
if (session.via !== 'local')
|
|
2688
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2689
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2690
|
+
const team = normalizeTeamDomain(typeof body.teamDomain === 'string' ? body.teamDomain : (await readCloudflareSetting()).teamDomain);
|
|
2691
|
+
if (!plausibleTeamDomain(team)) {
|
|
2692
|
+
return sendJson(res, 400, { error: 'That is not a Cloudflare team domain. It looks like yourteam.cloudflareaccess.com, under Zero Trust → Settings.' });
|
|
2693
|
+
}
|
|
2694
|
+
const result = await jwks.refresh(team);
|
|
2695
|
+
return sendJson(res, 200, {
|
|
2696
|
+
...result,
|
|
2697
|
+
teamDomain: team,
|
|
2698
|
+
sentence: result.ok ? `${team} answered with ${result.keys} signing key${result.keys === 1 ? '' : 's'}.` : result.error,
|
|
2699
|
+
listening: ingress.port() !== null,
|
|
2700
|
+
ingressPort: ingress.port(),
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2302
2703
|
if (path === '/api/extension/pair') {
|
|
2303
2704
|
// A six-digit code is worth guessing at scale, so a wrong one costs a
|
|
2304
2705
|
// budget — this session's pairing budget, not the shared sign-in one.
|
|
@@ -2345,24 +2746,47 @@ export function createWebApp(deps) {
|
|
|
2345
2746
|
return sendJson(res, 200, { ok: false, message: error instanceof Error ? error.message : String(error) });
|
|
2346
2747
|
}
|
|
2347
2748
|
}
|
|
2348
|
-
if (path === '/api/browser/settings'
|
|
2749
|
+
if (path === '/api/browser/settings') {
|
|
2349
2750
|
const body = await readJsonBody(req);
|
|
2350
2751
|
try {
|
|
2351
|
-
if (
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
return sendJson(res, 200, await browser.configure(body));
|
|
2355
|
-
}
|
|
2356
|
-
if (!body || typeof body !== 'object' || Array.isArray(body) || Object.keys(body).some((key) => key !== 'prompt') || ('prompt' in body && typeof body.prompt !== 'boolean'))
|
|
2357
|
-
return sendJson(res, 400, { error: 'Expected {prompt: boolean}' });
|
|
2358
|
-
if (!browser.checkPermissions)
|
|
2359
|
-
return sendJson(res, 409, { error: 'This host does not support native permission checks.' });
|
|
2360
|
-
return sendJson(res, 200, await browser.checkPermissions(body.prompt === true));
|
|
2752
|
+
if (!browser.configure)
|
|
2753
|
+
return sendJson(res, 409, { error: 'This host does not support changing control modes.' });
|
|
2754
|
+
return sendJson(res, 200, await browser.configure(body));
|
|
2361
2755
|
}
|
|
2362
2756
|
catch (error) {
|
|
2363
2757
|
return sendJson(res, 409, { error: error instanceof Error ? error.message : String(error) });
|
|
2364
2758
|
}
|
|
2365
2759
|
}
|
|
2760
|
+
/*
|
|
2761
|
+
* Pin one conversation to a route (the chip under the composer,
|
|
2762
|
+
* `/use browser:chrome`), or clear it with `auto`. A pin narrows; it never
|
|
2763
|
+
* allows a route the owner's switches forbid.
|
|
2764
|
+
*/
|
|
2765
|
+
if (path === '/api/browser/pin') {
|
|
2766
|
+
const body = await readJsonBody(req);
|
|
2767
|
+
if (typeof body?.conversationId !== 'string' || typeof body.route !== 'string')
|
|
2768
|
+
return sendJson(res, 400, { error: 'Expected {conversationId: string, route: auto|own|chrome|apps}' });
|
|
2769
|
+
if (!browser.pin)
|
|
2770
|
+
return sendJson(res, 409, { error: 'This host cannot pin a route.' });
|
|
2771
|
+
try {
|
|
2772
|
+
return sendJson(res, 200, await browser.pin(body.conversationId, body.route));
|
|
2773
|
+
}
|
|
2774
|
+
catch (error) {
|
|
2775
|
+
return sendJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
/*
|
|
2779
|
+
* A tap on a browser card (Look, Keep going, Take over, Use my Chrome,
|
|
2780
|
+
* Resume) from a page that draws its own buttons: the same as the owner
|
|
2781
|
+
* sending the label in the chat, without a message.
|
|
2782
|
+
*/
|
|
2783
|
+
if (path === '/api/browser/card') {
|
|
2784
|
+
const body = await readJsonBody(req);
|
|
2785
|
+
if (typeof body?.conversationId !== 'string' || typeof body.answer !== 'string' || body.answer.length > 80)
|
|
2786
|
+
return sendJson(res, 400, { error: 'Expected {conversationId: string, answer: string}' });
|
|
2787
|
+
const answered = await browser.touch?.({ conversationId: body.conversationId, text: body.answer });
|
|
2788
|
+
return sendJson(res, 200, { ...(answered && 'answered' in answered ? answered : {}), status: browser.status({ conversationId: body.conversationId }) });
|
|
2789
|
+
}
|
|
2366
2790
|
const control = /^\/api\/browser\/(stop|takeover|resume|release)$/.exec(path);
|
|
2367
2791
|
if (control) {
|
|
2368
2792
|
const body = await readJsonBody(req);
|
|
@@ -2377,7 +2801,8 @@ export function createWebApp(deps) {
|
|
|
2377
2801
|
// frozen picture.
|
|
2378
2802
|
if (action !== 'takeover')
|
|
2379
2803
|
await hand.close(action === 'stop' ? undefined : sessionId, action === 'resume' ? 'You gave the screen back.' : 'That session was released.');
|
|
2380
|
-
|
|
2804
|
+
// Stop agents' browsing expires (an hour by default); `forever` is "until I say".
|
|
2805
|
+
const status = await browser.control(action, sessionId, action === 'stop' && body?.forever === true ? { forever: true } : undefined);
|
|
2381
2806
|
// Whether this screen can be driven from here at all. The dashboard
|
|
2382
2807
|
// shows the mode's own sentence when it cannot.
|
|
2383
2808
|
const taken = sessionId ?? status.session?.id;
|
|
@@ -2388,7 +2813,7 @@ export function createWebApp(deps) {
|
|
|
2388
2813
|
* as that, with a reason the dashboard offers its ways out on, rather
|
|
2389
2814
|
* than the mode's "use this conversation's host tab".
|
|
2390
2815
|
*/
|
|
2391
|
-
if (offer && offer.supported && !offer.hand && status.mode === 'extension' && !extension.connected()) {
|
|
2816
|
+
if (offer && offer.supported && !offer.hand && (status.route === 'chrome' || status.mode === 'extension') && !extension.connected()) {
|
|
2392
2817
|
return sendJson(res, 200, { ...status, hand: false, handReason: 'browser-offline', handMessage: 'Your browser isn’t connected.' });
|
|
2393
2818
|
}
|
|
2394
2819
|
return sendJson(res, 200, offer
|
|
@@ -3724,6 +4149,10 @@ export async function startWebServer(deps) {
|
|
|
3724
4149
|
*/
|
|
3725
4150
|
if (previewPort !== null)
|
|
3726
4151
|
publishPreviewPort(deps.env ?? process.env, previewPort);
|
|
4152
|
+
// The ingress listener, after the previews have taken their port: bound
|
|
4153
|
+
// now when Cloudflare Access is on, and from then on as the setting changes.
|
|
4154
|
+
const ingress = ingressOf(server);
|
|
4155
|
+
await ingress.sync();
|
|
3727
4156
|
/*
|
|
3728
4157
|
* An approval nobody decides expires, and a delegation waiting on one is
|
|
3729
4158
|
* handed the expiry as its failure: the approval's own lifetime is the
|
|
@@ -3741,6 +4170,7 @@ export async function startWebServer(deps) {
|
|
|
3741
4170
|
server,
|
|
3742
4171
|
port,
|
|
3743
4172
|
previewPort,
|
|
4173
|
+
ingress,
|
|
3744
4174
|
url: webUrl({ host: deps.config.host, port }),
|
|
3745
4175
|
chat: webChatOf(server),
|
|
3746
4176
|
close: async () => {
|
|
@@ -3752,6 +4182,7 @@ export async function startWebServer(deps) {
|
|
|
3752
4182
|
// still held, and the next thing to want it — the next test, the
|
|
3753
4183
|
// gateway coming back up — finds it taken.
|
|
3754
4184
|
await Promise.all([
|
|
4185
|
+
ingress.close(),
|
|
3755
4186
|
new Promise((resolve) => {
|
|
3756
4187
|
if (!previews || previewPort === null)
|
|
3757
4188
|
return resolve();
|