@inneranimalmedia/agentsam-sdk 2.6.3 → 2.6.5
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/AGENTSAM.md +17 -0
- package/README.md +31 -10
- package/apps/client-cms-editor/AGENTS.md +12 -0
- package/apps/client-cms-editor/IMPORT_PROVENANCE.json +8 -0
- package/apps/client-cms-editor/README.md +72 -0
- package/apps/client-cms-editor/agentsam.app.json +57 -0
- package/apps/client-cms-editor/backend/README.md +5 -0
- package/apps/client-cms-editor/backend/package.json +22 -0
- package/apps/client-cms-editor/backend/src/api/client.ts +200 -0
- package/apps/client-cms-editor/backend/src/demo-bootstrap.ts +145 -0
- package/apps/client-cms-editor/backend/src/index.ts +6 -0
- package/apps/client-cms-editor/backend/src/model.ts +115 -0
- package/apps/client-cms-editor/backend/src/preview/bridge.ts +79 -0
- package/apps/client-cms-editor/backend/src/preview/urls.ts +55 -0
- package/apps/client-cms-editor/backend/src/routing/cms-route.js +293 -0
- package/apps/client-cms-editor/backend/src/routing/index.js +10 -0
- package/apps/client-cms-editor/backend/src/storefront.ts +52 -0
- package/apps/client-cms-editor/backend/tsconfig.json +15 -0
- package/apps/client-cms-editor/backend/worker/index.js +34 -0
- package/apps/client-cms-editor/backend/wrangler.jsonc +11 -0
- package/apps/client-cms-editor/bin/agentsam-cms.mjs +229 -0
- package/apps/client-cms-editor/frontend/index.html +12 -0
- package/apps/client-cms-editor/frontend/package.json +33 -0
- package/apps/client-cms-editor/frontend/src/AgentSamDrawer.tsx +188 -0
- package/apps/client-cms-editor/frontend/src/CmsAgentSurface.tsx +191 -0
- package/apps/client-cms-editor/frontend/src/CmsEditor.tsx +1345 -0
- package/apps/client-cms-editor/frontend/src/env.d.ts +14 -0
- package/apps/client-cms-editor/frontend/src/index.ts +8 -0
- package/apps/client-cms-editor/frontend/src/lib/content-safety.ts +63 -0
- package/apps/client-cms-editor/frontend/src/main.tsx +17 -0
- package/apps/client-cms-editor/frontend/src/mount.tsx +51 -0
- package/apps/client-cms-editor/frontend/src/styles/agentsam-drawer.css +214 -0
- package/apps/client-cms-editor/frontend/src/styles/cmsShell.css +1739 -0
- package/apps/client-cms-editor/frontend/src/styles/studio.css +106 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsDashboard.tsx +313 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsGuidedChatHero.tsx +121 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsHubPage.tsx +132 -0
- package/apps/client-cms-editor/frontend/src/surfaces/CmsSiteSwitcher.tsx +176 -0
- package/apps/client-cms-editor/frontend/src/surfaces/index.ts +5 -0
- package/apps/client-cms-editor/frontend/src/surfaces/types.ts +48 -0
- package/apps/client-cms-editor/frontend/tsconfig.json +25 -0
- package/apps/client-cms-editor/frontend/vite.config.ts +13 -0
- package/apps/client-cms-editor/package-lock.json +3832 -0
- package/apps/client-cms-editor/package.json +23 -0
- package/apps/client-cms-editor/reference/DONOR_README.md +52 -0
- package/apps/client-cms-editor/reference/DONOR_package-lock.json +1253 -0
- package/apps/client-cms-editor/reference/DONOR_tsconfig.json +15 -0
- package/apps/client-cms-editor/shared/cms/package.json +21 -0
- package/apps/client-cms-editor/shared/cms/src/agent-context.ts +35 -0
- package/apps/client-cms-editor/shared/cms/src/cloudflare-bindings.ts +51 -0
- package/apps/client-cms-editor/shared/cms/src/editor-types.ts +58 -0
- package/apps/client-cms-editor/shared/cms/src/index.ts +5 -0
- package/apps/client-cms-editor/shared/cms/src/publication.ts +24 -0
- package/apps/client-cms-editor/shared/cms/src/routes.ts +11 -0
- package/apps/client-cms-editor/shared/cms/tsconfig.json +12 -0
- package/bin/agentsam +16 -1
- package/bin/agentsam-rapid-rust +36 -0
- package/docs/AUTH_IDENTITY_CONTRACT.md +2 -0
- package/docs/BRAND_INTELLIGENCE.md +1 -1
- package/docs/MACHINE_INTELLIGENCE.md +120 -0
- package/docs/WINDOWS_RUNTIME_INSTALL.md +30 -0
- package/docs/architecture/AGENTSAM_APPLICATION_CONTRACT.md +188 -0
- package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
- package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
- package/docs/architecture/AGENTSAM_RUNTIME_PROTOCOL.md +151 -0
- package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
- package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
- package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
- package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +36 -0
- package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
- package/docs/architecture/R2_SLUG_NAMESPACE.md +20 -0
- package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
- package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
- package/docs/architecture/SAM_KERNEL.md +181 -0
- package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
- package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
- package/docs/architecture/WORK_PRODUCT_EXTRACTION.md +97 -0
- package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
- package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
- package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
- package/docs/brand/AGENT_SAM_ICON_GRAMMAR.md +70 -0
- package/docs/content-studio/HOST_MOUNT_CHECKLIST.md +71 -0
- package/docs/content-studio/REVISION_GATE_2026-09-27.md +501 -0
- package/docs/contracts/capability-install-planner.md +67 -0
- package/docs/contracts/environment-vocabulary.md +195 -0
- package/docs/contracts/google-cloud-oauth-setup.md +199 -0
- package/docs/local-studio/WORKMODE_DONOR_NOTES.md +1 -1
- package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +290 -0
- package/docs/plans/LOCAL-STUDIO-REAL-APP-CONTRACT-ADDENDUM-2026-09-27.md +394 -0
- package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +227 -0
- package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +221 -0
- package/docs/plans/TOMORROW-MACHINE-FIRST-BRIEFING.md +145 -0
- package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +215 -0
- package/docs/plugins.md +2 -2
- package/docs/product/AGENTSAM_PRODUCT_EXPERIENCE_STANDARD.md +280 -0
- package/docs/product/LOCAL_STUDIO_DESKTOP_EXPERIENCE.md +139 -0
- package/docs/product/README.md +8 -0
- package/docs/rapid-rust-wasm.md +35 -0
- package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
- package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
- package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
- package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
- package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
- package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
- package/migrations/d1/0013_identity_oauth_states.sql +15 -0
- package/migrations/d1/0014_auth_event_log.sql +20 -0
- package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
- package/migrations/d1/0016_cloudflare_oauth_user_oauth_tokens_ssot.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
- package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
- package/package.json +88 -14
- package/packages/agentsam-brand/README.md +106 -11
- package/packages/agentsam-brand/bin/agentsam-brand.mjs +9 -0
- package/packages/agentsam-brand/package.json +39 -7
- package/packages/agentsam-brand/src/adapters/cloudflare-images.js +453 -0
- package/packages/agentsam-brand/src/adapters/cloudflare-r2.js +74 -0
- package/packages/agentsam-brand/src/adapters/d1-registry.js +26 -0
- package/packages/agentsam-brand/src/adapters/filesystem.js +59 -0
- package/packages/agentsam-brand/src/adapters/memory.js +31 -0
- package/packages/agentsam-brand/src/cli/controller.js +503 -0
- package/packages/agentsam-brand/src/cli/wizard.js +526 -0
- package/packages/agentsam-brand/src/core/capabilities.js +201 -0
- package/packages/agentsam-brand/src/core/derivatives.js +211 -0
- package/packages/agentsam-brand/src/core/errors.js +12 -0
- package/packages/agentsam-brand/src/core/ingest.js +195 -0
- package/packages/agentsam-brand/src/core/inspect.js +109 -0
- package/packages/agentsam-brand/src/core/keys.js +83 -0
- package/packages/agentsam-brand/src/core/naming.js +142 -0
- package/packages/agentsam-brand/src/core/optimize.js +316 -0
- package/packages/agentsam-brand/src/core/pack.js +305 -0
- package/packages/agentsam-brand/src/core/plan.js +276 -0
- package/packages/agentsam-brand/src/core/preview.js +159 -0
- package/packages/agentsam-brand/src/core/processors/cloudflare.js +68 -0
- package/packages/agentsam-brand/src/core/processors/contract.js +203 -0
- package/packages/agentsam-brand/src/core/processors/index.js +148 -0
- package/packages/agentsam-brand/src/core/processors/native.js +82 -0
- package/packages/agentsam-brand/src/core/processors/sharp.js +113 -0
- package/packages/agentsam-brand/src/core/processors/squoosh-binary.js +195 -0
- package/packages/agentsam-brand/src/core/promote.js +288 -0
- package/packages/agentsam-brand/src/core/receipts.js +155 -0
- package/packages/agentsam-brand/src/core/v2/compile.js +280 -0
- package/packages/agentsam-brand/src/core/v2/derivatives-semantic.js +207 -0
- package/packages/agentsam-brand/src/core/v2/ingest-graph.js +387 -0
- package/packages/agentsam-brand/src/core/v2/roles.js +180 -0
- package/packages/agentsam-brand/src/core/v2/schema.js +209 -0
- package/packages/agentsam-brand/src/core/v2/templates.js +114 -0
- package/packages/agentsam-brand/src/index.js +193 -36
- package/packages/agentsam-brand/src/presets/app-icon.json +16 -0
- package/packages/agentsam-brand/src/presets/favicon.json +17 -0
- package/packages/agentsam-brand/src/presets/hero.json +12 -0
- package/packages/agentsam-brand/src/presets/index.js +40 -0
- package/packages/agentsam-brand/src/presets/logo.json +12 -0
- package/packages/agentsam-brand/src/presets/model.json +8 -0
- package/packages/agentsam-brand/src/presets/og-image.json +10 -0
- package/packages/agentsam-brand/src/presets/product-shot.json +11 -0
- package/packages/agentsam-brand/src/presets/social-image.json +10 -0
- package/packages/agentsam-brand/src/presets/web-image.json +10 -0
- package/packages/agentsam-contracts/src/artifacts.ts +41 -0
- package/packages/agentsam-contracts/src/errors.ts +16 -0
- package/packages/agentsam-errors/src/envelope.js +53 -0
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/recovery.js +301 -0
- package/packages/agentsam-knowledge/src/autorag/index.js +1 -1
- package/packages/agentsam-knowledge/src/providers/index.js +20 -6
- package/packages/agentsam-knowledge/src/providers/ollama-endpoint.js +31 -0
- package/packages/agentsam-knowledge/test/autorag.test.mjs +22 -1
- package/packages/agentsam-nav/package.json +2 -2
- package/packages/agentsam-rapid-rust/Cargo.lock +344 -0
- package/packages/agentsam-rapid-rust/Cargo.toml +18 -0
- package/packages/agentsam-rapid-rust/README.md +5 -0
- package/packages/agentsam-rapid-rust/src/main.rs +718 -0
- package/packages/agentsam-rapid-rust/templates/api/Cargo.toml.tmpl +18 -0
- package/packages/agentsam-rapid-rust/templates/api/src/lib.rs.tmpl +17 -0
- package/packages/agentsam-rapid-rust/templates/common/README.md.tmpl +22 -0
- package/packages/agentsam-rapid-rust/templates/common/package.json.tmpl +12 -0
- package/packages/agentsam-rapid-rust/templates/common/wrangler.toml.tmpl +6 -0
- package/packages/agentsam-rapid-rust/templates/crypto-auth/Cargo.toml.tmpl +21 -0
- package/packages/agentsam-rapid-rust/templates/crypto-auth/src/lib.rs.tmpl +32 -0
- package/packages/agentsam-rapid-rust/templates/data-processor/Cargo.toml.tmpl +18 -0
- package/packages/agentsam-rapid-rust/templates/data-processor/src/lib.rs.tmpl +41 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/Cargo.toml.tmpl +9 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/core/Cargo.toml.tmpl +7 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/core/src/lib.rs.tmpl +23 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/worker/Cargo.toml.tmpl +12 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/worker/src/lib.rs.tmpl +16 -0
- package/packages/agentsam-rapid-rust/templates/shared-core/wrangler.toml.tmpl +6 -0
- package/packages/agentsam-repository/src/index.js +1 -0
- package/packages/agentsam-repository/src/merkle/semantic.js +3 -10
- package/packages/agentsam-repository/src/source-types.js +85 -0
- package/packages/agentsam-vault/README.md +96 -0
- package/packages/agentsam-vault/package.json +32 -0
- package/packages/agentsam-vault/src/contracts/credential.d.ts +78 -0
- package/packages/agentsam-vault/src/contracts/credential.js +132 -0
- package/packages/agentsam-vault/src/crypto/aes-gcm.d.ts +30 -0
- package/packages/agentsam-vault/src/crypto/aes-gcm.js +107 -0
- package/packages/agentsam-vault/src/crypto/oauth-envelope.js +150 -0
- package/packages/agentsam-vault/src/index.d.ts +9 -0
- package/packages/agentsam-vault/src/index.js +27 -0
- package/packages/agentsam-vault/src/providers/registry.js +90 -0
- package/packages/agentsam-vault/src/runtime/resolver.js +77 -0
- package/packages/agentsam-workbench/README.md +24 -0
- package/packages/agentsam-workbench/package.json +38 -0
- package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +41 -0
- package/packages/agentsam-workbench/src/agent/ArtifactCard.tsx +9 -0
- package/packages/agentsam-workbench/src/agent/Composer.tsx +102 -0
- package/packages/agentsam-workbench/src/agent/ConnectedAgentPanel.tsx +194 -0
- package/packages/agentsam-workbench/src/agent/ContextualComposer.tsx +788 -0
- package/packages/agentsam-workbench/src/agent/GoalStatusStrip.tsx +38 -0
- package/packages/agentsam-workbench/src/agent/MiniAgentSam.tsx +86 -0
- package/packages/agentsam-workbench/src/agent/ModelSelect.tsx +19 -0
- package/packages/agentsam-workbench/src/agent/Thread.tsx +56 -0
- package/packages/agentsam-workbench/src/agent/ToolReceipt.tsx +11 -0
- package/packages/agentsam-workbench/src/agent/contextual-composer.css +611 -0
- package/packages/agentsam-workbench/src/agent/index.ts +10 -0
- package/packages/agentsam-workbench/src/agent/mini-agentsam.css +12 -0
- package/packages/agentsam-workbench/src/browser/BrowserFrame.tsx +37 -0
- package/packages/agentsam-workbench/src/browser/index.ts +1 -0
- package/packages/agentsam-workbench/src/index.ts +6 -0
- package/packages/agentsam-workbench/src/project-control.css +160 -0
- package/packages/agentsam-workbench/src/projects/ProjectsSurface.tsx +131 -0
- package/packages/agentsam-workbench/src/projects/index.ts +1 -0
- package/packages/agentsam-workbench/src/shell/Breadcrumb.tsx +35 -0
- package/packages/agentsam-workbench/src/shell/ResizableStage.tsx +99 -0
- package/packages/agentsam-workbench/src/shell/SidePanel.tsx +5 -0
- package/packages/agentsam-workbench/src/shell/index.ts +4 -0
- package/packages/agentsam-workbench/src/shell/surfaceRegistry.ts +29 -0
- package/packages/agentsam-workbench/src/terminal/TerminalSurface.tsx +5 -0
- package/packages/agentsam-workbench/src/terminal/index.ts +1 -0
- package/packages/agentsam-workbench/src/timeline/GanttBoard.tsx +258 -0
- package/packages/agentsam-workbench/src/timeline/index.ts +1 -0
- package/packages/agentsam-workbench/tsconfig.json +13 -0
- package/packages/connectors/cloudflare/OAUTH_STORAGE_AUDIT.md +53 -0
- package/packages/connectors/cloudflare/package.json +3 -1
- package/packages/connectors/cloudflare/src/api-client.js +279 -0
- package/packages/connectors/cloudflare/src/capabilities.js +585 -0
- package/packages/connectors/cloudflare/src/credential.js +318 -0
- package/packages/connectors/cloudflare/src/families/brand-protection.js +123 -0
- package/packages/connectors/cloudflare/src/families/keyless.js +114 -0
- package/packages/connectors/cloudflare/src/families/pages.js +151 -0
- package/packages/connectors/cloudflare/src/families/scanner.js +123 -0
- package/packages/connectors/cloudflare/src/families/snippets.js +207 -0
- package/packages/connectors/cloudflare/src/families/tag-gateway.js +46 -0
- package/packages/connectors/cloudflare/src/families/tags.js +124 -0
- package/packages/connectors/cloudflare/src/families/token-validation.js +95 -0
- package/packages/connectors/cloudflare/src/families/workflows.js +156 -0
- package/packages/connectors/cloudflare/src/index.js +102 -265
- package/packages/connectors/cloudflare/src/oauth-persist.js +336 -0
- package/packages/connectors/cloudflare/src/owner.js +42 -12
- package/packages/connectors/cloudflare/src/permission-options.js +1064 -0
- package/packages/connectors/cloudflare/src/routes.js +318 -144
- package/packages/connectors/cloudflare/src/scope-catalog.js +345 -0
- package/packages/connectors/cloudflare/src/vault.js +2 -2
- package/packages/connectors/cloudflare/tests/capabilities.test.mjs +276 -0
- package/packages/connectors/cloudflare/tests/connector.test.mjs +51 -30
- package/packages/connectors/cloudflare/tests/oauth-persist.test.mjs +125 -0
- package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
- package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +22 -2
- package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +10 -4
- package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +31 -2
- package/packages/identity/README.md +1 -1
- package/packages/identity/backend/README.md +1 -1
- package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
- package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +32 -0
- package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
- package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
- package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
- package/packages/identity/migrations/sqlite/004_identity_oauth_consent_catalog.sql +48 -0
- package/packages/identity/package.json +3 -2
- package/packages/identity/scripts/local-identity-bridge.mjs +184 -0
- package/packages/identity/scripts/preview-auth-portal.mjs +7 -7
- package/packages/identity/src/adapters/cloudflare-d1/index.js +153 -24
- package/packages/identity/src/adapters/sqlite/index.js +322 -0
- package/packages/identity/src/app/verify-app.js +95 -0
- package/packages/identity/src/contracts/auth-config.js +28 -8
- package/packages/identity/src/contracts/external-identity.js +1 -1
- package/packages/identity/src/contracts/identity-store.js +115 -0
- package/packages/identity/src/contracts/provider.js +1 -0
- package/packages/identity/src/contracts/route-ids.js +30 -0
- package/packages/identity/src/contracts/route-projection.js +218 -0
- package/packages/identity/src/contracts/routes.js +11 -0
- package/packages/identity/src/core/browser-paths.js +4 -5
- package/packages/identity/src/core/constants.js +13 -8
- package/packages/identity/src/core/session-policy.js +32 -0
- package/packages/identity/src/frontend/auth-portal/README.md +2 -1
- package/packages/identity/src/frontend/auth-portal/pages/login.html +16 -15
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +9 -8
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +9 -8
- package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
- package/packages/identity/src/frontend/auth-portal/shared/company-branding.js +1 -1
- package/packages/identity/src/frontend/auth-portal/shared/desktop-identity-bridge.js +207 -0
- package/packages/identity/src/index.js +41 -0
- package/packages/identity/src/migrations/0001_identity_core.sql +19 -2
- package/packages/identity/src/migrations/0003_accounts_ssot.sql +20 -0
- package/packages/identity/src/migrations/README.md +5 -2
- package/packages/identity/src/oauth/README.md +19 -8
- package/packages/identity/src/oauth/consent-view.js +388 -0
- package/packages/identity/src/oauth/credentials.js +46 -19
- package/packages/identity/src/oauth/finalize-inbound.js +1 -1
- package/packages/identity/src/oauth/google-desktop-exchange.js +173 -0
- package/packages/identity/src/oauth/iam-platform.js +8 -7
- package/packages/identity/src/oauth/redirect-paths.js +27 -36
- package/packages/identity/src/providers/cloudflare/oauth.js +3 -4
- package/packages/identity/src/providers/cloudflare/profile.js +49 -14
- package/packages/identity/src/providers/iam/index.js +27 -5
- package/packages/identity/src/server/identity-service.js +61 -15
- package/packages/identity/src/server/mount-policy.js +30 -0
- package/packages/identity/src/server/post-auth.js +79 -0
- package/packages/identity/src/server/worker-router.js +208 -146
- package/packages/identity/tests/auth-config.test.mjs +3 -2
- package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
- package/packages/identity/tests/iam-provider.test.mjs +1 -1
- package/packages/identity/tests/identity-init-scaffold.test.mjs +3 -0
- package/packages/identity/tests/identity-service.test.mjs +52 -5
- package/packages/identity/tests/native-session-worker.test.mjs +64 -0
- package/packages/identity/tests/oauth-consent-view.test.mjs +106 -0
- package/packages/identity/tests/oauth-credentials.test.mjs +20 -5
- package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +58 -0
- package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
- package/packages/identity/tests/preview-auth-portal.test.mjs +3 -3
- package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
- package/packages/runtime-protocol/src/index.js +154 -0
- package/packages/theme-church-site/package.json +2 -1
- package/packages/theme-church-site/src/index.js +1 -0
- package/packages/theme-companions-site/package.json +2 -1
- package/packages/theme-companions-site/src/index.js +1 -0
- package/packages/theme-floors-site/package.json +2 -1
- package/packages/theme-floors-site/src/index.js +1 -0
- package/packages/theme-fuelnfree-site/package.json +2 -1
- package/packages/theme-fuelnfree-site/src/index.js +1 -0
- package/packages/theme-handyman-site/package.json +2 -1
- package/packages/theme-handyman-site/src/index.js +1 -0
- package/packages/theme-insurance-site/package.json +2 -1
- package/packages/theme-insurance-site/src/index.js +1 -0
- package/packages/theme-scenes/README.md +164 -0
- package/packages/theme-scenes/package.json +53 -0
- package/packages/theme-scenes/src/blocks/index.js +30 -0
- package/packages/theme-scenes/src/contracts/index.js +286 -0
- package/packages/theme-scenes/src/demos/index.js +65 -0
- package/packages/theme-scenes/src/index.js +75 -0
- package/packages/theme-scenes/src/presets/index.js +263 -0
- package/packages/theme-scenes/src/runtime/compile.js +119 -0
- package/packages/theme-scenes/src/scenes/index.js +146 -0
- package/packages/theme-scenes/src/shell/index.js +47 -0
- package/packages/theme-scenes/src/themes/index.js +129 -0
- package/packages/theme-scenes/src/visuals/index.js +41 -0
- package/packages/theme-scenes/test/theme-scenes.test.mjs +179 -0
- package/packages/theme-shinshu-site/package.json +2 -1
- package/packages/theme-shinshu-site/src/index.js +1 -0
- package/packages/work-graph/src/index.js +34 -1
- package/packages/work-graph/src/renderers/gantt-model.js +24 -0
- package/packages/work-graph/test/work-graph.test.mjs +27 -7
- package/protocol/README.md +15 -7
- package/protocol/apps/agentsam.app.v1.schema.json +133 -0
- package/protocol/apps/agentsam.host-install.v1.schema.json +36 -0
- package/protocol/assets/README.md +9 -0
- package/protocol/assets/asset-record.v1.schema.json +64 -0
- package/protocol/brand/brandpack.v1.schema.json +43 -0
- package/protocol/credentials/issue.v1.schema.json +38 -0
- package/protocol/database/connection.v1.schema.json +41 -0
- package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
- package/protocol/errors/error-envelope.schema.json +135 -1
- package/protocol/errors/recovery.v1.schema.json +50 -0
- package/protocol/runtime/agentsam.runtime.v1.schema.json +75 -0
- package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
- package/protocol/sam/activity.v1.schema.json +48 -0
- package/protocol/sam/answer.v1.schema.json +35 -0
- package/protocol/sam/calibration.v1.schema.json +21 -0
- package/protocol/sam/decision-receipt.v1.schema.json +29 -0
- package/protocol/sam/evaluation.v1.schema.json +19 -0
- package/protocol/sam/operation.schema.json +66 -0
- package/protocol/sam/outcome.v1.schema.json +36 -0
- package/protocol/sam/question.v1.schema.json +26 -0
- package/protocol/sam/registry.seed.json +153 -0
- package/protocol/sam/result.schema.json +53 -0
- package/protocol/sam/state.v1.schema.json +23 -0
- package/protocol/scoring/README.md +10 -0
- package/protocol/scoring/scorecard.v1.schema.json +65 -0
- package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
- package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
- package/protocol/ui/icon-registry.mjs +227 -0
- package/protocol/ui/icon.v1.schema.json +51 -0
- package/registry/cms-rust-machine-20260928/installable-products.json +31 -0
- package/registry/cms-rust-machine-20260928/manifest.json +22 -0
- package/registry/cms-rust-machine-20260928/migration.sql +237 -0
- package/registry/cms-rust-machine-20260928/receipt.json +21 -0
- package/registry/cms-rust-machine-20260928/receipt.sql +27 -0
- package/scripts/build_rapid_rust_cli.py +83 -0
- package/skills/README.md +22 -9
- package/skills/agentsam-codebaseindex/SKILL.md +225 -0
- package/skills/catalog.json +14 -0
- package/src/attachments/index.js +6 -0
- package/src/attachments/intake.js +235 -0
- package/src/capabilities/repository-snapshot.js +19 -2
- package/src/cli/command-catalog.js +138 -0
- package/src/cli/dispatch.js +48 -0
- package/src/cli.js +225 -27
- package/src/commands/account-auth.js +94 -8
- package/src/commands/api-key.js +244 -0
- package/src/commands/app.js +365 -29
- package/src/commands/billing.js +127 -0
- package/src/commands/brand.js +86 -74
- package/src/commands/cheat-sheet.js +154 -0
- package/src/commands/cloudflare-login.js +222 -0
- package/src/commands/cloudflare.js +453 -23
- package/src/commands/codebaseindex.js +693 -0
- package/src/commands/compute.js +4 -0
- package/src/commands/connections.js +11 -5
- package/src/commands/credentials.js +116 -0
- package/src/commands/env.js +152 -25
- package/src/commands/gcloud-auth.js +427 -0
- package/src/commands/go.js +366 -53
- package/src/commands/google-cloud.js +375 -0
- package/src/commands/identity-init.js +2 -2
- package/src/commands/interaction-clack.js +115 -0
- package/src/commands/mcp.js +226 -33
- package/src/commands/models.js +1 -1
- package/src/commands/ollama.js +3 -2
- package/src/commands/plugins.js +7 -2
- package/src/commands/product.js +36 -0
- package/src/commands/providers.js +62 -14
- package/src/commands/runtime-status.js +28 -9
- package/src/commands/runtime.js +313 -0
- package/src/commands/rust.js +24 -0
- package/src/commands/setup.js +279 -0
- package/src/commands/shell.js +59 -5
- package/src/commands/skill.js +248 -0
- package/src/commands/skills.js +1 -1
- package/src/commands/start-local.js +6 -2
- package/src/commands/terminal.js +171 -0
- package/src/commands/update.js +140 -0
- package/src/commands/whoami.js +392 -56
- package/src/features/resolve.js +1 -0
- package/src/go/build.js +229 -39
- package/src/go/cloudflare.js +506 -105
- package/src/go/container.js +120 -0
- package/src/go/contract.js +9 -4
- package/src/go/discover.js +149 -33
- package/src/go/index.js +15 -3
- package/src/go/native-probe-runner.mjs +119 -0
- package/src/go/{registry.js → official-registry.js} +64 -7
- package/src/go/official-release.js +10 -0
- package/src/go/receipts.js +77 -10
- package/src/go/verify.js +9 -2
- package/src/index.js +31 -0
- package/src/indexing/ingest/discover-models.js +298 -0
- package/src/indexing/ingest/inventory.js +478 -0
- package/src/indexing/ingest/job-graph.js +181 -0
- package/src/indexing/ingest/materials.js +204 -0
- package/src/indexing/ingest/style-evidence.js +181 -0
- package/src/knowledge/source.js +3 -3
- package/src/lib/account-session.js +11 -4
- package/src/lib/app-authority.js +172 -0
- package/src/lib/auth.js +94 -21
- package/src/lib/core-client.js +5 -6
- package/src/lib/credentials-audit.js +451 -0
- package/src/lib/deploy/health.js +24 -6
- package/src/lib/detect-context.js +7 -1
- package/src/lib/google-cloud-connection.js +270 -0
- package/src/lib/google-cloud-inventory.js +385 -0
- package/src/lib/google-desktop-oauth.js +372 -0
- package/src/lib/google-studio-brokered-oauth.js +158 -0
- package/src/lib/identity-scaffold.js +24 -6
- package/src/lib/init-options.js +192 -0
- package/src/lib/local-scaffold.js +48 -16
- package/src/lib/provider-command-remediation.js +308 -0
- package/src/lib/provider-credentials.js +71 -21
- package/src/lib/scaffold/index.js +8 -2
- package/src/lib/scaffold/mcp-server.js +43 -0
- package/src/lib/scaffold/templates/mcp-server/index.js +397 -0
- package/src/lib/scaffold/templates/mcp-server/presets.js +39 -0
- package/src/lib/scaffold/wizards/cms.js +93 -0
- package/src/lib/scaffold/wizards/mcp-server.js +61 -0
- package/src/lib/setup/contract.js +26 -0
- package/src/lib/setup/discover.js +116 -0
- package/src/lib/setup/execute.js +205 -0
- package/src/lib/setup/planner.js +134 -0
- package/src/lib/setup/recipes.js +235 -0
- package/src/lib/setup/runtime-persist.js +197 -0
- package/src/lib/setup/runtime.js +394 -0
- package/src/lib/slash-commands.js +3 -0
- package/src/lib/terminal/machine-identity.js +95 -0
- package/src/lib/terminal-local.js +164 -0
- package/src/lib/terminal-scopes.js +52 -0
- package/src/lib/whoami-capabilities.js +184 -0
- package/src/local-fs/capability.js +121 -0
- package/src/local-fs/freshness.js +75 -0
- package/src/local-fs/index.js +385 -0
- package/src/local-fs/paths.js +100 -0
- package/src/local-pty/server.js +326 -21
- package/src/mcp/authority.js +58 -108
- package/src/mcp/client-adapters.js +68 -144
- package/src/mcp/client.js +142 -122
- package/src/mcp/cloudflare-bundles.js +225 -0
- package/src/mcp/index.js +12 -0
- package/src/models/ai-access-onboarding.js +112 -0
- package/src/models/discovery.js +10 -2
- package/src/models/inventory-core.js +9 -1
- package/src/plugins/cloudflare.js +1 -1
- package/src/providers/ollama-chat.js +2 -1
- package/src/sam/activity/index.js +183 -0
- package/src/sam/client.js +252 -0
- package/src/sam/decision/calibration.js +109 -0
- package/src/sam/decision/confidence.js +126 -0
- package/src/sam/decision/evaluate.js +157 -0
- package/src/sam/decision/evaluators/deterministic.js +341 -0
- package/src/sam/decision/evaluators/heuristic.js +61 -0
- package/src/sam/decision/evaluators/select.js +50 -0
- package/src/sam/decision/evaluators/semantic.js +149 -0
- package/src/sam/decision/hierarchical.js +61 -0
- package/src/sam/decision/index.js +53 -0
- package/src/sam/decision/policy.js +86 -0
- package/src/sam/decision/questions.js +120 -0
- package/src/sam/decision/receipt.js +148 -0
- package/src/sam/decision/state.js +117 -0
- package/src/sam/decision/types.js +22 -0
- package/src/sam/decision/validate.js +200 -0
- package/src/sam/define.js +51 -0
- package/src/sam/index.js +65 -0
- package/src/sam/operations/brand-scan.js +62 -0
- package/src/sam/operations/cad-blender-inspect.js +36 -0
- package/src/sam/operations/codebaseindex-ingest.js +49 -0
- package/src/sam/operations/decision-evaluate.js +59 -0
- package/src/sam/operations/planning-astar.js +77 -0
- package/src/sam/operations/planning-goap.js +60 -0
- package/src/sam/operations/repository-inspect.js +72 -0
- package/src/sam/operations/security-scan.js +33 -0
- package/src/sam/operations/terminal-exec.js +29 -0
- package/src/sam/planning/astar.js +311 -0
- package/src/sam/planning/goap.js +177 -0
- package/src/sam/planning/index.js +21 -0
- package/src/sam/planning/state.js +84 -0
- package/src/sam/registry.js +48 -0
- package/src/sam/result.js +77 -0
- package/src/sam/seed.js +44 -0
- package/src/sam/types.js +116 -0
- package/src/security/inventory.js +12 -2
- package/src/security/local-vault.js +2 -0
- package/src/security/scan.js +1 -1
- package/src/skills/catalog.js +64 -0
- package/src/skills/content-resolver.js +124 -0
- package/src/skills/hosted-store.js +37 -0
- package/src/skills/index.js +29 -64
- package/src/skills/interaction.js +102 -0
- package/src/skills/local-store.js +228 -0
- package/src/skills/manifest.js +104 -0
- package/src/skills/metrics.js +31 -0
- package/src/skills/registry.js +184 -0
- package/src/skills/runtime.js +287 -0
- package/src/skills/slash.js +44 -0
- package/src/ui/cli/help.js +94 -101
- package/test/account-session.test.mjs +3 -3
- package/test/app-authority-context.test.mjs +32 -0
- package/test/cli/api-key-env-whoami.test.mjs +129 -0
- package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
- package/test/cli/go.test.mjs +62 -5
- package/test/cli/mcp-client.test.mjs +21 -10
- package/test/cli/runtime-persist.test.mjs +56 -0
- package/test/cli/rust-command.test.mjs +21 -0
- package/test/cli/skill-npm-and-env.test.mjs +52 -0
- package/test/cli/wireframes-go-registry.test.mjs +87 -2
- package/test/credentials-audit.test.mjs +113 -0
- package/test/deploy-health-scan.test.mjs +29 -1
- package/test/gcloud-auth.test.mjs +111 -0
- package/test/go/build-source-identity.test.mjs +31 -0
- package/test/go/cloudflare-probe.test.mjs +274 -10
- package/test/go/distribution.test.mjs +28 -0
- package/test/google-cloud-connection.test.mjs +83 -0
- package/test/google-cloud-inventory.test.mjs +64 -0
- package/test/init-options.test.mjs +35 -0
- package/test/integration/ai-access-onboarding.test.mjs +47 -0
- package/test/integration/app-command.test.mjs +30 -0
- package/test/integration/cad-project.test.mjs +4 -1
- package/test/integration/cli-help.test.mjs +1 -1
- package/test/integration/cms-app-scaffold.test.mjs +71 -0
- package/test/integration/cms-site-tenancy-contract.test.mjs +9 -8
- package/test/integration/codebaseindex-ingest.test.mjs +214 -0
- package/test/integration/features-resolve.test.mjs +30 -11
- package/test/integration/icon-registry.test.mjs +67 -0
- package/test/integration/ingest-discover-models.test.mjs +30 -0
- package/test/integration/inspect-path-cli.test.mjs +46 -0
- package/test/integration/install-script.test.mjs +12 -9
- package/test/integration/inventory-evidence.test.mjs +125 -0
- package/test/integration/local-fs.test.mjs +113 -0
- package/test/integration/provider-env-cli.test.mjs +2 -1
- package/test/integration/runtime-status.integration.test.mjs +2 -1
- package/test/integration/sam-activity-recovery.test.mjs +147 -0
- package/test/integration/sam-decision.test.mjs +584 -0
- package/test/integration/sam-kernel.test.mjs +99 -0
- package/test/integration/sam-planning-astar.test.mjs +279 -0
- package/test/integration/skill-runtime.test.mjs +240 -0
- package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
- package/test/knowledge.test.mjs +35 -1
- package/test/loopback-oauth.test.mjs +53 -0
- package/test/models.test.mjs +14 -7
- package/test/ollama.test.mjs +22 -0
- package/test/security.test.mjs +23 -0
- package/test/setup-planner.test.mjs +74 -0
- package/test/setup-runtime.test.mjs +51 -0
- package/test/shell.test.mjs +4 -4
- package/test/terminal/local-pty.mock.test.mjs +3 -1
- package/test/terminal-machine-identity.test.mjs +88 -0
- package/test/whoami-resume.test.mjs +27 -6
- package/packages/agentsam-brand/test/brand-scan.test.mjs +0 -106
- package/packages/work-graph/prototype/README.md +0 -32
- package/packages/work-graph/prototype/data/demo-workgraph.js +0 -47
- package/packages/work-graph/prototype/renderers/timeline-model.js +0 -21
- package/packages/work-graph/prototype/renderers/workgraph-runtime.js +0 -38
- package/packages/work-graph/prototype-gnantt.html +0 -655
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side Google token exchange for CLI / desktop PKCE.
|
|
3
|
+
*
|
|
4
|
+
* Desktop/"installed" OAuth clients must be type Desktop in Google Console (no secret).
|
|
5
|
+
* If the configured desktop client_id was created as a Web client, Google demands a secret.
|
|
6
|
+
* Secrets never leave the Worker: GOOGLE_DESKTOP_CLIENT_SECRET (optional) or GOOGLE_CLIENT_SECRET
|
|
7
|
+
* when client_id matches the web client.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
11
|
+
|
|
12
|
+
function clean(value) {
|
|
13
|
+
return value == null ? '' : String(value).trim();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function json(data, status = 200) {
|
|
17
|
+
return new Response(JSON.stringify(data), {
|
|
18
|
+
status,
|
|
19
|
+
headers: {
|
|
20
|
+
'content-type': 'application/json; charset=utf-8',
|
|
21
|
+
'cache-control': 'no-store',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isLoopbackRedirect(uri) {
|
|
27
|
+
try {
|
|
28
|
+
const u = new URL(String(uri || ''));
|
|
29
|
+
if (u.protocol !== 'http:') return false;
|
|
30
|
+
return u.hostname === '127.0.0.1' || u.hostname === 'localhost' || u.hostname === '[::1]';
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve which secret (if any) the Worker may attach for this client_id.
|
|
38
|
+
*/
|
|
39
|
+
export function resolveGoogleExchangeSecret(env, clientId) {
|
|
40
|
+
const id = clean(clientId);
|
|
41
|
+
const desktopId = clean(env?.GOOGLE_DESKTOP_CLIENT_ID);
|
|
42
|
+
const webId = clean(env?.GOOGLE_CLIENT_ID);
|
|
43
|
+
const desktopSecret = clean(env?.GOOGLE_DESKTOP_CLIENT_SECRET);
|
|
44
|
+
const webSecret = clean(env?.GOOGLE_CLIENT_SECRET);
|
|
45
|
+
|
|
46
|
+
if (id && desktopId && id === desktopId && desktopSecret) {
|
|
47
|
+
return { clientId: id, clientSecret: desktopSecret, mode: 'desktop_with_optional_secret' };
|
|
48
|
+
}
|
|
49
|
+
if (id && webId && id === webId && webSecret) {
|
|
50
|
+
return { clientId: id, clientSecret: webSecret, mode: 'web_confidential' };
|
|
51
|
+
}
|
|
52
|
+
if (id && desktopId && id === desktopId) {
|
|
53
|
+
return { clientId: id, clientSecret: null, mode: 'desktop_public_pkce' };
|
|
54
|
+
}
|
|
55
|
+
return { clientId: id || null, clientSecret: null, mode: 'unknown_client' };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function exchangeGoogleAuthorizationCode({
|
|
59
|
+
code,
|
|
60
|
+
codeVerifier,
|
|
61
|
+
clientId,
|
|
62
|
+
redirectUri,
|
|
63
|
+
clientSecret = null,
|
|
64
|
+
fetchImpl = fetch,
|
|
65
|
+
} = {}) {
|
|
66
|
+
const body = new URLSearchParams({
|
|
67
|
+
grant_type: 'authorization_code',
|
|
68
|
+
code: clean(code),
|
|
69
|
+
code_verifier: clean(codeVerifier),
|
|
70
|
+
client_id: clean(clientId),
|
|
71
|
+
redirect_uri: clean(redirectUri),
|
|
72
|
+
});
|
|
73
|
+
if (clean(clientSecret)) body.set('client_secret', clean(clientSecret));
|
|
74
|
+
|
|
75
|
+
const res = await fetchImpl(GOOGLE_TOKEN_URL, {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
78
|
+
body,
|
|
79
|
+
});
|
|
80
|
+
const data = await res.json().catch(() => ({}));
|
|
81
|
+
return { ok: res.ok && Boolean(data.access_token), status: res.status, data };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* POST /api/oauth/google/desktop-exchange
|
|
86
|
+
* Body JSON: { code, code_verifier, redirect_uri, client_id }
|
|
87
|
+
*/
|
|
88
|
+
export async function handleGoogleDesktopExchangeRequest(request, env, opts = {}) {
|
|
89
|
+
if (request.method !== 'POST') {
|
|
90
|
+
return json({ ok: false, error: 'method_not_allowed' }, 405);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let payload = {};
|
|
94
|
+
try {
|
|
95
|
+
payload = await request.json();
|
|
96
|
+
} catch {
|
|
97
|
+
return json({ ok: false, error: 'invalid_json' }, 400);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const code = clean(payload.code);
|
|
101
|
+
const codeVerifier = clean(payload.code_verifier || payload.codeVerifier);
|
|
102
|
+
const redirectUri = clean(payload.redirect_uri || payload.redirectUri);
|
|
103
|
+
const clientId = clean(payload.client_id || payload.clientId);
|
|
104
|
+
|
|
105
|
+
if (!code || !codeVerifier || !redirectUri || !clientId) {
|
|
106
|
+
return json({
|
|
107
|
+
ok: false,
|
|
108
|
+
error: 'code_code_verifier_redirect_uri_client_id_required',
|
|
109
|
+
}, 400);
|
|
110
|
+
}
|
|
111
|
+
if (!isLoopbackRedirect(redirectUri)) {
|
|
112
|
+
return json({ ok: false, error: 'redirect_uri_must_be_loopback' }, 400);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const allowed = new Set(
|
|
116
|
+
[clean(env?.GOOGLE_DESKTOP_CLIENT_ID), clean(env?.GOOGLE_CLIENT_ID)].filter(Boolean),
|
|
117
|
+
);
|
|
118
|
+
if (!allowed.has(clientId)) {
|
|
119
|
+
return json({ ok: false, error: 'client_id_not_configured_on_host' }, 403);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const resolved = resolveGoogleExchangeSecret(env, clientId);
|
|
123
|
+
if (resolved.mode === 'unknown_client') {
|
|
124
|
+
return json({ ok: false, error: 'client_id_not_configured_on_host' }, 403);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const fetchImpl = opts.fetchImpl || fetch;
|
|
128
|
+
const result = await exchangeGoogleAuthorizationCode({
|
|
129
|
+
code,
|
|
130
|
+
codeVerifier,
|
|
131
|
+
clientId,
|
|
132
|
+
redirectUri,
|
|
133
|
+
clientSecret: resolved.clientSecret,
|
|
134
|
+
fetchImpl,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const detail = String(result.data?.error_description || result.data?.error || '');
|
|
138
|
+
if (
|
|
139
|
+
!result.ok
|
|
140
|
+
&& /client_secret/i.test(detail)
|
|
141
|
+
&& resolved.mode === 'desktop_public_pkce'
|
|
142
|
+
&& !resolved.clientSecret
|
|
143
|
+
) {
|
|
144
|
+
return json({
|
|
145
|
+
ok: false,
|
|
146
|
+
error: 'desktop_client_requires_secret',
|
|
147
|
+
detail,
|
|
148
|
+
remediation: [
|
|
149
|
+
'In Google Cloud Console create OAuth client type Desktop app (no secret) and set GOOGLE_DESKTOP_CLIENT_ID to that client id.',
|
|
150
|
+
'Or if this client id is a Web app, put its secret on the Worker: wrangler secret put GOOGLE_DESKTOP_CLIENT_SECRET',
|
|
151
|
+
'Web browser login continues to use GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET.',
|
|
152
|
+
],
|
|
153
|
+
}, 502);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!result.ok) {
|
|
157
|
+
return json({
|
|
158
|
+
ok: false,
|
|
159
|
+
error: 'google_token_exchange_failed',
|
|
160
|
+
detail: detail || `http_${result.status}`,
|
|
161
|
+
}, 502);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return json({
|
|
165
|
+
ok: true,
|
|
166
|
+
access_token: result.data.access_token,
|
|
167
|
+
refresh_token: result.data.refresh_token || null,
|
|
168
|
+
token_type: result.data.token_type || 'Bearer',
|
|
169
|
+
expires_in: result.data.expires_in || null,
|
|
170
|
+
scope: result.data.scope || null,
|
|
171
|
+
exchange_mode: resolved.mode,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IDENTITY_ROUTE_IDS } from '../contracts/route-ids.js';
|
|
2
2
|
import {
|
|
3
3
|
IAM_PLATFORM_CALLBACK_PATH,
|
|
4
4
|
IAM_PLATFORM_STATE_PROVIDER,
|
|
@@ -38,6 +38,7 @@ export async function iamPlatformOAuthStart(request, env, adapter, identity) {
|
|
|
38
38
|
provider: IAM_PLATFORM_STATE_PROVIDER,
|
|
39
39
|
codeVerifier,
|
|
40
40
|
redirectTo,
|
|
41
|
+
appId: identity?.app?.id || null,
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
const redirectUri = `${url.origin}${IAM_PLATFORM_CALLBACK_PATH}`;
|
|
@@ -67,15 +68,15 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
|
|
|
67
68
|
const err = url.searchParams.get('error');
|
|
68
69
|
|
|
69
70
|
if (err || !code || !state) {
|
|
70
|
-
return Response.redirect(`${url.origin}${
|
|
71
|
+
return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=oauth_failed`, 302);
|
|
71
72
|
}
|
|
72
73
|
if (!creds) {
|
|
73
|
-
return Response.redirect(`${url.origin}${
|
|
74
|
+
return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=iam_oauth_not_configured`, 302);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
const saved = await adapter.consumeOAuthState(state);
|
|
77
78
|
if (!saved || saved.provider !== IAM_PLATFORM_STATE_PROVIDER) {
|
|
78
|
-
return Response.redirect(`${url.origin}${
|
|
79
|
+
return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=state_mismatch`, 302);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
const redirectUri = `${url.origin}${IAM_PLATFORM_CALLBACK_PATH}`;
|
|
@@ -88,7 +89,7 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
|
|
|
88
89
|
redirectUri,
|
|
89
90
|
});
|
|
90
91
|
if (!token?.access_token) {
|
|
91
|
-
return Response.redirect(`${url.origin}${
|
|
92
|
+
return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=token_exchange_failed`, 302);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
const profile = await fetchIamProfile({
|
|
@@ -97,7 +98,7 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
|
|
|
97
98
|
});
|
|
98
99
|
const normalized = profile ? normalizeIamIdentity(profile) : null;
|
|
99
100
|
if (!normalized?.subject || !normalized?.email) {
|
|
100
|
-
return Response.redirect(`${url.origin}${
|
|
101
|
+
return Response.redirect(`${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?error=userinfo_failed`, 302);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const result = await identity.provisionOAuthUser({
|
|
@@ -109,7 +110,7 @@ export async function iamPlatformOAuthCallback(request, env, adapter, identity)
|
|
|
109
110
|
|
|
110
111
|
const redirectTo = identity.resolvePostLoginPath(saved.redirect_to);
|
|
111
112
|
const res = identity.buildLoginSuccessResponse(request, result.sessionId, redirectTo);
|
|
112
|
-
const globeUrl = `${url.origin}${
|
|
113
|
+
const globeUrl = `${url.origin}${identity.routeRegistry.resolve(identity.app.id, IDENTITY_ROUTE_IDS.LOGIN)}?globe_exit=1&next=${encodeURIComponent(redirectTo)}`;
|
|
113
114
|
return new Response(null, {
|
|
114
115
|
status: 302,
|
|
115
116
|
headers: {
|
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Post-OAuth redirect helpers — portable path policy with host injectables.
|
|
3
|
+
* Hosts MUST pass loginPath from their route projection (never hardcode).
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
import { sanitizeBrowserNextPath } from '../core/browser-paths.js';
|
|
7
|
+
import { IdentityRoutingError } from '../contracts/identity-store.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @typedef {object} OAuthRedirectPathOptions
|
|
9
11
|
* @property {string} [authCookieName]
|
|
10
|
-
* @property {string}
|
|
12
|
+
* @property {string} loginPath concrete projection of identity.login
|
|
13
|
+
* @property {string} [fallback] only used when isAllowedLoginResumePath rejects; prefer omit
|
|
11
14
|
* @property {(path: string) => boolean} [isAllowedLoginResumePath]
|
|
12
15
|
* @property {(env: unknown, rawCookie: string) => Promise<string|null>} [resolveSessionIdFromCookie]
|
|
13
16
|
* @property {(env: unknown, sessionId: string, reason: string, userId: string|null) => Promise<void>} [revokeAuthSession]
|
|
14
17
|
*/
|
|
15
18
|
|
|
16
|
-
/**
|
|
17
|
-
* @param {OAuthRedirectPathOptions} options
|
|
18
|
-
*/
|
|
19
19
|
export function createOAuthRedirectHelpers(options = {}) {
|
|
20
20
|
const authCookieName = options.authCookieName ?? 'iam_session';
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const loginPath = options.loginPath;
|
|
22
|
+
if (!loginPath || !String(loginPath).startsWith('/')) {
|
|
23
|
+
throw new IdentityRoutingError(
|
|
24
|
+
'AUTH_ROUTE_MISSING',
|
|
25
|
+
'createOAuthRedirectHelpers requires loginPath from route projection',
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const isAllowedLoginResumePath = options.isAllowedLoginResumePath
|
|
29
|
+
?? ((path) => Boolean(sanitizeBrowserNextPath(path)));
|
|
23
30
|
const resolveSessionIdFromCookie = options.resolveSessionIdFromCookie;
|
|
24
31
|
const revokeAuthSession = options.revokeAuthSession;
|
|
25
32
|
|
|
26
|
-
/** Revoke browser cookie session before issuing a new login session. */
|
|
27
33
|
async function revokeIncomingCookieSession(request, env, reason = 'oauth_login_replaced') {
|
|
28
34
|
const cookie = request.headers.get('Cookie') || '';
|
|
29
35
|
const match = cookie.match(new RegExp(`(?:^|;\\s*)${authCookieName}=([^;]+)`));
|
|
@@ -45,48 +51,33 @@ export function createOAuthRedirectHelpers(options = {}) {
|
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (t.startsWith('/') && !t.startsWith('//') && !t.includes('://')) {
|
|
53
|
-
if (isAllowedLoginResumePath(t)) return t;
|
|
54
|
-
if (t.startsWith('/dashboard/settings/integrations')) return dashboardFallback;
|
|
55
|
-
if (!t.startsWith('/dashboard')) return dashboardFallback;
|
|
56
|
-
return t;
|
|
54
|
+
function safeLoginRedirectPath(_originBase, returnTo) {
|
|
55
|
+
const cleaned = sanitizeBrowserNextPath(returnTo);
|
|
56
|
+
if (!cleaned) {
|
|
57
|
+
throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'return_to missing/invalid');
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const ob = new URL(originBase);
|
|
61
|
-
if (u.origin !== ob.origin) return dashboardFallback;
|
|
62
|
-
const p = u.pathname + (u.search || '');
|
|
63
|
-
if (p.startsWith('/dashboard/settings/integrations')) return dashboardFallback;
|
|
64
|
-
if (!p.startsWith('/dashboard')) return dashboardFallback;
|
|
65
|
-
return p;
|
|
66
|
-
} catch {
|
|
67
|
-
return dashboardFallback;
|
|
59
|
+
if (!isAllowedLoginResumePath(cleaned)) {
|
|
60
|
+
throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'return_to not allowed', { returnTo: cleaned });
|
|
68
61
|
}
|
|
62
|
+
return cleaned;
|
|
69
63
|
}
|
|
70
64
|
|
|
71
65
|
function oauthPostLoginGlobeRedirectUrl(originBase, returnToFullUrl) {
|
|
72
|
-
let path
|
|
66
|
+
let path;
|
|
73
67
|
try {
|
|
74
68
|
const u = new URL(returnToFullUrl);
|
|
75
69
|
path = u.pathname + (u.search || '');
|
|
76
70
|
} catch {
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
if (!path.startsWith('/') || path.startsWith('//')) path = dashboardFallback;
|
|
80
|
-
if (path.startsWith('/dashboard/settings/integrations')) path = dashboardFallback;
|
|
81
|
-
if (!isAllowedLoginResumePath(path) && !path.startsWith('/dashboard')) {
|
|
82
|
-
path = dashboardFallback;
|
|
71
|
+
throw new IdentityRoutingError('AUTH_DESTINATION_UNRESOLVED', 'invalid returnToFullUrl');
|
|
83
72
|
}
|
|
84
|
-
|
|
73
|
+
path = safeLoginRedirectPath(originBase, path);
|
|
74
|
+
return `${originBase}${loginPath}?globe_exit=1&next=${encodeURIComponent(path)}`;
|
|
85
75
|
}
|
|
86
76
|
|
|
87
77
|
return {
|
|
88
78
|
revokeIncomingCookieSession,
|
|
89
|
-
safeDashboardLoginRedirectPath,
|
|
79
|
+
safeDashboardLoginRedirectPath: safeLoginRedirectPath,
|
|
80
|
+
safeLoginRedirectPath,
|
|
90
81
|
oauthPostLoginGlobeRedirectUrl,
|
|
91
82
|
};
|
|
92
83
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const CLOUDFLARE_AUTH_URL = 'https://dash.cloudflare.com/oauth2/auth';
|
|
2
2
|
const CLOUDFLARE_TOKEN_URL = 'https://dash.cloudflare.com/oauth2/token';
|
|
3
3
|
|
|
4
|
-
// Identity-only login
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
const CLOUDFLARE_LOGIN_SCOPE = 'account-settings.read offline_access';
|
|
4
|
+
// Identity-only login: account identity + user details (email/name via /v4/user).
|
|
5
|
+
// Do NOT request the resource-access scope set used by the Cloudflare *connection* flow.
|
|
6
|
+
const CLOUDFLARE_LOGIN_SCOPE = 'account-settings.read user-details.read offline_access';
|
|
8
7
|
|
|
9
8
|
/** @param {import('../../provider-contract.js').OAuthAuthorizeInput} input */
|
|
10
9
|
export function getCloudflareAuthUrl({ clientId, redirectUri, state, codeChallenge, scope } = {}) {
|
|
@@ -1,26 +1,61 @@
|
|
|
1
1
|
const CLOUDFLARE_USERINFO_URL = 'https://dash.cloudflare.com/oauth2/userinfo';
|
|
2
|
+
const CLOUDFLARE_API_USER_URL = 'https://api.cloudflare.com/client/v4/user';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Fetch the authenticated Cloudflare user's identity.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* OIDC userinfo (`/oauth2/userinfo`) structurally returns `sub` only.
|
|
8
|
+
* Email/name require `user-details.read` and a second call to `/client/v4/user`
|
|
9
|
+
* (`data.result.*`, not top-level fields).
|
|
10
|
+
*
|
|
9
11
|
* @param {string} accessToken
|
|
12
|
+
* @param {{ fetchImpl?: typeof fetch }} [opts]
|
|
10
13
|
*/
|
|
11
|
-
export async function fetchCloudflareProfile(accessToken) {
|
|
14
|
+
export async function fetchCloudflareProfile(accessToken, opts = {}) {
|
|
15
|
+
const token = String(accessToken || '').trim();
|
|
16
|
+
if (!token) return null;
|
|
17
|
+
const fetchImpl = opts.fetchImpl || fetch;
|
|
12
18
|
try {
|
|
13
|
-
const
|
|
14
|
-
headers: { Authorization: `Bearer ${
|
|
19
|
+
const userinfoRes = await fetchImpl(CLOUDFLARE_USERINFO_URL, {
|
|
20
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
15
21
|
});
|
|
16
|
-
if (!
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
22
|
+
if (!userinfoRes.ok) return null;
|
|
23
|
+
const userinfo = await userinfoRes.json().catch(() => null);
|
|
24
|
+
if (!userinfo) return null;
|
|
25
|
+
|
|
26
|
+
const sub = userinfo.sub || userinfo.id || userinfo.user_id || null;
|
|
27
|
+
let email = typeof userinfo.email === 'string' ? userinfo.email : null;
|
|
28
|
+
let name = typeof userinfo.name === 'string'
|
|
29
|
+
? userinfo.name
|
|
30
|
+
: (typeof userinfo.display_name === 'string' ? userinfo.display_name : null);
|
|
31
|
+
|
|
32
|
+
// Cloudflare userinfo does not return email/name — enrich from /v4/user.
|
|
33
|
+
if (!email || !name) {
|
|
34
|
+
try {
|
|
35
|
+
const apiRes = await fetchImpl(CLOUDFLARE_API_USER_URL, {
|
|
36
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
|
|
37
|
+
});
|
|
38
|
+
if (apiRes.ok) {
|
|
39
|
+
const body = await apiRes.json().catch(() => null);
|
|
40
|
+
const result = body?.result && typeof body.result === 'object' ? body.result : null;
|
|
41
|
+
if (result) {
|
|
42
|
+
if (!email && typeof result.email === 'string') email = result.email;
|
|
43
|
+
if (!name && typeof result.first_name === 'string' && typeof result.last_name === 'string') {
|
|
44
|
+
name = `${result.first_name} ${result.last_name}`.trim() || null;
|
|
45
|
+
}
|
|
46
|
+
if (!name && typeof result.name === 'string') name = result.name;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// Non-fatal: identity can proceed with sub alone.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
19
54
|
return {
|
|
20
|
-
sub:
|
|
21
|
-
email
|
|
22
|
-
name
|
|
23
|
-
raw:
|
|
55
|
+
sub: sub || null,
|
|
56
|
+
email,
|
|
57
|
+
name,
|
|
58
|
+
raw: userinfo,
|
|
24
59
|
};
|
|
25
60
|
} catch {
|
|
26
61
|
return null;
|
|
@@ -9,13 +9,16 @@ import {
|
|
|
9
9
|
} from './oauth.js';
|
|
10
10
|
import { fetchIamProfile } from './profile.js';
|
|
11
11
|
import { normalizeIamIdentity } from './mapper.js';
|
|
12
|
-
import {
|
|
12
|
+
import { resolveIamIssuer } from '../../contracts/auth-config.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {string}
|
|
15
|
+
* @param {string} origin Absolute IAM issuer origin (required — no DEFAULT_*).
|
|
16
16
|
*/
|
|
17
|
-
export function createIamIdentityProvider(origin
|
|
18
|
-
const resolvedOrigin = String(origin ||
|
|
17
|
+
export function createIamIdentityProvider(origin) {
|
|
18
|
+
const resolvedOrigin = String(origin || '').replace(/\/+$/, '');
|
|
19
|
+
if (!resolvedOrigin) {
|
|
20
|
+
throw new Error('IAM_OAUTH_ISSUER is required to create the IAM identity provider');
|
|
21
|
+
}
|
|
19
22
|
return createIdentityProvider({
|
|
20
23
|
id: 'iam',
|
|
21
24
|
authorizeUrl: (input) => getIamAuthUrl({ ...input, origin: resolvedOrigin }),
|
|
@@ -25,7 +28,26 @@ export function createIamIdentityProvider(origin = DEFAULT_IAM_ORIGIN) {
|
|
|
25
28
|
});
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Registry singleton — resolves IAM_OAUTH_ISSUER from env/input at call time.
|
|
33
|
+
* No baked-in product host.
|
|
34
|
+
*/
|
|
35
|
+
export const IamProvider = createIdentityProvider({
|
|
36
|
+
id: 'iam',
|
|
37
|
+
authorizeUrl: (input) => {
|
|
38
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
39
|
+
return getIamAuthUrl({ ...input, origin });
|
|
40
|
+
},
|
|
41
|
+
exchangeCode: (input) => {
|
|
42
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
43
|
+
return exchangeIamCode({ ...input, origin });
|
|
44
|
+
},
|
|
45
|
+
getProfile: (accessToken, input = {}) => {
|
|
46
|
+
const origin = resolveIamIssuer(input?.env || process.env, input?.origin || input?.issuer || '');
|
|
47
|
+
return fetchIamProfile({ origin, accessToken });
|
|
48
|
+
},
|
|
49
|
+
normalizeIdentity: normalizeIamIdentity,
|
|
50
|
+
});
|
|
29
51
|
|
|
30
52
|
export {
|
|
31
53
|
getIamAuthUrl,
|
|
@@ -1,33 +1,48 @@
|
|
|
1
|
-
import { AUTH_COOKIE_NAME,
|
|
1
|
+
import { AUTH_COOKIE_NAME, SESSION_POLICY } from '../core/constants.js';
|
|
2
2
|
import { hashPassword, verifyPassword } from '../core/password-crypto.js';
|
|
3
3
|
import { jsonResponse } from '../core/http-json.js';
|
|
4
|
-
import {
|
|
4
|
+
import { resolvePostAuthDestination } from './post-auth.js';
|
|
5
|
+
import { IdentityRoutingError } from '../contracts/identity-store.js';
|
|
5
6
|
import { newAuthUserId } from '../adapters/cloudflare-d1/ids.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
* @typedef {
|
|
9
|
+
* @typedef {import('../contracts/identity-store.js').IdentityStore} IdentityStore
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Server-side identity orchestration (Worker / Node). No secrets in client bundle.
|
|
13
|
-
*
|
|
14
|
+
* Hosts must supply `app` + `routeRegistry` — no platform "/" fallback.
|
|
15
|
+
*
|
|
16
|
+
* @param {{
|
|
17
|
+
* adapter: IdentityStore,
|
|
18
|
+
* cookieName?: string,
|
|
19
|
+
* app: { id: string },
|
|
20
|
+
* routeRegistry: ReturnType<import('../contracts/route-projection.js').createRouteRegistry>,
|
|
21
|
+
* }} config
|
|
14
22
|
*/
|
|
15
23
|
export function createIdentityService(config) {
|
|
16
24
|
const adapter = config.adapter;
|
|
17
25
|
if (!adapter) throw new Error('identity_service_requires_adapter');
|
|
18
26
|
const cookieName = config.cookieName || AUTH_COOKIE_NAME;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
const app = config.app || null;
|
|
28
|
+
const routeRegistry = config.routeRegistry || null;
|
|
29
|
+
if (!app?.id || !routeRegistry) {
|
|
30
|
+
throw new IdentityRoutingError(
|
|
31
|
+
'AUTH_APP_UNRESOLVED',
|
|
32
|
+
'createIdentityService requires app + routeRegistry (no platform fallback)',
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
routeRegistry.assertAuthCapable(app.id);
|
|
22
36
|
|
|
23
|
-
// OAuth state is durable and may outlive a deployment. Normalize both the
|
|
24
|
-
// incoming request value and a value read back from prior state so an old or
|
|
25
|
-
// malformed value can never become an open redirect.
|
|
26
37
|
function resolvePostLoginPath(nextPath) {
|
|
27
|
-
return
|
|
38
|
+
return resolvePostAuthDestination({
|
|
39
|
+
transaction: { return_to: nextPath, app_id: app.id },
|
|
40
|
+
app,
|
|
41
|
+
routeRegistry,
|
|
42
|
+
});
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
function sessionCookieHeader(sessionId, requestUrl, maxAge =
|
|
45
|
+
function sessionCookieHeader(sessionId, requestUrl, maxAge = SESSION_POLICY.browser.ttlSeconds) {
|
|
31
46
|
const secure = new URL(requestUrl).protocol === 'https:';
|
|
32
47
|
const parts = [
|
|
33
48
|
`${cookieName}=${sessionId}`,
|
|
@@ -46,9 +61,16 @@ export function createIdentityService(config) {
|
|
|
46
61
|
return match ? decodeURIComponent(match[1]) : null;
|
|
47
62
|
}
|
|
48
63
|
|
|
64
|
+
function parseBearerSessionId(authorization) {
|
|
65
|
+
const match = String(authorization || '').match(/^Bearer\s+([^\s]+)$/i);
|
|
66
|
+
return match ? match[1] : null;
|
|
67
|
+
}
|
|
68
|
+
|
|
49
69
|
return Object.freeze({
|
|
50
70
|
cookieName,
|
|
51
|
-
|
|
71
|
+
app,
|
|
72
|
+
routeRegistry,
|
|
73
|
+
defaultRedirect: resolvePostLoginPath(null),
|
|
52
74
|
|
|
53
75
|
async signup({ email, password, displayName }) {
|
|
54
76
|
const normalized = String(email || '').trim().toLowerCase();
|
|
@@ -91,7 +113,8 @@ export function createIdentityService(config) {
|
|
|
91
113
|
},
|
|
92
114
|
|
|
93
115
|
async sessionFromRequest(request) {
|
|
94
|
-
const sessionId =
|
|
116
|
+
const sessionId = parseBearerSessionId(request.headers.get('Authorization'))
|
|
117
|
+
|| parseSessionId(request.headers.get('Cookie'));
|
|
95
118
|
if (!sessionId) return null;
|
|
96
119
|
const session = await adapter.getSession(sessionId);
|
|
97
120
|
if (!session) return null;
|
|
@@ -101,7 +124,8 @@ export function createIdentityService(config) {
|
|
|
101
124
|
},
|
|
102
125
|
|
|
103
126
|
async logout(request) {
|
|
104
|
-
const sessionId =
|
|
127
|
+
const sessionId = parseBearerSessionId(request.headers.get('Authorization'))
|
|
128
|
+
|| parseSessionId(request.headers.get('Cookie'));
|
|
105
129
|
if (sessionId) await adapter.revokeSession(sessionId);
|
|
106
130
|
return { ok: true };
|
|
107
131
|
},
|
|
@@ -135,6 +159,28 @@ export function createIdentityService(config) {
|
|
|
135
159
|
return { ok: true, authUserId: user.id, sessionId: session.id, session };
|
|
136
160
|
},
|
|
137
161
|
|
|
162
|
+
isNativeSessionRequest(request) {
|
|
163
|
+
const marker = String(request?.headers?.get?.('X-AgentSam-Native-Client') || '').toLowerCase();
|
|
164
|
+
return marker === '1' || marker === 'true' || marker === 'native';
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
buildNativeLoginSuccessResponse(result, nextPath) {
|
|
168
|
+
const redirect = resolvePostLoginPath(nextPath);
|
|
169
|
+
return jsonResponse({
|
|
170
|
+
ok: true,
|
|
171
|
+
redirect,
|
|
172
|
+
session_id: result.sessionId,
|
|
173
|
+
expires_at: result.session?.expires_at ?? null,
|
|
174
|
+
user: result.user
|
|
175
|
+
? {
|
|
176
|
+
id: result.user.id,
|
|
177
|
+
email: result.user.email,
|
|
178
|
+
displayName: result.user.display_name ?? null,
|
|
179
|
+
}
|
|
180
|
+
: null,
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
|
|
138
184
|
buildLoginSuccessResponse(request, sessionId, nextPath) {
|
|
139
185
|
const redirect = resolvePostLoginPath(nextPath);
|
|
140
186
|
return jsonResponse(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mount-level auth policy helpers (host applies; identity does not invent mounts).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {{ path: string, auth?: 'required'|'optional'|'public', spa?: boolean, shell?: string }} AppMount
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export function pathMatchesMount(pathname, mount) {
|
|
10
|
+
const base = String(mount?.path || '');
|
|
11
|
+
if (!base) return false;
|
|
12
|
+
const path = String(pathname || '');
|
|
13
|
+
return path === base || path.startsWith(`${base}/`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveMountForPath(pathname, app) {
|
|
17
|
+
const mounts = Array.isArray(app?.routes?.mounts) ? app.routes.mounts : [];
|
|
18
|
+
let best = null;
|
|
19
|
+
for (const mount of mounts) {
|
|
20
|
+
if (!pathMatchesMount(pathname, mount)) continue;
|
|
21
|
+
if (!best || String(mount.path).length > String(best.path).length) best = mount;
|
|
22
|
+
}
|
|
23
|
+
return best;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function mountRequiresAuth(pathname, app) {
|
|
27
|
+
const mount = resolveMountForPath(pathname, app);
|
|
28
|
+
if (!mount) return false;
|
|
29
|
+
return (mount.auth || 'public') === 'required';
|
|
30
|
+
}
|