madarx 2.15.1 → 2.16.0
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +322 -321
- package/.next/standalone/.next/app-path-routes-manifest.json +81 -81
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +9 -9
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/activity/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/admin/page.js +2 -2
- package/.next/standalone/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/agents/[id]/page.js +6 -6
- package/.next/standalone/.next/server/app/agents/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/agents/page.js +1 -1
- package/.next/standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/activity/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/admin/audit-export/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/admin/share-links/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-memory/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-runs/[id]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-runs/[id]/events/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-runs/[id]/log/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-runs/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-runs/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[id]/chain/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[id]/memory/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[id]/reports/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[id]/run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/create/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/ops/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/approvals/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/approvals/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/acl/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/protect/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/raw/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/share-link/[linkId]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/[id]/share-link/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/artifacts/upload/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/list/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/search/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/config/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/join-bootstrap/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/session/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/brand/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/chat/sessions/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/chat/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/config/env/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/config/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/[service]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/[service]/verify/route.js +2 -2
- package/.next/standalone/.next/server/app/api/connections/[service]/verify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/connections/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/cron/tick/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/[id]/move/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/[id]/share-link/[linkId]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/[id]/share-link/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/import/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/dashboard/spaces/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/disk/files/[id]/blob/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/disk/files/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/disk/files/[id]/transcribe/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/disk/files/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/disk/folders/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/since/[cursor]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/stream/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/fs/create-folder/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/fs/pick-folder/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/blueprint/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/diagnostic/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/governance/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/interview/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/pilot/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/quarterly/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/[id]/setup-package/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/engagements/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/interviews/[id]/responses/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/interviews/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/setup-packages/[id]/apply/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hail/setup-packages/validate/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/heartbeat/tick/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/heartbeat/worker/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/help/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hermes/jobs/[id]/events/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hermes/jobs/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/hermes/jobs/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/integrations/google/callback/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/integrations/google/oauth/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/marketplace/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/marketplace/open-design/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/marketplace/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/import-roots/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/portfolio/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/projects/[id]/chunks/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/projects/[id]/diligence/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/projects/[id]/import/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/projects/[id]/publish/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mines/projects/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/missions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/onboarding/blueprint/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/onboarding/launch/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orchestrator/command/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orchestrator/stream/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orchestrator/upload/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/org/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/invites/[inviteId]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/invites/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/members/[userId]/role/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/members/[userId]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/members/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/invites/pending/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/join/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/join-complete/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/orgs/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/printing-press/clis/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/printing-press/install/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/printing-press/security-mode/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/privacy/config/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/privacy/verify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/[id]/share-link/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/[id]/stages/[stageId]/override/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/[id]/stages/[stageId]/retry/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/[id]/stages/[stageId]/submit/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/definitions/[slug]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/definitions/[slug]/settings/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/definitions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/definitions/validate/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/processes/start-and-route/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[slug]/library/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[slug]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/runs/approve-claude-run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/runs/claude-code-dry-run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/runs/competitor-report/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/runs/engine-ping/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/runs/marketing-plan/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/schedules/upsert/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/secrets/[name]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/secrets/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/settings/trust-mode/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/otp/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/verify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/space/[token]/otp/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/space/[token]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/share/space/[token]/verify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/shared/spaces/[id]/acl/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/shared/spaces/publish/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/shared/spaces/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/shared/spaces/status/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/shared/spaces/unpublish/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/state/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/system/update/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/active-run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/attachments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/checklist/[itemId]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/checklist/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/checkout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/children/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/events/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/live-runs/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/release/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tool-allowlists/[id]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tool-allowlists/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tool-egress/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tools/[name]/approve/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tools/[name]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tools/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/transcripts/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/providers/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/realtime/context/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/realtime/session/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/realtime/tool-result/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/realtime/tools/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/voice/tts/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/allowlist/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/disconnect/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/messages/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/qr/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/send/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/whatsapp/status/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/approvals/page.js +1 -1
- package/.next/standalone/.next/server/app/approvals/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/architecture/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/architecture.html +2 -2
- package/.next/standalone/.next/server/app/architecture.rsc +2 -2
- package/.next/standalone/.next/server/app/audit/live/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/brand/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/brand.html +1 -1
- package/.next/standalone/.next/server/app/brand.rsc +2 -2
- package/.next/standalone/.next/server/app/disk/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/federated-ai/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/federated-ai.html +2 -2
- package/.next/standalone/.next/server/app/federated-ai.rsc +2 -2
- package/.next/standalone/.next/server/app/hail/[id]/governance/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/hail/[id]/interview/page.js +1 -1
- package/.next/standalone/.next/server/app/hail/[id]/interview/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/hail/[id]/page.js +1 -1
- package/.next/standalone/.next/server/app/hail/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/hail/[id]/setup/page.js +2 -2
- package/.next/standalone/.next/server/app/hail/[id]/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/hail/page.js +1 -1
- package/.next/standalone/.next/server/app/hail/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/help/[slug]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +2 -2
- package/.next/standalone/.next/server/app/index.rsc +2 -2
- package/.next/standalone/.next/server/app/join/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/join.html +1 -1
- package/.next/standalone/.next/server/app/join.rsc +2 -2
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/marketplace/page.js +4 -3
- package/.next/standalone/.next/server/app/marketplace/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/marketplace/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/mines/[projectId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/mines/[projectId]/results/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/mines/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/missions/page.js +2 -2
- package/.next/standalone/.next/server/app/missions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding/org/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding.html +2 -2
- package/.next/standalone/.next/server/app/onboarding.rsc +2 -2
- package/.next/standalone/.next/server/app/org/page.js +1 -1
- package/.next/standalone/.next/server/app/org/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/org/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/[slug]/log/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/new/page.js +3 -2
- package/.next/standalone/.next/server/app/projects/new/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/new.html +1 -1
- package/.next/standalone/.next/server/app/projects/new.rsc +3 -3
- package/.next/standalone/.next/server/app/projects/page.js +32 -15
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/reports/[file]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/reports/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/runtime/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/schedules/page.js +2 -2
- package/.next/standalone/.next/server/app/schedules/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/account/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/advanced/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/appearance/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/appearance/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/brand/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/brand/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/brand.html +2 -2
- package/.next/standalone/.next/server/app/settings/brand.rsc +3 -3
- package/.next/standalone/.next/server/app/settings/connectors/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/engines/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/onboarding/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/onboarding.html +2 -2
- package/.next/standalone/.next/server/app/settings/onboarding.rsc +3 -3
- package/.next/standalone/.next/server/app/settings/organization/page.js +2 -2
- package/.next/standalone/.next/server/app/settings/organization/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/organization/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/runtime/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/runtime/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/team/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/team/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/tools/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +2 -2
- package/.next/standalone/.next/server/app/settings.rsc +3 -3
- package/.next/standalone/.next/server/app/share/[token]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/share/space/[token]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/tasks/[id]/page.js +2 -2
- package/.next/standalone/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/tasks/page.js +2 -2
- package/.next/standalone/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/team/[agentId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/team/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/whatsapp/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/whatsapp.html +1 -1
- package/.next/standalone/.next/server/app/whatsapp.rsc +2 -2
- package/.next/standalone/.next/server/app/workflows/[caseId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workflows/new/[caseId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workflows/new/definition/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workflows/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workflows/share/[caseId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +81 -81
- package/.next/standalone/.next/server/chunks/1648.js +1 -1
- package/.next/standalone/.next/server/chunks/1699.js +39 -22
- package/.next/standalone/.next/server/chunks/3230.js +2 -2
- package/.next/standalone/.next/server/chunks/5093.js +1 -0
- package/.next/standalone/.next/server/chunks/5864.js +1 -0
- package/.next/standalone/.next/server/chunks/{9801.js → 7500.js} +1 -1
- package/.next/standalone/.next/server/functions-config-manifest.json +42 -42
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/7695-04c7f1a5233de027.js +1 -0
- package/.next/standalone/.next/static/chunks/app/agents/[id]/page-474f640e84f7b4b5.js +1 -0
- package/.next/standalone/.next/static/chunks/app/agents/page-b79b611acd56712b.js +1 -0
- package/.next/standalone/.next/static/chunks/app/marketplace/page-0b7d3a6309302de3.js +1 -0
- package/.next/standalone/.next/static/chunks/app/projects/page-e1cfb0b17418e719.js +1 -0
- package/.next/standalone/.next/static/chunks/app/settings/layout-08f6b30132b26dd1.js +1 -0
- package/.next/standalone/.next/static/chunks/app/settings/team/page-9a2e675124de6aac.js +1 -0
- package/.next/standalone/.next/static/css/{65c472079b6fd086.css → 9fbf057b7ce95c36.css} +1 -1
- package/.next/standalone/CHANGELOG.md +14 -0
- package/.next/standalone/data/.artifacts-migrated-v1 +1 -1
- package/.next/standalone/data/.default-project-seeded +1 -1
- package/.next/standalone/data/madarx.sqlite +0 -0
- package/.next/standalone/data/madarx.sqlite-shm +0 -0
- package/.next/standalone/data/madarx.sqlite-wal +0 -0
- package/.next/standalone/package.json +1 -1
- package/.next/static/chunks/7695-04c7f1a5233de027.js +1 -0
- package/.next/static/chunks/app/agents/[id]/page-474f640e84f7b4b5.js +1 -0
- package/.next/static/chunks/app/agents/page-b79b611acd56712b.js +1 -0
- package/.next/static/chunks/app/marketplace/page-0b7d3a6309302de3.js +1 -0
- package/.next/static/chunks/app/projects/page-e1cfb0b17418e719.js +1 -0
- package/.next/static/chunks/app/settings/layout-08f6b30132b26dd1.js +1 -0
- package/.next/static/chunks/app/settings/team/page-9a2e675124de6aac.js +1 -0
- package/.next/static/css/{65c472079b6fd086.css → 9fbf057b7ce95c36.css} +1 -1
- package/CHANGELOG.md +14 -0
- package/app/agents/[id]/agent-activity-feed.tsx +96 -0
- package/app/agents/[id]/agent-detail-simple.tsx +71 -83
- package/app/agents/[id]/agent-quick-controls.tsx +497 -0
- package/app/agents/[id]/page.js +90 -2
- package/app/api/connections/[service]/verify/route.js +17 -2
- package/app/globals.css +347 -32
- package/lib/agent-templates.js +12 -0
- package/lib/connection-grant.js +106 -0
- package/lib/connection-seeds.js +126 -0
- package/lib/connections/health-check-verify.js +114 -0
- package/lib/connections/manifest-validator.js +161 -0
- package/lib/marketplace-modules.js +45 -0
- package/lib/marketplace-seeds.js +105 -0
- package/lib/marketplace.js +1 -0
- package/lib/oauth/flow.js +204 -0
- package/lib/oauth/provider-registry.js +102 -0
- package/lib/runtime.js +74 -1
- package/lib/schema.js +17 -0
- package/lib/tools/adapters/http-api-call.js +92 -28
- package/lib/tools/connectors/connector-validator.js +27 -1
- package/package.json +1 -1
- package/.next/standalone/.next/server/chunks/1887.js +0 -2
- package/.next/standalone/.next/server/chunks/3711.js +0 -1
- package/.next/standalone/.next/server/chunks/6098.js +0 -1
- package/.next/standalone/.next/static/chunks/9077-f54ea987eb597e43.js +0 -1
- package/.next/standalone/.next/static/chunks/app/agents/[id]/page-66477263de089865.js +0 -1
- package/.next/standalone/.next/static/chunks/app/agents/page-64d6bdc6ba3ad4d7.js +0 -1
- package/.next/standalone/.next/static/chunks/app/marketplace/page-45c6d49f8eddad67.js +0 -1
- package/.next/standalone/.next/static/chunks/app/projects/page-15a7a85fa216b575.js +0 -1
- package/.next/standalone/.next/static/chunks/app/settings/layout-2c1e6807acb6fdad.js +0 -1
- package/.next/standalone/.next/static/chunks/app/settings/team/page-0aee40dfa9e7a430.js +0 -1
- package/.next/static/chunks/9077-f54ea987eb597e43.js +0 -1
- package/.next/static/chunks/app/agents/[id]/page-66477263de089865.js +0 -1
- package/.next/static/chunks/app/agents/page-64d6bdc6ba3ad4d7.js +0 -1
- package/.next/static/chunks/app/marketplace/page-45c6d49f8eddad67.js +0 -1
- package/.next/static/chunks/app/projects/page-15a7a85fa216b575.js +0 -1
- package/.next/static/chunks/app/settings/layout-2c1e6807acb6fdad.js +0 -1
- package/.next/static/chunks/app/settings/team/page-0aee40dfa9e7a430.js +0 -1
- /package/.next/standalone/.next/static/{JcJc6PlL89SQvtZvP-LnU → JGJBLnQfb05RAKCcECbJt}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{JcJc6PlL89SQvtZvP-LnU → JGJBLnQfb05RAKCcECbJt}/_ssgManifest.js +0 -0
- /package/.next/static/{JcJc6PlL89SQvtZvP-LnU → JGJBLnQfb05RAKCcECbJt}/_buildManifest.js +0 -0
- /package/.next/static/{JcJc6PlL89SQvtZvP-LnU → JGJBLnQfb05RAKCcECbJt}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// lib/oauth/flow.js — OAuth2 authorization-code flow primitives.
|
|
2
|
+
//
|
|
3
|
+
// Local-first and provider-agnostic. Three responsibilities:
|
|
4
|
+
// 1. CSRF state — a single-use, server-stored random state value (oauth_states
|
|
5
|
+
// table). createAuthState() issues one; consumeAuthState() validates +
|
|
6
|
+
// burns it exactly once. Replay or expiry is rejected.
|
|
7
|
+
// 2. PKCE — S256 code_verifier/code_challenge generation (RFC 7636).
|
|
8
|
+
// 3. Token I/O — exchangeCodeForTokens() and refreshAccessToken(), both taking
|
|
9
|
+
// an injectable fetchFn so tests use a mock and never hit a live provider.
|
|
10
|
+
//
|
|
11
|
+
// SECURITY: this module never persists access/refresh tokens — that is the
|
|
12
|
+
// caller's job (the vault, via setSecret). The state ledger stores only the PKCE
|
|
13
|
+
// verifier and non-secret scope metadata. Tokens never appear in audit/log here.
|
|
14
|
+
|
|
15
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
16
|
+
import { getDb, nowIso } from '../db.js';
|
|
17
|
+
|
|
18
|
+
const DEFAULT_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
|
19
|
+
|
|
20
|
+
function base64url(buf) {
|
|
21
|
+
return Buffer.from(buf).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Generate a PKCE verifier + S256 challenge pair. */
|
|
25
|
+
export function generatePkce() {
|
|
26
|
+
const verifier = base64url(randomBytes(32));
|
|
27
|
+
const challenge = base64url(createHash('sha256').update(verifier).digest());
|
|
28
|
+
return { code_verifier: verifier, code_challenge: challenge, code_challenge_method: 'S256' };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Issue a single-use state value and persist it (with the PKCE verifier and
|
|
33
|
+
* scope metadata) so the callback can validate the round-trip.
|
|
34
|
+
*
|
|
35
|
+
* @returns {{ state, code_verifier?, code_challenge?, code_challenge_method? }}
|
|
36
|
+
*/
|
|
37
|
+
export function createAuthState({ service_key, provider, scope = null, redirect_uri = null, pkce = false, ttl_ms = DEFAULT_TTL_MS } = {}) {
|
|
38
|
+
if (!service_key) throw new Error('service_key is required');
|
|
39
|
+
const db = getDb();
|
|
40
|
+
const state = base64url(randomBytes(24));
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const created_at = nowIso();
|
|
43
|
+
const expires_at = new Date(now + (Number(ttl_ms) || DEFAULT_TTL_MS)).toISOString();
|
|
44
|
+
|
|
45
|
+
let pkceParts = null;
|
|
46
|
+
if (pkce) pkceParts = generatePkce();
|
|
47
|
+
|
|
48
|
+
db.prepare(`
|
|
49
|
+
INSERT INTO oauth_states (state, service_key, provider, scope_json, code_verifier, redirect_uri, created_at, expires_at, consumed_at)
|
|
50
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)
|
|
51
|
+
`).run(
|
|
52
|
+
state,
|
|
53
|
+
String(service_key),
|
|
54
|
+
String(provider || 'custom'),
|
|
55
|
+
scope ? JSON.stringify(scope) : null,
|
|
56
|
+
pkceParts?.code_verifier || null,
|
|
57
|
+
redirect_uri || null,
|
|
58
|
+
created_at,
|
|
59
|
+
expires_at,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
state,
|
|
64
|
+
code_verifier: pkceParts?.code_verifier || null,
|
|
65
|
+
code_challenge: pkceParts?.code_challenge || null,
|
|
66
|
+
code_challenge_method: pkceParts?.code_challenge_method || null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Validate + burn a state value. Returns the stored row (scope + verifier) on
|
|
72
|
+
* success, or throws. Single-use: a second call with the same state fails.
|
|
73
|
+
*/
|
|
74
|
+
export function consumeAuthState(state) {
|
|
75
|
+
if (!state) { const e = new Error('missing state'); e.code = 'state_invalid'; throw e; }
|
|
76
|
+
const db = getDb();
|
|
77
|
+
const row = db.prepare('SELECT * FROM oauth_states WHERE state = ?').get(String(state));
|
|
78
|
+
if (!row) { const e = new Error('unknown or already-consumed state'); e.code = 'state_invalid'; throw e; }
|
|
79
|
+
if (row.consumed_at) { const e = new Error('state already used'); e.code = 'state_replayed'; throw e; }
|
|
80
|
+
if (row.expires_at && Date.parse(row.expires_at) < Date.now()) {
|
|
81
|
+
const e = new Error('state expired'); e.code = 'state_expired'; throw e;
|
|
82
|
+
}
|
|
83
|
+
// Burn it. The WHERE clause guards against a concurrent double-consume.
|
|
84
|
+
const res = db.prepare('UPDATE oauth_states SET consumed_at = ? WHERE state = ? AND consumed_at IS NULL')
|
|
85
|
+
.run(nowIso(), String(state));
|
|
86
|
+
if (res.changes !== 1) { const e = new Error('state already used'); e.code = 'state_replayed'; throw e; }
|
|
87
|
+
|
|
88
|
+
let scope = null;
|
|
89
|
+
try { scope = row.scope_json ? JSON.parse(row.scope_json) : null; } catch { scope = null; }
|
|
90
|
+
return {
|
|
91
|
+
state: row.state,
|
|
92
|
+
service_key: row.service_key,
|
|
93
|
+
provider: row.provider,
|
|
94
|
+
scope,
|
|
95
|
+
code_verifier: row.code_verifier || null,
|
|
96
|
+
redirect_uri: row.redirect_uri || null,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Build the provider authorize URL the "Sign in with…" button redirects to.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} provider resolved provider (resolveProvider output)
|
|
104
|
+
* @param {object} opts { client_id, redirect_uri, state, code_challenge }
|
|
105
|
+
*/
|
|
106
|
+
export function buildAuthorizeUrl(provider, opts = {}) {
|
|
107
|
+
if (!provider?.authorize_url) throw new Error('provider.authorize_url required');
|
|
108
|
+
if (!opts.client_id) throw new Error('client_id required');
|
|
109
|
+
if (!opts.redirect_uri) throw new Error('redirect_uri required');
|
|
110
|
+
const url = new URL(provider.authorize_url);
|
|
111
|
+
url.searchParams.set('response_type', 'code');
|
|
112
|
+
url.searchParams.set('client_id', String(opts.client_id));
|
|
113
|
+
url.searchParams.set('redirect_uri', String(opts.redirect_uri));
|
|
114
|
+
if (provider.scopes?.length) url.searchParams.set('scope', provider.scopes.join(' '));
|
|
115
|
+
if (opts.state) url.searchParams.set('state', String(opts.state));
|
|
116
|
+
if (provider.pkce && opts.code_challenge) {
|
|
117
|
+
url.searchParams.set('code_challenge', String(opts.code_challenge));
|
|
118
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
119
|
+
}
|
|
120
|
+
for (const [k, v] of Object.entries(provider.extra_auth_params || {})) {
|
|
121
|
+
if (v != null) url.searchParams.set(k, String(v));
|
|
122
|
+
}
|
|
123
|
+
return url.toString();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseTokenResponse(data) {
|
|
127
|
+
if (!data || typeof data !== 'object') return null;
|
|
128
|
+
const access_token = data.access_token || null;
|
|
129
|
+
if (!access_token) return null;
|
|
130
|
+
return {
|
|
131
|
+
access_token,
|
|
132
|
+
refresh_token: data.refresh_token || null,
|
|
133
|
+
token_type: data.token_type || 'Bearer',
|
|
134
|
+
expires_in: Number.isFinite(data.expires_in) ? data.expires_in : null,
|
|
135
|
+
scope: data.scope || null,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function postForm(tokenUrl, params, fetchFn) {
|
|
140
|
+
const body = new URLSearchParams(params).toString();
|
|
141
|
+
const res = await fetchFn(tokenUrl, {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },
|
|
144
|
+
body,
|
|
145
|
+
});
|
|
146
|
+
let data = null;
|
|
147
|
+
try { data = await res.json(); } catch { data = null; }
|
|
148
|
+
return { res, data };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Exchange an authorization code for tokens.
|
|
153
|
+
*
|
|
154
|
+
* @param {object} provider resolved provider config (needs token_url)
|
|
155
|
+
* @param {object} opts { code, client_id, client_secret, redirect_uri, code_verifier }
|
|
156
|
+
* @param {Function} fetchFn injectable fetch (tests pass a mock)
|
|
157
|
+
*/
|
|
158
|
+
export async function exchangeCodeForTokens(provider, opts = {}, fetchFn = fetch) {
|
|
159
|
+
if (!provider?.token_url) throw new Error('provider.token_url required');
|
|
160
|
+
if (!opts.code) throw new Error('code required');
|
|
161
|
+
const params = {
|
|
162
|
+
grant_type: 'authorization_code',
|
|
163
|
+
code: opts.code,
|
|
164
|
+
client_id: opts.client_id || '',
|
|
165
|
+
redirect_uri: opts.redirect_uri || '',
|
|
166
|
+
};
|
|
167
|
+
if (opts.client_secret) params.client_secret = opts.client_secret;
|
|
168
|
+
if (opts.code_verifier) params.code_verifier = opts.code_verifier;
|
|
169
|
+
|
|
170
|
+
const { res, data } = await postForm(provider.token_url, params, fetchFn);
|
|
171
|
+
if (!res.ok) {
|
|
172
|
+
return { ok: false, error: 'token_exchange_failed', http_status: res.status, detail: data?.error || null };
|
|
173
|
+
}
|
|
174
|
+
const tokens = parseTokenResponse(data);
|
|
175
|
+
if (!tokens) return { ok: false, error: 'no_access_token' };
|
|
176
|
+
return { ok: true, ...tokens };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Re-mint an access token from a refresh token. Used by http_api_call on a 401.
|
|
181
|
+
*
|
|
182
|
+
* @param {object} provider resolved provider config (needs token_url)
|
|
183
|
+
* @param {object} opts { refresh_token, client_id, client_secret }
|
|
184
|
+
* @param {Function} fetchFn injectable fetch
|
|
185
|
+
*/
|
|
186
|
+
export async function refreshAccessToken(provider, opts = {}, fetchFn = fetch) {
|
|
187
|
+
if (!provider?.token_url) throw new Error('provider.token_url required');
|
|
188
|
+
if (!opts.refresh_token) throw new Error('refresh_token required');
|
|
189
|
+
const params = {
|
|
190
|
+
grant_type: 'refresh_token',
|
|
191
|
+
refresh_token: opts.refresh_token,
|
|
192
|
+
client_id: opts.client_id || '',
|
|
193
|
+
};
|
|
194
|
+
if (opts.client_secret) params.client_secret = opts.client_secret;
|
|
195
|
+
|
|
196
|
+
const { res, data } = await postForm(provider.token_url, params, fetchFn);
|
|
197
|
+
if (!res.ok) {
|
|
198
|
+
return { ok: false, error: 'refresh_failed', http_status: res.status, detail: data?.error || null };
|
|
199
|
+
}
|
|
200
|
+
const tokens = parseTokenResponse(data);
|
|
201
|
+
if (!tokens) return { ok: false, error: 'no_access_token' };
|
|
202
|
+
// Providers often omit a new refresh_token on refresh — keep the old one.
|
|
203
|
+
return { ok: true, ...tokens, refresh_token: tokens.refresh_token || opts.refresh_token };
|
|
204
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// lib/oauth/provider-registry.js — declarative OAuth2 provider catalog.
|
|
2
|
+
//
|
|
3
|
+
// Each provider is INERT DATA: authorize/token endpoints, default scopes, and
|
|
4
|
+
// whether PKCE is used. NO secrets live here — client id/secret are supplied by
|
|
5
|
+
// the operator once (per connection) and referenced from the vault by name.
|
|
6
|
+
//
|
|
7
|
+
// This registry is the single source of truth for "how do I talk to provider X's
|
|
8
|
+
// OAuth endpoints". A connection manifest's `oauth.provider` keys into it; the
|
|
9
|
+
// manifest may also override authorize_url/token_url/scopes inline so Tool-Smith
|
|
10
|
+
// connectors for not-yet-catalogued providers still work without editing code.
|
|
11
|
+
//
|
|
12
|
+
// Pure ESM — no DB, fs, or network imports.
|
|
13
|
+
|
|
14
|
+
const PROVIDERS = {
|
|
15
|
+
google: {
|
|
16
|
+
label: 'Google',
|
|
17
|
+
authorize_url: 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
18
|
+
token_url: 'https://oauth2.googleapis.com/token',
|
|
19
|
+
pkce: true,
|
|
20
|
+
// Default to read-only mail+calendar scopes; connections add what they need.
|
|
21
|
+
default_scopes: ['openid', 'email'],
|
|
22
|
+
// Google requires these to mint a refresh token.
|
|
23
|
+
extra_auth_params: { access_type: 'offline', prompt: 'consent' },
|
|
24
|
+
},
|
|
25
|
+
meta: {
|
|
26
|
+
label: 'Meta (Facebook/Instagram)',
|
|
27
|
+
authorize_url: 'https://www.facebook.com/v19.0/dialog/oauth',
|
|
28
|
+
token_url: 'https://graph.facebook.com/v19.0/oauth/access_token',
|
|
29
|
+
pkce: false,
|
|
30
|
+
default_scopes: ['public_profile'],
|
|
31
|
+
extra_auth_params: {},
|
|
32
|
+
},
|
|
33
|
+
linkedin: {
|
|
34
|
+
label: 'LinkedIn',
|
|
35
|
+
authorize_url: 'https://www.linkedin.com/oauth/v2/authorization',
|
|
36
|
+
token_url: 'https://www.linkedin.com/oauth/v2/accessToken',
|
|
37
|
+
pkce: false,
|
|
38
|
+
default_scopes: ['r_liteprofile'],
|
|
39
|
+
extra_auth_params: {},
|
|
40
|
+
},
|
|
41
|
+
tiktok: {
|
|
42
|
+
label: 'TikTok',
|
|
43
|
+
authorize_url: 'https://www.tiktok.com/v2/auth/authorize/',
|
|
44
|
+
token_url: 'https://open.tiktokapis.com/v2/oauth/token/',
|
|
45
|
+
pkce: true,
|
|
46
|
+
default_scopes: ['user.info.basic'],
|
|
47
|
+
extra_auth_params: {},
|
|
48
|
+
},
|
|
49
|
+
hubspot: {
|
|
50
|
+
label: 'HubSpot',
|
|
51
|
+
authorize_url: 'https://app.hubspot.com/oauth/authorize',
|
|
52
|
+
token_url: 'https://api.hubapi.com/oauth/v1/token',
|
|
53
|
+
pkce: false,
|
|
54
|
+
default_scopes: ['oauth'],
|
|
55
|
+
extra_auth_params: {},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a provider config, layering manifest-supplied overrides on top of the
|
|
61
|
+
* built-in catalog. Either source may be absent: a fully-inline connection
|
|
62
|
+
* manifest needs no catalog entry; a catalogued provider needs no inline URLs.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} providerKey e.g. 'google'
|
|
65
|
+
* @param {object} [overrides] connection.oauth block (authorize_url, token_url, scopes, pkce, extra_auth_params)
|
|
66
|
+
* @returns {object|null} normalized provider config, or null if unresolvable
|
|
67
|
+
*/
|
|
68
|
+
export function resolveProvider(providerKey, overrides = {}) {
|
|
69
|
+
const base = providerKey && PROVIDERS[providerKey] ? PROVIDERS[providerKey] : null;
|
|
70
|
+
const authorize_url = overrides.authorize_url || base?.authorize_url || null;
|
|
71
|
+
const token_url = overrides.token_url || base?.token_url || null;
|
|
72
|
+
if (!authorize_url || !token_url) return null;
|
|
73
|
+
|
|
74
|
+
const scopes = Array.isArray(overrides.scopes) && overrides.scopes.length
|
|
75
|
+
? overrides.scopes.slice()
|
|
76
|
+
: (base?.default_scopes || []).slice();
|
|
77
|
+
|
|
78
|
+
const pkce = typeof overrides.pkce === 'boolean' ? overrides.pkce : Boolean(base?.pkce);
|
|
79
|
+
|
|
80
|
+
const extra_auth_params = {
|
|
81
|
+
...(base?.extra_auth_params || {}),
|
|
82
|
+
...(overrides.extra_auth_params && typeof overrides.extra_auth_params === 'object'
|
|
83
|
+
? overrides.extra_auth_params
|
|
84
|
+
: {}),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
provider: providerKey || 'custom',
|
|
89
|
+
label: base?.label || providerKey || 'Custom provider',
|
|
90
|
+
authorize_url,
|
|
91
|
+
token_url,
|
|
92
|
+
scopes,
|
|
93
|
+
pkce,
|
|
94
|
+
extra_auth_params,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function listProviders() {
|
|
99
|
+
return Object.entries(PROVIDERS).map(([key, p]) => ({ provider: key, label: p.label, pkce: p.pkce }));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { PROVIDERS };
|
package/lib/runtime.js
CHANGED
|
@@ -12,7 +12,7 @@ import { listApprovalRequests } from './approvals.js';
|
|
|
12
12
|
import { defaultModelForEngine, normalizeAgentEngine } from './agent-engines.js';
|
|
13
13
|
import { DEFAULT_PROJECT_ID, appendProjectChangelog, getProject } from './projects.js';
|
|
14
14
|
import { listActivity, listTasks, reportingSnapshot } from './delegation.js';
|
|
15
|
-
import { getMainAgentTrustMode } from './tools/registry.js';
|
|
15
|
+
import { getMainAgentTrustMode, listMarketplaceTools } from './tools/registry.js';
|
|
16
16
|
import { defaultSkillsMarkdown } from './marketplace-seeds.js';
|
|
17
17
|
import { getConfig } from './config.js';
|
|
18
18
|
import { publishLiveEvent, publishStateChanged } from './live-events.js';
|
|
@@ -154,6 +154,79 @@ export function setAgentToolPermission(agentId, toolName, mode = 'approval_requi
|
|
|
154
154
|
return rowToAgentToolPermission(db.prepare('SELECT * FROM agent_tool_permissions WHERE agent_id = ? AND tool_name = ?').get(agentId, toolName));
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Set an agent's declared toolset from the simple agent page.
|
|
159
|
+
*
|
|
160
|
+
* Two sources of truth are kept in sync:
|
|
161
|
+
* - `agents.tools` (JSON list) drives the runner prompt and the /agents card
|
|
162
|
+
* icons — it is the agent's *declared* toolset.
|
|
163
|
+
* - `agent_tool_permissions` is the *enforcement* layer the runtime actually
|
|
164
|
+
* gates on. Newly added tools get a safe default mode (read-only → auto,
|
|
165
|
+
* anything that can write/send → approval_required), matching the Caretaker
|
|
166
|
+
* seeding convention. Existing non-disabled rows are left untouched so the
|
|
167
|
+
* deep per-tool modes set in Configuration survive a simple-page edit.
|
|
168
|
+
*
|
|
169
|
+
* Unknown tool names are dropped (a stale form can't poison the toolset).
|
|
170
|
+
* Workspace files are intentionally NOT rewritten here — writeAgentFiles would
|
|
171
|
+
* regenerate skills.md from defaults and clobber an owner's edits.
|
|
172
|
+
*/
|
|
173
|
+
export function updateAgentToolset(agentId, toolNames = []) {
|
|
174
|
+
if (!agentId) return { ok: false, error: 'agent_id is required' };
|
|
175
|
+
const db = getDb();
|
|
176
|
+
const agentRow = db.prepare('SELECT id, tools FROM agents WHERE id = ?').get(agentId);
|
|
177
|
+
if (!agentRow) return { ok: false, error: 'agent not found' };
|
|
178
|
+
|
|
179
|
+
const known = new Map(listMarketplaceTools().map(tool => [tool.name, tool]));
|
|
180
|
+
const next = [...new Set(
|
|
181
|
+
(Array.isArray(toolNames) ? toolNames : [])
|
|
182
|
+
.map(name => String(name || '').trim())
|
|
183
|
+
.filter(name => name && known.has(name))
|
|
184
|
+
)];
|
|
185
|
+
const desired = new Set(next);
|
|
186
|
+
|
|
187
|
+
// Reconcile against the enforcement layer (permission rows), NOT just the
|
|
188
|
+
// declared `agents.tools` column — agents created via createAgent carry a
|
|
189
|
+
// tools list but no permission rows, so a pure column diff would leave newly
|
|
190
|
+
// "kept" tools non-functional.
|
|
191
|
+
const existing = listAgentToolPermissions(agentId);
|
|
192
|
+
const existingMode = new Map(existing.map(p => [p.tool_name, p.mode]));
|
|
193
|
+
const prevEnabled = new Set(existing.filter(p => p.mode !== 'disabled').map(p => p.tool_name));
|
|
194
|
+
|
|
195
|
+
// 1) Declared toolset (drives the runner prompt + the /agents card icons).
|
|
196
|
+
db.prepare('UPDATE agents SET tools = ? WHERE id = ?').run(JSON.stringify(next), agentId);
|
|
197
|
+
|
|
198
|
+
// 2) Enable every desired tool. Existing non-disabled rows are left untouched
|
|
199
|
+
// so deep per-tool modes set in Configuration survive a simple-page edit;
|
|
200
|
+
// new or previously-disabled tools get a safe default (read-only → auto,
|
|
201
|
+
// anything that can write/send → approval_required).
|
|
202
|
+
for (const name of next) {
|
|
203
|
+
const cur = existingMode.get(name);
|
|
204
|
+
if (cur && cur !== 'disabled') continue;
|
|
205
|
+
const tool = known.get(name);
|
|
206
|
+
const mode = (tool?.risk_level === 'low' || tool?.approval_mode === 'auto')
|
|
207
|
+
? 'auto'
|
|
208
|
+
: 'approval_required';
|
|
209
|
+
setAgentToolPermission(agentId, name, mode);
|
|
210
|
+
}
|
|
211
|
+
// 3) Disable previously-enabled tools the owner removed.
|
|
212
|
+
for (const p of existing) {
|
|
213
|
+
if (p.mode !== 'disabled' && !desired.has(p.tool_name)) {
|
|
214
|
+
setAgentToolPermission(agentId, p.tool_name, 'disabled');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const added = next.filter(name => !prevEnabled.has(name));
|
|
219
|
+
const removed = [...prevEnabled].filter(name => !desired.has(name));
|
|
220
|
+
|
|
221
|
+
appendAudit({
|
|
222
|
+
type: 'agent.tools.update',
|
|
223
|
+
summary: `Updated toolset for ${agentId}`,
|
|
224
|
+
status: 'complete',
|
|
225
|
+
meta: { agent_id: agentId, added, removed, count: next.length, surface: 'agent-detail-simple' },
|
|
226
|
+
});
|
|
227
|
+
return { ok: true, tools: next, added, removed };
|
|
228
|
+
}
|
|
229
|
+
|
|
157
230
|
export function ensureOpsAgent({ silent = false } = {}) {
|
|
158
231
|
const tools = ['directory_list', 'file_read', 'file_search', 'terminal_run', 'web_search', 'web_fetch'];
|
|
159
232
|
const created = createAgent({
|
package/lib/schema.js
CHANGED
|
@@ -1555,6 +1555,23 @@ CREATE TABLE IF NOT EXISTS tool_proposals (
|
|
|
1555
1555
|
);
|
|
1556
1556
|
CREATE INDEX IF NOT EXISTS idx_tool_proposals_status ON tool_proposals(status);
|
|
1557
1557
|
|
|
1558
|
+
-- OAuth2 authorization-code state ledger. Single-use CSRF state values for the
|
|
1559
|
+
-- connection OAuth flow. A row is created at /oauth/start and consumed exactly
|
|
1560
|
+
-- once at /oauth/callback (consumed_at set). Replay of a consumed/expired state
|
|
1561
|
+
-- is rejected. code_verifier holds the PKCE verifier (never the access token).
|
|
1562
|
+
CREATE TABLE IF NOT EXISTS oauth_states (
|
|
1563
|
+
state TEXT PRIMARY KEY,
|
|
1564
|
+
service_key TEXT NOT NULL,
|
|
1565
|
+
provider TEXT NOT NULL,
|
|
1566
|
+
scope_json TEXT,
|
|
1567
|
+
code_verifier TEXT,
|
|
1568
|
+
redirect_uri TEXT,
|
|
1569
|
+
created_at TEXT NOT NULL,
|
|
1570
|
+
expires_at TEXT NOT NULL,
|
|
1571
|
+
consumed_at TEXT
|
|
1572
|
+
);
|
|
1573
|
+
CREATE INDEX IF NOT EXISTS idx_oauth_states_service ON oauth_states(service_key);
|
|
1574
|
+
|
|
1558
1575
|
|
|
1559
1576
|
`;
|
|
1560
1577
|
|
|
@@ -14,10 +14,12 @@
|
|
|
14
14
|
// Risk + approval gating happen UPSTREAM in executeRegistryTool on the endpoint's
|
|
15
15
|
// declared (clamped) risk tier before this adapter is ever called.
|
|
16
16
|
|
|
17
|
-
import { getSecret } from '../../secrets.js';
|
|
17
|
+
import { getSecret, setSecret } from '../../secrets.js';
|
|
18
18
|
import { wrapFetch } from '../../egress.js';
|
|
19
19
|
import { assertPublicHttpUrl } from './web.js';
|
|
20
20
|
import { resolveConnectorEndpoint } from '../connectors/registry.js';
|
|
21
|
+
import { resolveProvider } from '../../oauth/provider-registry.js';
|
|
22
|
+
import { refreshAccessToken } from '../../oauth/flow.js';
|
|
21
23
|
|
|
22
24
|
const MAX_RESPONSE_BYTES = 512000;
|
|
23
25
|
const RESERVED_KEYS = new Set(['__connector_slug', '__endpoint', 'approval_id', 'body', 'query']);
|
|
@@ -59,11 +61,50 @@ function buildAuth(auth = {}) {
|
|
|
59
61
|
const user = need(auth.username_ref);
|
|
60
62
|
const pass = need(auth.password_ref);
|
|
61
63
|
headers.Authorization = `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}`;
|
|
64
|
+
} else if (auth.type === 'oauth2') {
|
|
65
|
+
const secret = need(auth.access_token_ref);
|
|
66
|
+
headers[auth.header || 'Authorization'] = `${auth.prefix ?? 'Bearer '}${secret}`;
|
|
62
67
|
}
|
|
63
68
|
// type 'none' → no injection.
|
|
64
69
|
return { headers, query };
|
|
65
70
|
}
|
|
66
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Attempt a single OAuth2 access-token refresh for an oauth2 connector, re-storing
|
|
74
|
+
* the new token in the vault. Returns true on success. Best-effort: any missing
|
|
75
|
+
* refresh material or provider config means "no refresh" (returns false). The
|
|
76
|
+
* minted token is never logged or returned to the caller.
|
|
77
|
+
*/
|
|
78
|
+
async function tryRefreshOauthToken(auth, fetchFn) {
|
|
79
|
+
if (auth?.type !== 'oauth2' || !auth.refresh_token_ref) return false;
|
|
80
|
+
const refreshToken = getSecret(auth.refresh_token_ref);
|
|
81
|
+
if (!refreshToken) return false;
|
|
82
|
+
const provider = resolveProvider(auth.provider, { token_url: auth.token_url });
|
|
83
|
+
if (!provider?.token_url) return false;
|
|
84
|
+
const clientId = auth.client_id_ref ? getSecret(auth.client_id_ref) : null;
|
|
85
|
+
const clientSecret = auth.client_secret_ref ? getSecret(auth.client_secret_ref) : null;
|
|
86
|
+
let result;
|
|
87
|
+
try {
|
|
88
|
+
result = await refreshAccessToken(
|
|
89
|
+
provider,
|
|
90
|
+
{ refresh_token: String(refreshToken), client_id: clientId || '', client_secret: clientSecret || '' },
|
|
91
|
+
fetchFn,
|
|
92
|
+
);
|
|
93
|
+
} catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
if (!result?.ok || !result.access_token) return false;
|
|
97
|
+
try {
|
|
98
|
+
setSecret(auth.access_token_ref, result.access_token, { source: 'oauth_refresh' });
|
|
99
|
+
if (result.refresh_token && auth.refresh_token_ref) {
|
|
100
|
+
setSecret(auth.refresh_token_ref, result.refresh_token, { source: 'oauth_refresh' });
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
67
108
|
export async function httpApiCall(input = {}, options = {}) {
|
|
68
109
|
const connectorSlug = input.__connector_slug;
|
|
69
110
|
const endpointName = input.__endpoint;
|
|
@@ -128,7 +169,7 @@ export async function httpApiCall(input = {}, options = {}) {
|
|
|
128
169
|
// baseHeaders never carry the secret; authHeaderKeys are injected only when the
|
|
129
170
|
// target host matches the original (auth must never ride a cross-host redirect).
|
|
130
171
|
const baseHeaders = { Accept: 'application/json', ...(manifest.default_headers || {}) };
|
|
131
|
-
|
|
172
|
+
let authHeaderKeys = Object.keys(authParts.headers);
|
|
132
173
|
const method = endpointDef.method;
|
|
133
174
|
const hasBody = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method);
|
|
134
175
|
let bodyStr = null;
|
|
@@ -170,35 +211,58 @@ export async function httpApiCall(input = {}, options = {}) {
|
|
|
170
211
|
// allowlist before the next request; a redirect outside the allowlist is refused.
|
|
171
212
|
const wrappedFetch = wrapFetch(toolName, options.agent_id ?? null);
|
|
172
213
|
const REDIRECT_CODES = new Set([301, 302, 303, 307, 308]);
|
|
173
|
-
let currentUrl = url;
|
|
174
214
|
let res;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
215
|
+
// Outer loop allows a SINGLE OAuth2 refresh-on-401 retry. attempt 0 is the
|
|
216
|
+
// normal call; attempt 1 only runs after a successful token refresh.
|
|
217
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
218
|
+
let currentUrl = url;
|
|
219
|
+
let redirectError = null;
|
|
220
|
+
for (let hop = 0; hop < 5; hop++) {
|
|
221
|
+
try {
|
|
222
|
+
res = await wrappedFetch(currentUrl, buildInit(currentUrl.hostname.toLowerCase()));
|
|
223
|
+
} catch (err) {
|
|
224
|
+
return { ok: false, status: 'error', error: 'request_failed', message: String(err?.message || err) };
|
|
225
|
+
}
|
|
226
|
+
if (!REDIRECT_CODES.has(res.status)) break;
|
|
227
|
+
const loc = res.headers.get('location');
|
|
228
|
+
if (!loc) break; // 3xx with no Location — return it as-is below.
|
|
229
|
+
let next;
|
|
230
|
+
try {
|
|
231
|
+
next = new URL(loc, currentUrl);
|
|
232
|
+
} catch {
|
|
233
|
+
return { ok: false, status: 'error', error: 'bad_redirect', message: `Invalid redirect target: ${loc}` };
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
assertPublicHttpUrl(next.toString());
|
|
237
|
+
} catch (err) {
|
|
238
|
+
return { ok: false, status: 'error', error: 'blocked_redirect', message: `Redirect blocked: ${err.message}` };
|
|
239
|
+
}
|
|
240
|
+
if (!manifest.allowed_hosts.includes(next.hostname.toLowerCase())) {
|
|
241
|
+
return { ok: false, status: 'error', error: 'blocked_redirect', message: `Redirect to ${next.hostname} is not in the connector allowlist` };
|
|
242
|
+
}
|
|
243
|
+
currentUrl = next;
|
|
244
|
+
if (hop === 4) {
|
|
245
|
+
redirectError = { ok: false, status: 'error', error: 'too_many_redirects', message: 'Exceeded redirect limit' };
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
197
248
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
249
|
+
if (redirectError) return redirectError;
|
|
250
|
+
|
|
251
|
+
// OAuth2 transparent refresh: on a 401, attempt exactly one token refresh,
|
|
252
|
+
// re-store the new token, rebuild auth headers, and retry once.
|
|
253
|
+
if (attempt === 0 && res.status === 401 && (manifest.auth || {}).type === 'oauth2') {
|
|
254
|
+
const refreshed = await tryRefreshOauthToken(manifest.auth, wrappedFetch);
|
|
255
|
+
if (refreshed) {
|
|
256
|
+
try {
|
|
257
|
+
authParts = buildAuth(manifest.auth || {});
|
|
258
|
+
authHeaderKeys = Object.keys(authParts.headers);
|
|
259
|
+
} catch {
|
|
260
|
+
break; // can't rebuild auth — return the 401 as-is.
|
|
261
|
+
}
|
|
262
|
+
continue; // retry with the fresh token.
|
|
263
|
+
}
|
|
201
264
|
}
|
|
265
|
+
break;
|
|
202
266
|
}
|
|
203
267
|
|
|
204
268
|
const respContentType = res.headers.get('content-type') || '';
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
export const CONNECTOR_SLUG_REGEX = /^[a-z][a-z0-9-]{2,63}$/;
|
|
39
39
|
export const MAX_CONNECTOR_BYTES = 64 * 1024;
|
|
40
|
-
export const VALID_AUTH_TYPES = new Set(['bearer', 'api_key', 'basic', 'none']);
|
|
40
|
+
export const VALID_AUTH_TYPES = new Set(['bearer', 'api_key', 'basic', 'oauth2', 'none']);
|
|
41
41
|
|
|
42
42
|
// Ordered low→high. 'blocked' is never authorable and is intentionally absent.
|
|
43
43
|
export const RISK_ORDER = ['low', 'medium', 'high', 'irreversible_external'];
|
|
@@ -53,6 +53,8 @@ const MAX_ENDPOINTS = 50;
|
|
|
53
53
|
// comparison is applied at runtime).
|
|
54
54
|
const RAW_SECRET_KEYS = new Set([
|
|
55
55
|
'token', 'key', 'secret', 'password', 'value', 'api_key', 'bearer', 'credentials',
|
|
56
|
+
// oauth2 raw-token names — must be referenced via *_ref, never inline.
|
|
57
|
+
'access_token', 'refresh_token', 'client_id', 'client_secret',
|
|
56
58
|
]);
|
|
57
59
|
|
|
58
60
|
// ─── Internal helpers ────────────────────────────────────────────────────────
|
|
@@ -171,6 +173,27 @@ function validateAuth(auth, errors) {
|
|
|
171
173
|
pushErr(errors, 'auth.password_ref', `must match ${SECRET_REF_REGEX}`);
|
|
172
174
|
}
|
|
173
175
|
}
|
|
176
|
+
|
|
177
|
+
if (type === 'oauth2') {
|
|
178
|
+
// The access token is referenced from the vault, never inline. Refresh fields
|
|
179
|
+
// are optional (a connector can carry a long-lived token with no refresh).
|
|
180
|
+
if (!auth.access_token_ref || typeof auth.access_token_ref !== 'string') {
|
|
181
|
+
pushErr(errors, 'auth.access_token_ref', 'required for oauth2 auth (vault ref)');
|
|
182
|
+
} else if (!SECRET_REF_REGEX.test(auth.access_token_ref)) {
|
|
183
|
+
pushErr(errors, 'auth.access_token_ref', `must match ${SECRET_REF_REGEX}`);
|
|
184
|
+
}
|
|
185
|
+
for (const field of ['refresh_token_ref', 'client_id_ref', 'client_secret_ref']) {
|
|
186
|
+
if (auth[field] == null) continue;
|
|
187
|
+
if (typeof auth[field] !== 'string' || !SECRET_REF_REGEX.test(auth[field])) {
|
|
188
|
+
pushErr(errors, `auth.${field}`, `must match ${SECRET_REF_REGEX}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (auth.token_url != null) {
|
|
192
|
+
let ok = false;
|
|
193
|
+
try { ok = new URL(auth.token_url).protocol === 'https:'; } catch { ok = false; }
|
|
194
|
+
if (!ok) pushErr(errors, 'auth.token_url', 'must be a valid https URL');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
174
197
|
}
|
|
175
198
|
|
|
176
199
|
function validateDefaultHeaders(headers, errors) {
|
|
@@ -417,6 +440,9 @@ export function validateConnectorManifest(manifest, opts = {}) {
|
|
|
417
440
|
const allowedAuthKeys = new Set([
|
|
418
441
|
'type', 'header', 'prefix', 'query_param',
|
|
419
442
|
'secret_ref', 'username_ref', 'password_ref',
|
|
443
|
+
// oauth2: token reference + refresh material (all *_ref, never raw)
|
|
444
|
+
'access_token_ref', 'refresh_token_ref', 'client_id_ref', 'client_secret_ref',
|
|
445
|
+
'token_url', 'provider',
|
|
420
446
|
]);
|
|
421
447
|
for (const [k, v] of Object.entries(manifest.auth)) {
|
|
422
448
|
if (allowedAuthKeys.has(k)) normalizedAuth[k] = v;
|
package/package.json
CHANGED