conductor-oss 0.2.5 → 0.2.6
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/README.md +29 -6
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.d.ts +30 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +131 -29
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts +3 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +209 -15
- package/dist/commands/start.js.map +1 -1
- package/dist/index.js +1 -1
- package/node_modules/@conductor-oss/core/dist/config.d.ts +1 -1
- package/node_modules/@conductor-oss/core/dist/config.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/config.js +34 -0
- package/node_modules/@conductor-oss/core/dist/config.js.map +1 -1
- package/node_modules/@conductor-oss/core/dist/scaffold.d.ts +14 -0
- package/node_modules/@conductor-oss/core/dist/scaffold.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/scaffold.js +27 -4
- package/node_modules/@conductor-oss/core/dist/scaffold.js.map +1 -1
- package/node_modules/@conductor-oss/core/dist/types.d.ts +71 -0
- package/node_modules/@conductor-oss/core/dist/types.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/types.js +244 -0
- package/node_modules/@conductor-oss/core/dist/types.js.map +1 -1
- package/node_modules/@conductor-oss/core/package.json +1 -1
- package/node_modules/@conductor-oss/plugin-agent-amp/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-amp/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-ccr/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-ccr/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-claude-code/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-claude-code/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-codex/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-codex/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-cursor-cli/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-cursor-cli/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-droid/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-droid/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-gemini/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-gemini/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-github-copilot/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-github-copilot/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-opencode/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-agent-opencode/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-agent-qwen-code/dist/index.js +10 -6
- package/node_modules/@conductor-oss/plugin-agent-qwen-code/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-mcp-server/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-mcp-server/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-notifier-desktop/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-notifier-desktop/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-notifier-discord/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-notifier-discord/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-runtime-tmux/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-runtime-tmux/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-scm-github/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-scm-github/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-terminal-web/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-terminal-web/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-tracker-github/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-tracker-github/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-webhook/package.json +2 -2
- package/node_modules/@conductor-oss/plugin-workspace-worktree/dist/index.js +1 -1
- package/node_modules/@conductor-oss/plugin-workspace-worktree/package.json +2 -2
- package/package.json +22 -21
- package/web/.next/standalone/packages/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/packages/web/.next/app-path-routes-manifest.json +5 -1
- package/web/.next/standalone/packages/web/.next/build-manifest.json +4 -4
- package/web/.next/standalone/packages/web/.next/routes-manifest.json +24 -0
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.rsc +9 -9
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +9 -9
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js +8 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js +4 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js +3 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js +5 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js +8 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/auth/grant/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/index.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/build-manifest.json +18 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/next-font-manifest.json +14 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/react-loadable-manifest.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/server-reference-manifest.json +110 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js +19 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app-paths-manifest.json +5 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_1651710d.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_34b04c2b.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_9c655a1d.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_b41c4976.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/1bc17_next_dist_esm_build_templates_app-route_f4104ae4.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__005aa909._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__03ff76ee._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__07ec6d5c._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0a0f0f01._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0ad3545b._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__04d7f8e9._.js → [root-of-the-server]__0c65150d._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__39e2947e._.js → [root-of-the-server]__0d615ef4._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__13ad088c._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__14b1d4a3._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__000a39bb._.js → [root-of-the-server]__14d277b3._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1741fb8a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__17d81825._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__4266ed21._.js → [root-of-the-server]__1b7c6a55._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1e288076._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f626a16._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1f712b77._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2062aaab._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__206c3d8a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9469f247._.js → [root-of-the-server]__230d54da._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__24d8e6fc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2556a816._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2af6c2e0._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2d57abda._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30b0f109._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__30c75561._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__31c39bd9._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__7e505454._.js → [root-of-the-server]__341657dd._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__34a19860._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3fde7043._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__40c8037e._.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__41ee872a._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44606e04._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__44d59fd0._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__459839a6._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__46a8e776._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__48875cbb._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b3f4ff98._.js → [root-of-the-server]__488ab4b2._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4ac9d639._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4c3fb752._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4dab6a6a._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__544326ac._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5494c5a2._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a218f0._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__54a76cd2._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5661ca72._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__568f0a6e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cd49624._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d76c5af._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5e0533de._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5f628cf2._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__62608541._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d62709d._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6e4e09be._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70258e45._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__917adaec._.js → [root-of-the-server]__711dc459._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__720136dd._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__749331b0._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__755c7e10._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__778e46a1._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7e6ea46e._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f023a04._.js +4 -4
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7f2ed2cd._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fa52da6._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__82171aa3._.js +9 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__84362910._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__848eb266._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8596d782._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__85c5cb36._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__878fbacc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__881858fa._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__885e3a00._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__893f6b3b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8ac30f97._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__8c519453._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__919845e0._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9b62b450._.js → [root-of-the-server]__927b9bce._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__93b3582e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__964f4e89._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__96633022._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__98697e45._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__997ebfca._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9c930222._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__9f36b7ec._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a44f91a4._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__1bc4f8f5._.js → [root-of-the-server]__a5d13971._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a6c7bd91._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ae580a1a._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__af533b5e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__afa79f55._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b057f7b2._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b59abfbd._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bd8ace80._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be0f2c29._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bea07e07._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c8618cb1._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__caf8e7cb._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb112606._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cb51f2e3._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cba32afb._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cc74ea40._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cd3692a0._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cf3cdecd._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d09e7a99._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d538c110._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d93447b9._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d9c80b18._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dc0959da._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__dda8eac1._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__df2c6efe._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e113f6df._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2573a77._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e2d60274._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e308bb89._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e345a443._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e80a520f._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ea0bb124._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ef773ea6._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f0d15920._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b029d2c1._.js → [root-of-the-server]__f2f30c04._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f47a2a9e._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f48eb2d4._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f6a8bbd9._.js +12 -12
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__faceea9b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fb6ab669._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fcf96768._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fdaa8058._.js +7 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ff2b205d._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_core_dist_index_cdd30418.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-amp_dist_index_bf3d8239.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-ccr_dist_index_69cbf726.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-claude-code_dist_index_31314e43.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-cursor-cli_dist_index_8d5cc426.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-droid_dist_index_f731227a.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-gemini_dist_index_b2d219e8.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-github-copilot_dist_index_9f80cb45.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-opencode_dist_index_7c7015da.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_agent-qwen-code_dist_index_46dd8653.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-desktop_dist_index_ef3473f0.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_notifier-discord_dist_index_34257226.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_scm-github_dist_index_3b5a621e.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_terminal-web_dist_index_1e0706d3.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_plugins_tracker-github_dist_index_2d7af62f.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_access_route_actions_06740e99.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_api_auth_session_route_actions_078c0ee4.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web__next-internal_server_app_auth_grant_route_actions_13ba4421.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_13fee5eb._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/packages_web_src_lib_d64596cc._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__1ddf22db._.js → [root-of-the-server]__1012a4c8._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__ed81e796._.js → [root-of-the-server]__81affb12._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__95e85d3d._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__f577d85a._.js → [root-of-the-server]__9d698773._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__a38f483b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__3bf3fbfb._.js → [root-of-the-server]__c09a0c60._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__d9dde485._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__d5970f3e._.js → [root-of-the-server]__dd435d80._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__469db3c3._.js → [root-of-the-server]__e78955d0._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_14a33487._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_34d55bf1._.js +4 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{node_modules__pnpm_c636dc22._.js → node_modules__pnpm_597c265e._.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_page_tsx_cd282e82._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_app_unlock_UnlockForm_tsx_ce3149a7._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/middleware-build-manifest.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/middleware.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/next-font-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/next-font-manifest.json +7 -0
- package/web/.next/standalone/packages/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.json +56 -7
- package/web/.next/{static/chunks/9b799cd7eb9a34ff.js → standalone/packages/web/.next/static/chunks/1c4c14af475ada00.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/ba68284a3401d670.css +3 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
- package/web/.next/standalone/packages/web/package.json +1 -0
- package/web/.next/standalone/packages/web/src/app/api/access/route.ts +214 -0
- package/web/.next/standalone/packages/web/src/app/api/agents/route.ts +2 -2
- package/web/.next/standalone/packages/web/src/app/api/attachments/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/auth/session/route.ts +54 -0
- package/web/.next/standalone/packages/web/src/app/api/boards/route.ts +2 -2
- package/web/.next/standalone/packages/web/src/app/api/config/route.ts +2 -1
- package/web/.next/standalone/packages/web/src/app/api/context-files/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/events/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/filesystem/directory/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/github/repos/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/health/boards/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/preferences/route.ts +9 -2
- package/web/.next/standalone/packages/web/src/app/api/repositories/route.ts +19 -2
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/checks/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/diff/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/feedback/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/files/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/keys/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/kill/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/stream/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/restore/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/send/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/spawn/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/workspaces/branches/route.ts +1 -1
- package/web/.next/standalone/packages/web/src/app/api/workspaces/route.ts +9 -2
- package/web/.next/standalone/packages/web/src/app/auth/grant/route.ts +37 -0
- package/web/.next/standalone/packages/web/src/app/page.tsx +763 -9
- package/web/.next/standalone/packages/web/src/app/unlock/UnlockForm.tsx +77 -0
- package/web/.next/standalone/packages/web/src/app/unlock/page.tsx +41 -0
- package/web/.next/standalone/packages/web/src/components/Dashboard.tsx +11 -125
- package/web/.next/standalone/packages/web/src/hooks/useConfig.ts +4 -0
- package/web/.next/standalone/packages/web/src/lib/accessControl.test.ts +46 -0
- package/web/.next/standalone/packages/web/src/lib/accessControl.ts +115 -0
- package/web/.next/standalone/packages/web/src/lib/auth.ts +294 -53
- package/web/.next/standalone/packages/web/src/lib/edgeAuth.test.ts +91 -0
- package/web/.next/standalone/packages/web/src/lib/edgeAuth.ts +205 -0
- package/web/.next/standalone/packages/web/src/lib/modelAccess.ts +40 -0
- package/web/.next/standalone/packages/web/src/lib/projectConfigSync.ts +2 -0
- package/web/.next/standalone/packages/web/src/lib/remoteAuth.ts +104 -0
- package/web/.next/standalone/packages/web/src/proxy.ts +64 -0
- package/web/.next/standalone/packages/web/tsconfig.tsbuildinfo +1 -1
- package/web/.next/{standalone/packages/web/.next/static/chunks/9b799cd7eb9a34ff.js → static/chunks/1c4c14af475ada00.js} +1 -1
- package/web/.next/static/chunks/ba68284a3401d670.css +3 -0
- package/web/.next/static/chunks/{4372fb4d7779cd64.js → d00ddc86d1af3b6d.js} +1 -1
- package/web/.next/static/chunks/d8f4bf59132f70fd.js +1 -0
- package/web/.next/static/chunks/f355d4d60f0ec80e.js +1 -0
- package/web/.next/static/chunks/{turbopack-c3449aaab622f98c.js → turbopack-dc658d17ee981623.js} +1 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js +0 -67
- package/node_modules/@conductor-oss/core/dist/__tests__/board-parser.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js +0 -122
- package/node_modules/@conductor-oss/core/dist/__tests__/board-watcher-support-files.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts +0 -2
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js +0 -48
- package/node_modules/@conductor-oss/core/dist/__tests__/project-paths.test.js.map +0 -1
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts +0 -20
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.d.ts.map +0 -1
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js +0 -192
- package/node_modules/@conductor-oss/core/dist/agent-cli-runtime.js.map +0 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__019d9c90._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__08a3e108._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0b0ab434._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__0e59a166._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__16fb4c3e._.js +0 -9
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2ff87bed._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__3c1772ab._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5093c7e0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__53970b23._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5a67f1f9._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5cf55740._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5d124f64._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6cad94c3._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6d28affc._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f6826fa._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6f84fa49._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__70c9c405._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__711294a3._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7791414d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__7fb2ee11._.js +0 -7
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__86646048._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a15b5527._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a4a89ac9._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a8a53d4a._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__a93c59df._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__abf6274f._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b091b8bc._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b87de88e._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__bc304d71._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be52402d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__be74f171._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c03aa571._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c2850420._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c82b8934._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__deafbc7a._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e18c8e77._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e1f610fb._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__e4976f6d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec21c9a4._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ec256a62._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__edc8e5a5._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f2c28004._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f7c743c0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f95f5172._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__fc292e1c._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ffbf3faf._.js +0 -3
- package/web/.next/standalone/packages/web/.next/static/chunks/687bc713618f6993.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
- package/web/.next/static/chunks/687bc713618f6993.js +0 -1
- package/web/.next/static/chunks/e7bb96d7efad8e32.css +0 -3
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_ssgManifest.js +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_buildManifest.js +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{2lp61OU9Asm88Hx_JCL5e → tV9IvZT_f540bpw2KonCu}/_ssgManifest.js +0 -0
|
@@ -1,12 +1,28 @@
|
|
|
1
|
+
import type { DashboardAccessConfig, DashboardRole } from "@conductor-oss/core/types";
|
|
2
|
+
import { cookies, headers } from "next/headers";
|
|
1
3
|
import { NextRequest, NextResponse } from "next/server";
|
|
4
|
+
import { resolveRoleForEmail, roleMeetsRequirement, isLoopbackHost } from "@/lib/accessControl";
|
|
5
|
+
import { verifyTrustedEdgeIdentity } from "@/lib/edgeAuth";
|
|
6
|
+
import { BUILTIN_REMOTE_SESSION_COOKIE, isBuiltinRemoteAuthEnabled, verifyBuiltinRemoteSession } from "@/lib/remoteAuth";
|
|
7
|
+
import { getServices } from "@/lib/services";
|
|
2
8
|
|
|
3
9
|
const clerkConfigured = Boolean(
|
|
4
10
|
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY && process.env.CLERK_SECRET_KEY,
|
|
5
11
|
);
|
|
6
12
|
|
|
13
|
+
type DashboardIdentityProvider =
|
|
14
|
+
| "local"
|
|
15
|
+
| "builtin"
|
|
16
|
+
| "clerk"
|
|
17
|
+
| "trusted-header"
|
|
18
|
+
| "cloudflare-access";
|
|
19
|
+
|
|
7
20
|
export interface DashboardAccess {
|
|
8
21
|
ok: boolean;
|
|
22
|
+
authenticated: boolean;
|
|
23
|
+
role?: DashboardRole;
|
|
9
24
|
email?: string;
|
|
25
|
+
provider?: DashboardIdentityProvider;
|
|
10
26
|
reason?: string;
|
|
11
27
|
}
|
|
12
28
|
|
|
@@ -23,6 +39,12 @@ type HostParts = {
|
|
|
23
39
|
host: string;
|
|
24
40
|
};
|
|
25
41
|
|
|
42
|
+
type ClerkUser = {
|
|
43
|
+
emailAddresses: { id: string; emailAddress: string }[];
|
|
44
|
+
primaryEmailAddressId: string | null;
|
|
45
|
+
publicMetadata: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
|
|
26
48
|
function parseHostParts(value: string, fallbackHost?: string): HostParts | null {
|
|
27
49
|
try {
|
|
28
50
|
const url = new URL(value, fallbackHost ? `https://${fallbackHost}` : undefined);
|
|
@@ -34,10 +56,6 @@ function parseHostParts(value: string, fallbackHost?: string): HostParts | null
|
|
|
34
56
|
}
|
|
35
57
|
}
|
|
36
58
|
|
|
37
|
-
function isLoopbackHost(hostname: string): boolean {
|
|
38
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname === "[::1]";
|
|
39
|
-
}
|
|
40
|
-
|
|
41
59
|
function equivalentHost(candidate: string, expectedHost: string): boolean {
|
|
42
60
|
if (candidate.toLowerCase() === expectedHost.toLowerCase()) return true;
|
|
43
61
|
|
|
@@ -69,77 +87,306 @@ function getAllowedActionHosts(expectedHost: string): Set<string> {
|
|
|
69
87
|
return hosts;
|
|
70
88
|
}
|
|
71
89
|
|
|
72
|
-
type ClerkUser = {
|
|
73
|
-
emailAddresses: { id: string; emailAddress: string }[];
|
|
74
|
-
primaryEmailAddressId: string | null;
|
|
75
|
-
publicMetadata: Record<string, unknown>;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
90
|
function isApproved(user: ClerkUser): boolean {
|
|
79
91
|
const raw = user.publicMetadata ?? {};
|
|
80
92
|
return raw.conductorApproved === true;
|
|
81
93
|
}
|
|
82
94
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
function envRequiresAuth(): boolean {
|
|
96
|
+
return (process.env.CONDUCTOR_REQUIRE_AUTH ?? "").trim().toLowerCase() === "true";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function legacyRoleEnvFallback(): {
|
|
100
|
+
allowedEmails: string[];
|
|
101
|
+
allowedDomains: string[];
|
|
102
|
+
adminEmails: string[];
|
|
103
|
+
} {
|
|
104
|
+
return {
|
|
105
|
+
allowedEmails: parseCsv(process.env.CONDUCTOR_ALLOWED_EMAILS),
|
|
106
|
+
allowedDomains: parseCsv(process.env.CONDUCTOR_ALLOWED_DOMAINS),
|
|
107
|
+
adminEmails: parseCsv(process.env.CONDUCTOR_ADMIN_EMAILS),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function hasLegacyAllowListConfigured(): boolean {
|
|
112
|
+
const { allowedEmails, allowedDomains, adminEmails } = legacyRoleEnvFallback();
|
|
113
|
+
return allowedEmails.length > 0 || allowedDomains.length > 0 || adminEmails.length > 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function passesLegacyEmailRestrictions(email: string): boolean {
|
|
117
|
+
const normalizedEmail = email.trim().toLowerCase();
|
|
118
|
+
const { allowedEmails, allowedDomains, adminEmails } = legacyRoleEnvFallback();
|
|
119
|
+
|
|
120
|
+
const emailAllowed =
|
|
121
|
+
allowedEmails.length === 0 ||
|
|
122
|
+
allowedEmails.includes(normalizedEmail) ||
|
|
123
|
+
adminEmails.includes(normalizedEmail);
|
|
124
|
+
|
|
125
|
+
const domainAllowed =
|
|
126
|
+
allowedDomains.length === 0 ||
|
|
127
|
+
allowedDomains.some((domain) => normalizedEmail.endsWith(`@${domain}`));
|
|
128
|
+
|
|
129
|
+
return emailAllowed && domainAllowed;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function loadAccessConfig(): Promise<DashboardAccessConfig | null> {
|
|
133
|
+
try {
|
|
134
|
+
const { config } = await getServices();
|
|
135
|
+
return config.access ?? null;
|
|
136
|
+
} catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getDefaultRole(access: DashboardAccessConfig | null): DashboardRole | null {
|
|
142
|
+
const configured = process.env.CONDUCTOR_ACCESS_DEFAULT_ROLE?.trim().toLowerCase();
|
|
143
|
+
if (configured === "viewer" || configured === "operator" || configured === "admin") {
|
|
144
|
+
return configured;
|
|
145
|
+
}
|
|
146
|
+
return access?.defaultRole ?? null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function currentHeaders(request?: Request): Promise<Headers> {
|
|
150
|
+
if (request) return request.headers;
|
|
151
|
+
return headers();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function currentHost(request?: Request): Promise<string> {
|
|
155
|
+
if (request) {
|
|
156
|
+
try {
|
|
157
|
+
return new URL(request.url).hostname;
|
|
158
|
+
} catch {
|
|
159
|
+
return request.headers.get("host")?.split(":")[0]?.trim().toLowerCase() ?? "";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const headerStore = await headers();
|
|
163
|
+
return headerStore.get("host")?.split(":")[0]?.trim().toLowerCase() ?? "";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function resolveRoleForAuthenticatedEmail(
|
|
167
|
+
email: string,
|
|
168
|
+
access: DashboardAccessConfig | null,
|
|
169
|
+
): DashboardAccess {
|
|
170
|
+
if (!passesLegacyEmailRestrictions(email)) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
authenticated: true,
|
|
174
|
+
email,
|
|
175
|
+
reason: "Email/domain not allowed",
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const defaultRole = getDefaultRole(access);
|
|
180
|
+
const roleResolution = resolveRoleForEmail(
|
|
181
|
+
email,
|
|
182
|
+
defaultRole ? { ...access, defaultRole } : access,
|
|
183
|
+
legacyRoleEnvFallback(),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (!roleResolution.role) {
|
|
187
|
+
return {
|
|
188
|
+
ok: false,
|
|
189
|
+
authenticated: true,
|
|
190
|
+
email,
|
|
191
|
+
reason: "Authenticated user is not granted dashboard access",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
ok: true,
|
|
197
|
+
authenticated: true,
|
|
198
|
+
email,
|
|
199
|
+
role: roleResolution.role,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function resolveTrustedHeaderAccess(
|
|
204
|
+
request: Request | undefined,
|
|
205
|
+
access: DashboardAccessConfig | null,
|
|
206
|
+
): Promise<DashboardAccess | null> {
|
|
207
|
+
const headerStore = await currentHeaders(request);
|
|
208
|
+
const identity = await verifyTrustedEdgeIdentity(headerStore, access);
|
|
209
|
+
if (!identity) return null;
|
|
210
|
+
if (!identity.ok) {
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
authenticated: false,
|
|
214
|
+
reason: identity.reason,
|
|
215
|
+
provider: identity.provider,
|
|
216
|
+
};
|
|
86
217
|
}
|
|
87
218
|
|
|
219
|
+
const resolved = resolveRoleForAuthenticatedEmail(identity.email, access);
|
|
220
|
+
return {
|
|
221
|
+
...resolved,
|
|
222
|
+
provider: identity.provider,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function resolveBuiltinRemoteAccess(): Promise<DashboardAccess | null> {
|
|
227
|
+
if (!isBuiltinRemoteAuthEnabled()) return null;
|
|
228
|
+
|
|
229
|
+
const cookieStore = await cookies();
|
|
230
|
+
const session = cookieStore.get(BUILTIN_REMOTE_SESSION_COOKIE)?.value ?? null;
|
|
231
|
+
if (!session) {
|
|
232
|
+
return {
|
|
233
|
+
ok: false,
|
|
234
|
+
authenticated: false,
|
|
235
|
+
reason: "Remote sign-in required",
|
|
236
|
+
provider: "builtin",
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const validSession = await verifyBuiltinRemoteSession(session);
|
|
241
|
+
if (!validSession) {
|
|
242
|
+
return {
|
|
243
|
+
ok: false,
|
|
244
|
+
authenticated: false,
|
|
245
|
+
reason: "Remote sign-in required",
|
|
246
|
+
provider: "builtin",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
ok: true,
|
|
252
|
+
authenticated: true,
|
|
253
|
+
role: "admin",
|
|
254
|
+
email: "builtin",
|
|
255
|
+
provider: "builtin",
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function resolveClerkAccess(access: DashboardAccessConfig | null): Promise<DashboardAccess | null> {
|
|
260
|
+
if (!clerkConfigured) return null;
|
|
261
|
+
|
|
88
262
|
try {
|
|
89
263
|
const { currentUser } = await import("@clerk/nextjs/server");
|
|
90
264
|
const user = await currentUser() as ClerkUser | null;
|
|
91
|
-
if (!user)
|
|
265
|
+
if (!user) {
|
|
266
|
+
return {
|
|
267
|
+
ok: false,
|
|
268
|
+
authenticated: false,
|
|
269
|
+
reason: "Not authenticated",
|
|
270
|
+
provider: "clerk",
|
|
271
|
+
};
|
|
272
|
+
}
|
|
92
273
|
|
|
93
|
-
const email = user.emailAddresses.find((
|
|
274
|
+
const email = user.emailAddresses.find((entry) => entry.id === user.primaryEmailAddressId)?.emailAddress
|
|
94
275
|
?? user.emailAddresses[0]?.emailAddress
|
|
95
276
|
?? "";
|
|
96
277
|
|
|
97
|
-
if (!email)
|
|
278
|
+
if (!email) {
|
|
279
|
+
return {
|
|
280
|
+
ok: false,
|
|
281
|
+
authenticated: true,
|
|
282
|
+
reason: "No email on account",
|
|
283
|
+
provider: "clerk",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
98
286
|
|
|
99
287
|
const normalizedEmail = email.toLowerCase();
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
allowedEmails.length === 0 ||
|
|
107
|
-
allowedEmails.includes(normalizedEmail) ||
|
|
108
|
-
adminEmails.includes(normalizedEmail);
|
|
109
|
-
|
|
110
|
-
const domainAllowed =
|
|
111
|
-
allowedDomains.length === 0 ||
|
|
112
|
-
allowedDomains.some((d) => normalizedEmail.endsWith(`@${d}`));
|
|
113
|
-
|
|
114
|
-
if (!emailAllowed || !domainAllowed) {
|
|
115
|
-
return { ok: false, email: normalizedEmail, reason: "Email/domain not allowed" };
|
|
288
|
+
const resolved = resolveRoleForAuthenticatedEmail(normalizedEmail, access);
|
|
289
|
+
if (!resolved.ok) {
|
|
290
|
+
return {
|
|
291
|
+
...resolved,
|
|
292
|
+
provider: "clerk",
|
|
293
|
+
};
|
|
116
294
|
}
|
|
117
295
|
|
|
296
|
+
const requireApproval = (process.env.CONDUCTOR_REQUIRE_APPROVAL ?? "true") === "true";
|
|
297
|
+
const adminEmails = legacyRoleEnvFallback().adminEmails;
|
|
118
298
|
if (requireApproval && !adminEmails.includes(normalizedEmail) && !isApproved(user)) {
|
|
119
|
-
return {
|
|
299
|
+
return {
|
|
300
|
+
ok: false,
|
|
301
|
+
authenticated: true,
|
|
302
|
+
email: normalizedEmail,
|
|
303
|
+
provider: "clerk",
|
|
304
|
+
reason: "Awaiting manual approval",
|
|
305
|
+
};
|
|
120
306
|
}
|
|
121
307
|
|
|
122
|
-
return {
|
|
308
|
+
return {
|
|
309
|
+
...resolved,
|
|
310
|
+
provider: "clerk",
|
|
311
|
+
};
|
|
123
312
|
} catch {
|
|
124
313
|
return {
|
|
125
314
|
ok: false,
|
|
126
|
-
|
|
127
|
-
|
|
315
|
+
authenticated: false,
|
|
316
|
+
reason: "Authentication service is unavailable. Check Clerk env vars and retry.",
|
|
317
|
+
provider: "clerk",
|
|
128
318
|
};
|
|
129
319
|
}
|
|
130
320
|
}
|
|
131
321
|
|
|
132
|
-
export async function
|
|
133
|
-
const access = await
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
);
|
|
322
|
+
export async function getDashboardAccess(request?: Request): Promise<DashboardAccess> {
|
|
323
|
+
const access = await loadAccessConfig();
|
|
324
|
+
const host = await currentHost(request);
|
|
325
|
+
|
|
326
|
+
const trustedHeaderAccess = await resolveTrustedHeaderAccess(request, access);
|
|
327
|
+
if (trustedHeaderAccess) return trustedHeaderAccess;
|
|
328
|
+
|
|
329
|
+
const builtinAccess = await resolveBuiltinRemoteAccess();
|
|
330
|
+
if (builtinAccess) return builtinAccess;
|
|
331
|
+
|
|
332
|
+
const clerkAccess = await resolveClerkAccess(access);
|
|
333
|
+
if (clerkAccess) return clerkAccess;
|
|
334
|
+
|
|
335
|
+
const requireAuth = access?.requireAuth === true || envRequiresAuth() || hasLegacyAllowListConfigured();
|
|
336
|
+
if (!isLoopbackHost(host)) {
|
|
337
|
+
return {
|
|
338
|
+
ok: false,
|
|
339
|
+
authenticated: false,
|
|
340
|
+
reason: "Authentication is required for non-local dashboard access",
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (requireAuth) {
|
|
345
|
+
return {
|
|
346
|
+
ok: false,
|
|
347
|
+
authenticated: false,
|
|
348
|
+
reason: "Authentication required",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
ok: true,
|
|
354
|
+
authenticated: false,
|
|
355
|
+
role: "admin",
|
|
356
|
+
email: "local",
|
|
357
|
+
provider: "local",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export async function guardApiAccess(
|
|
362
|
+
request?: Request,
|
|
363
|
+
requiredRole: DashboardRole = "viewer",
|
|
364
|
+
): Promise<NextResponse | null> {
|
|
365
|
+
const access = await getDashboardAccess(request);
|
|
366
|
+
if (!access.ok) {
|
|
367
|
+
return NextResponse.json(
|
|
368
|
+
{
|
|
369
|
+
error: "Access denied",
|
|
370
|
+
reason: access.reason,
|
|
371
|
+
email: access.email ?? null,
|
|
372
|
+
},
|
|
373
|
+
{ status: 403 },
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (!access.role || !roleMeetsRequirement(access.role, requiredRole)) {
|
|
378
|
+
return NextResponse.json(
|
|
379
|
+
{
|
|
380
|
+
error: "Insufficient permissions",
|
|
381
|
+
reason: `Requires ${requiredRole} access`,
|
|
382
|
+
email: access.email ?? null,
|
|
383
|
+
role: access.role ?? null,
|
|
384
|
+
},
|
|
385
|
+
{ status: 403 },
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return null;
|
|
143
390
|
}
|
|
144
391
|
|
|
145
392
|
function matchesHost(value: string, expectedHost: string, allowedHosts: Set<string>): boolean {
|
|
@@ -191,12 +438,6 @@ function guardActionOrigin(request: NextRequest): NextResponse | null {
|
|
|
191
438
|
return null;
|
|
192
439
|
}
|
|
193
440
|
|
|
194
|
-
/**
|
|
195
|
-
* Guard mutating dashboard actions against simple CSRF-style origin/referer abuse.
|
|
196
|
-
*
|
|
197
|
-
* We keep this header-based check intentionally conservative: allow requests with
|
|
198
|
-
* missing origin/referer headers (API clients), but block obvious cross-site calls.
|
|
199
|
-
*/
|
|
200
441
|
export function guardApiActionAccess(request: NextRequest): NextResponse | null {
|
|
201
442
|
return guardActionOrigin(request);
|
|
202
443
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { exportJWK, generateKeyPair, SignJWT } from "jose";
|
|
4
|
+
import { resolveTrustedEdgeAuthConfig, verifyTrustedEdgeIdentity } from "./edgeAuth";
|
|
5
|
+
|
|
6
|
+
test("resolveTrustedEdgeAuthConfig defaults to verified Cloudflare Access mode", { concurrency: false }, () => {
|
|
7
|
+
const config = resolveTrustedEdgeAuthConfig(null);
|
|
8
|
+
|
|
9
|
+
assert.equal(config.enabled, false);
|
|
10
|
+
assert.equal(config.provider, "cloudflare-access");
|
|
11
|
+
assert.equal(config.emailHeader, "Cf-Access-Authenticated-User-Email");
|
|
12
|
+
assert.equal(config.jwtHeader, "Cf-Access-Jwt-Assertion");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("verifyTrustedEdgeIdentity blocks generic header passthrough by default", { concurrency: false }, async () => {
|
|
16
|
+
const original = process.env.CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS;
|
|
17
|
+
delete process.env.CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const result = await verifyTrustedEdgeIdentity(
|
|
21
|
+
new Headers({
|
|
22
|
+
"Cf-Access-Authenticated-User-Email": "dev@example.com",
|
|
23
|
+
}),
|
|
24
|
+
{
|
|
25
|
+
trustedHeaders: {
|
|
26
|
+
enabled: true,
|
|
27
|
+
provider: "generic",
|
|
28
|
+
emailHeader: "Cf-Access-Authenticated-User-Email",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
assert.equal(result?.ok, false);
|
|
34
|
+
assert.match(result?.reason ?? "", /disabled/i);
|
|
35
|
+
} finally {
|
|
36
|
+
if (original === undefined) {
|
|
37
|
+
delete process.env.CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS;
|
|
38
|
+
} else {
|
|
39
|
+
process.env.CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS = original;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("verifyTrustedEdgeIdentity validates a Cloudflare Access JWT before trusting the email", { concurrency: false }, async () => {
|
|
45
|
+
const { privateKey, publicKey } = await generateKeyPair("RS256");
|
|
46
|
+
const jwk = await exportJWK(publicKey);
|
|
47
|
+
jwk.kid = "edge-auth-test";
|
|
48
|
+
|
|
49
|
+
const assertion = await new SignJWT({ email: "dev@example.com" })
|
|
50
|
+
.setProtectedHeader({ alg: "RS256", kid: "edge-auth-test" })
|
|
51
|
+
.setIssuedAt()
|
|
52
|
+
.setIssuer("https://acme.cloudflareaccess.com")
|
|
53
|
+
.setAudience("cf-access-audience")
|
|
54
|
+
.setExpirationTime("5m")
|
|
55
|
+
.sign(privateKey);
|
|
56
|
+
|
|
57
|
+
const originalFetch = globalThis.fetch;
|
|
58
|
+
globalThis.fetch = async (input) => {
|
|
59
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
60
|
+
assert.equal(url, "https://acme.cloudflareaccess.com/cdn-cgi/access/certs");
|
|
61
|
+
return new Response(JSON.stringify({ keys: [jwk] }), {
|
|
62
|
+
headers: { "content-type": "application/json" },
|
|
63
|
+
status: 200,
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const result = await verifyTrustedEdgeIdentity(
|
|
69
|
+
new Headers({
|
|
70
|
+
"Cf-Access-Jwt-Assertion": assertion,
|
|
71
|
+
"Cf-Access-Authenticated-User-Email": "dev@example.com",
|
|
72
|
+
}),
|
|
73
|
+
{
|
|
74
|
+
trustedHeaders: {
|
|
75
|
+
enabled: true,
|
|
76
|
+
provider: "cloudflare-access",
|
|
77
|
+
teamDomain: "acme.cloudflareaccess.com",
|
|
78
|
+
audience: "cf-access-audience",
|
|
79
|
+
emailHeader: "Cf-Access-Authenticated-User-Email",
|
|
80
|
+
jwtHeader: "Cf-Access-Jwt-Assertion",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
assert.equal(result?.ok, true);
|
|
86
|
+
assert.equal(result?.provider, "cloudflare-access");
|
|
87
|
+
assert.equal(result?.ok ? result.email : null, "dev@example.com");
|
|
88
|
+
} finally {
|
|
89
|
+
globalThis.fetch = originalFetch;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify, type JWTPayload } from "jose";
|
|
2
|
+
import type {
|
|
3
|
+
DashboardAccessConfig,
|
|
4
|
+
TrustedHeaderAccessProvider,
|
|
5
|
+
} from "@conductor-oss/core/types";
|
|
6
|
+
|
|
7
|
+
export type TrustedEdgeAuthProvider = "trusted-header" | "cloudflare-access";
|
|
8
|
+
|
|
9
|
+
export type TrustedEdgeAuthConfig = {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
provider: TrustedHeaderAccessProvider;
|
|
12
|
+
emailHeader: string;
|
|
13
|
+
jwtHeader: string;
|
|
14
|
+
teamDomain: string | null;
|
|
15
|
+
audience: string | null;
|
|
16
|
+
allowInsecureEmailHeader: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type TrustedEdgeIdentity =
|
|
20
|
+
| {
|
|
21
|
+
ok: true;
|
|
22
|
+
email: string;
|
|
23
|
+
provider: TrustedEdgeAuthProvider;
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
ok: false;
|
|
27
|
+
reason: string;
|
|
28
|
+
provider: TrustedEdgeAuthProvider;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const DEFAULT_EMAIL_HEADER = "Cf-Access-Authenticated-User-Email";
|
|
32
|
+
const DEFAULT_JWT_HEADER = "Cf-Access-Jwt-Assertion";
|
|
33
|
+
const CLOUDFLARE_PROVIDER = "cloudflare-access";
|
|
34
|
+
const jwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();
|
|
35
|
+
|
|
36
|
+
function normalizeValue(value: string | null | undefined): string | null {
|
|
37
|
+
const trimmed = value?.trim();
|
|
38
|
+
return trimmed ? trimmed : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeTeamDomain(value: string | null | undefined): string | null {
|
|
42
|
+
const trimmed = normalizeValue(value);
|
|
43
|
+
if (!trimmed) return null;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
return new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`).hostname.toLowerCase();
|
|
47
|
+
} catch {
|
|
48
|
+
return trimmed
|
|
49
|
+
.replace(/^https?:\/\//i, "")
|
|
50
|
+
.replace(/\/+$/g, "")
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getProvider(
|
|
56
|
+
access: DashboardAccessConfig | null | undefined,
|
|
57
|
+
teamDomain: string | null,
|
|
58
|
+
audience: string | null,
|
|
59
|
+
): TrustedHeaderAccessProvider {
|
|
60
|
+
const provider =
|
|
61
|
+
normalizeValue(process.env.CONDUCTOR_TRUST_AUTH_PROVIDER)?.toLowerCase()
|
|
62
|
+
|| access?.trustedHeaders?.provider
|
|
63
|
+
|| (teamDomain || audience ? CLOUDFLARE_PROVIDER : null);
|
|
64
|
+
|
|
65
|
+
return provider === "generic" ? "generic" : CLOUDFLARE_PROVIDER;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function resolveTrustedEdgeAuthConfig(
|
|
69
|
+
access: DashboardAccessConfig | null | undefined,
|
|
70
|
+
): TrustedEdgeAuthConfig {
|
|
71
|
+
const teamDomain = normalizeTeamDomain(
|
|
72
|
+
process.env.CONDUCTOR_CLOUDFLARE_ACCESS_TEAM_DOMAIN
|
|
73
|
+
?? access?.trustedHeaders?.teamDomain,
|
|
74
|
+
);
|
|
75
|
+
const audience = normalizeValue(
|
|
76
|
+
process.env.CONDUCTOR_CLOUDFLARE_ACCESS_AUDIENCE
|
|
77
|
+
?? access?.trustedHeaders?.audience,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
enabled:
|
|
82
|
+
access?.trustedHeaders?.enabled === true
|
|
83
|
+
|| (process.env.CONDUCTOR_TRUST_AUTH_HEADERS ?? "").trim().toLowerCase() === "true",
|
|
84
|
+
provider: getProvider(access, teamDomain, audience),
|
|
85
|
+
emailHeader:
|
|
86
|
+
normalizeValue(process.env.CONDUCTOR_TRUST_AUTH_EMAIL_HEADER)
|
|
87
|
+
?? normalizeValue(access?.trustedHeaders?.emailHeader)
|
|
88
|
+
?? DEFAULT_EMAIL_HEADER,
|
|
89
|
+
jwtHeader:
|
|
90
|
+
normalizeValue(process.env.CONDUCTOR_TRUST_AUTH_JWT_HEADER)
|
|
91
|
+
?? normalizeValue(access?.trustedHeaders?.jwtHeader)
|
|
92
|
+
?? DEFAULT_JWT_HEADER,
|
|
93
|
+
teamDomain,
|
|
94
|
+
audience,
|
|
95
|
+
allowInsecureEmailHeader:
|
|
96
|
+
(process.env.CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS ?? "").trim().toLowerCase() === "true",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getCloudflareJwks(teamDomain: string) {
|
|
101
|
+
const cached = jwksCache.get(teamDomain);
|
|
102
|
+
if (cached) return cached;
|
|
103
|
+
|
|
104
|
+
const next = createRemoteJWKSet(
|
|
105
|
+
new URL(`https://${teamDomain}/cdn-cgi/access/certs`),
|
|
106
|
+
);
|
|
107
|
+
jwksCache.set(teamDomain, next);
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function extractEmailFromPayload(payload: JWTPayload): string | null {
|
|
112
|
+
const emailClaim = payload.email;
|
|
113
|
+
if (typeof emailClaim === "string" && emailClaim.trim().length > 0) {
|
|
114
|
+
return emailClaim.trim().toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const subClaim = payload.sub;
|
|
118
|
+
if (typeof subClaim === "string" && subClaim.includes("@")) {
|
|
119
|
+
return subClaim.trim().toLowerCase();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function formatJwtError(error: unknown): string {
|
|
126
|
+
if (error instanceof Error && error.message.trim().length > 0) {
|
|
127
|
+
return error.message;
|
|
128
|
+
}
|
|
129
|
+
return "Cloudflare Access token verification failed";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function verifyTrustedEdgeIdentity(
|
|
133
|
+
headers: Headers,
|
|
134
|
+
access: DashboardAccessConfig | null | undefined,
|
|
135
|
+
): Promise<TrustedEdgeIdentity | null> {
|
|
136
|
+
const config = resolveTrustedEdgeAuthConfig(access);
|
|
137
|
+
if (!config.enabled) return null;
|
|
138
|
+
|
|
139
|
+
if (config.provider === CLOUDFLARE_PROVIDER) {
|
|
140
|
+
const assertion = headers.get(config.jwtHeader)?.trim() ?? "";
|
|
141
|
+
if (!assertion) return null;
|
|
142
|
+
|
|
143
|
+
if (!config.teamDomain || !config.audience) {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
reason: "Cloudflare Access is enabled but team domain or audience is missing.",
|
|
147
|
+
provider: "cloudflare-access",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const { payload } = await jwtVerify(assertion, getCloudflareJwks(config.teamDomain), {
|
|
153
|
+
audience: config.audience,
|
|
154
|
+
issuer: `https://${config.teamDomain}`,
|
|
155
|
+
});
|
|
156
|
+
const email = extractEmailFromPayload(payload);
|
|
157
|
+
if (!email) {
|
|
158
|
+
return {
|
|
159
|
+
ok: false,
|
|
160
|
+
reason: "Cloudflare Access token is missing an email claim.",
|
|
161
|
+
provider: "cloudflare-access",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const assertedEmail = headers.get(config.emailHeader)?.trim().toLowerCase() ?? "";
|
|
166
|
+
if (assertedEmail && assertedEmail !== email) {
|
|
167
|
+
return {
|
|
168
|
+
ok: false,
|
|
169
|
+
reason: "Cloudflare Access email header does not match the verified token.",
|
|
170
|
+
provider: "cloudflare-access",
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
ok: true,
|
|
176
|
+
email,
|
|
177
|
+
provider: "cloudflare-access",
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
reason: formatJwtError(error),
|
|
183
|
+
provider: "cloudflare-access",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const email = headers.get(config.emailHeader)?.trim().toLowerCase() ?? "";
|
|
189
|
+
if (!email) return null;
|
|
190
|
+
|
|
191
|
+
if (!config.allowInsecureEmailHeader) {
|
|
192
|
+
return {
|
|
193
|
+
ok: false,
|
|
194
|
+
reason:
|
|
195
|
+
"Generic trusted-header mode is disabled. Use verified Cloudflare Access, or explicitly set CONDUCTOR_ALLOW_INSECURE_TRUSTED_HEADERS=true.",
|
|
196
|
+
provider: "trusted-header",
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
ok: true,
|
|
202
|
+
email,
|
|
203
|
+
provider: "trusted-header",
|
|
204
|
+
};
|
|
205
|
+
}
|