@bevel-software/platform-core-backend 0.1.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/LICENSE +202 -0
- package/dist/assets.d.ts +5 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +23 -0
- package/dist/assets.js.map +1 -0
- package/dist/core/core-ports.d.ts +83 -0
- package/dist/core/core-ports.d.ts.map +1 -0
- package/dist/core/core-ports.js +12 -0
- package/dist/core/core-ports.js.map +1 -0
- package/dist/core/create-core-server.d.ts +62 -0
- package/dist/core/create-core-server.d.ts.map +1 -0
- package/dist/core/create-core-server.js +204 -0
- package/dist/core/create-core-server.js.map +1 -0
- package/dist/core/create-core-services.d.ts +95 -0
- package/dist/core/create-core-services.d.ts.map +1 -0
- package/dist/core/create-core-services.js +352 -0
- package/dist/core/create-core-services.js.map +1 -0
- package/dist/core-config.d.ts +119 -0
- package/dist/core-config.d.ts.map +1 -0
- package/dist/core-config.js +240 -0
- package/dist/core-config.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/access/access-control.interface.d.ts +348 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -0
- package/dist/modules/access/access-control.interface.js +2 -0
- package/dist/modules/access/access-control.interface.js.map +1 -0
- package/dist/modules/access/access-control.service.d.ts +323 -0
- package/dist/modules/access/access-control.service.d.ts.map +1 -0
- package/dist/modules/access/access-control.service.js +1431 -0
- package/dist/modules/access/access-control.service.js.map +1 -0
- package/dist/modules/access/access-errors.d.ts +34 -0
- package/dist/modules/access/access-errors.d.ts.map +1 -0
- package/dist/modules/access/access-errors.js +40 -0
- package/dist/modules/access/access-errors.js.map +1 -0
- package/dist/modules/access/access-mutation.service.d.ts +176 -0
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -0
- package/dist/modules/access/access-mutation.service.js +307 -0
- package/dist/modules/access/access-mutation.service.js.map +1 -0
- package/dist/modules/access/access-splice.d.ts +98 -0
- package/dist/modules/access/access-splice.d.ts.map +1 -0
- package/dist/modules/access/access-splice.js +346 -0
- package/dist/modules/access/access-splice.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts +10 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -0
- package/dist/modules/access/access.routes.js +757 -0
- package/dist/modules/access/access.routes.js.map +1 -0
- package/dist/modules/access/creator-access.d.ts +113 -0
- package/dist/modules/access/creator-access.d.ts.map +1 -0
- package/dist/modules/access/creator-access.js +212 -0
- package/dist/modules/access/creator-access.js.map +1 -0
- package/dist/modules/access/kb-read-filter.d.ts +41 -0
- package/dist/modules/access/kb-read-filter.d.ts.map +1 -0
- package/dist/modules/access/kb-read-filter.js +60 -0
- package/dist/modules/access/kb-read-filter.js.map +1 -0
- package/dist/modules/access/roles-admin.service.d.ts +240 -0
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -0
- package/dist/modules/access/roles-admin.service.js +630 -0
- package/dist/modules/access/roles-admin.service.js.map +1 -0
- package/dist/modules/access/roles-edit.d.ts +91 -0
- package/dist/modules/access/roles-edit.d.ts.map +1 -0
- package/dist/modules/access/roles-edit.js +232 -0
- package/dist/modules/access/roles-edit.js.map +1 -0
- package/dist/modules/access/roles-yaml-guard.d.ts +56 -0
- package/dist/modules/access/roles-yaml-guard.d.ts.map +1 -0
- package/dist/modules/access/roles-yaml-guard.js +79 -0
- package/dist/modules/access/roles-yaml-guard.js.map +1 -0
- package/dist/modules/admin/admin-access.routes.d.ts +18 -0
- package/dist/modules/admin/admin-access.routes.d.ts.map +1 -0
- package/dist/modules/admin/admin-access.routes.js +26 -0
- package/dist/modules/admin/admin-access.routes.js.map +1 -0
- package/dist/modules/admin/admin-access.service.d.ts +24 -0
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -0
- package/dist/modules/admin/admin-access.service.js +41 -0
- package/dist/modules/admin/admin-access.service.js.map +1 -0
- package/dist/modules/admin/admin.interface.d.ts +11 -0
- package/dist/modules/admin/admin.interface.d.ts.map +1 -0
- package/dist/modules/admin/admin.interface.js +2 -0
- package/dist/modules/admin/admin.interface.js.map +1 -0
- package/dist/modules/auth/account-erasure.service.d.ts +80 -0
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -0
- package/dist/modules/auth/account-erasure.service.js +91 -0
- package/dist/modules/auth/account-erasure.service.js.map +1 -0
- package/dist/modules/auth/auth.middleware.d.ts +23 -0
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -0
- package/dist/modules/auth/auth.middleware.js +68 -0
- package/dist/modules/auth/auth.middleware.js.map +1 -0
- package/dist/modules/auth/auth.routes.d.ts +25 -0
- package/dist/modules/auth/auth.routes.d.ts.map +1 -0
- package/dist/modules/auth/auth.routes.js +72 -0
- package/dist/modules/auth/auth.routes.js.map +1 -0
- package/dist/modules/auth/auth.service.d.ts +76 -0
- package/dist/modules/auth/auth.service.d.ts.map +1 -0
- package/dist/modules/auth/auth.service.js +168 -0
- package/dist/modules/auth/auth.service.js.map +1 -0
- package/dist/modules/code-mode/code-mode-names.d.ts +16 -0
- package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -0
- package/dist/modules/code-mode/code-mode-names.js +30 -0
- package/dist/modules/code-mode/code-mode-names.js.map +1 -0
- package/dist/modules/code-mode/code-mode.tool.d.ts +13 -0
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -0
- package/dist/modules/code-mode/code-mode.tool.js +112 -0
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -0
- package/dist/modules/code-mode/index.d.ts +3 -0
- package/dist/modules/code-mode/index.d.ts.map +1 -0
- package/dist/modules/code-mode/index.js +3 -0
- package/dist/modules/code-mode/index.js.map +1 -0
- package/dist/modules/database/connection.d.ts +6 -0
- package/dist/modules/database/connection.d.ts.map +1 -0
- package/dist/modules/database/connection.js +12 -0
- package/dist/modules/database/connection.js.map +1 -0
- package/dist/modules/database/core-schema.d.ts +2273 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -0
- package/dist/modules/database/core-schema.js +413 -0
- package/dist/modules/database/core-schema.js.map +1 -0
- package/dist/modules/database/migrate.d.ts +10 -0
- package/dist/modules/database/migrate.d.ts.map +1 -0
- package/dist/modules/database/migrate.js +40 -0
- package/dist/modules/database/migrate.js.map +1 -0
- package/dist/modules/database/schema.d.ts +12 -0
- package/dist/modules/database/schema.d.ts.map +1 -0
- package/dist/modules/database/schema.js +12 -0
- package/dist/modules/database/schema.js.map +1 -0
- package/dist/modules/diff/diff-paths.d.ts +2 -0
- package/dist/modules/diff/diff-paths.d.ts.map +1 -0
- package/dist/modules/diff/diff-paths.js +9 -0
- package/dist/modules/diff/diff-paths.js.map +1 -0
- package/dist/modules/diff/diff.config.d.ts +8 -0
- package/dist/modules/diff/diff.config.d.ts.map +1 -0
- package/dist/modules/diff/diff.config.js +13 -0
- package/dist/modules/diff/diff.config.js.map +1 -0
- package/dist/modules/diff/diff.interface.d.ts +73 -0
- package/dist/modules/diff/diff.interface.d.ts.map +1 -0
- package/dist/modules/diff/diff.interface.js +2 -0
- package/dist/modules/diff/diff.interface.js.map +1 -0
- package/dist/modules/diff/diff.routes.d.ts +35 -0
- package/dist/modules/diff/diff.routes.d.ts.map +1 -0
- package/dist/modules/diff/diff.routes.js +228 -0
- package/dist/modules/diff/diff.routes.js.map +1 -0
- package/dist/modules/diff/diff.service.d.ts +51 -0
- package/dist/modules/diff/diff.service.d.ts.map +1 -0
- package/dist/modules/diff/diff.service.js +489 -0
- package/dist/modules/diff/diff.service.js.map +1 -0
- package/dist/modules/diff/line-diff.d.ts +16 -0
- package/dist/modules/diff/line-diff.d.ts.map +1 -0
- package/dist/modules/diff/line-diff.js +67 -0
- package/dist/modules/diff/line-diff.js.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +27 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.js +116 -0
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -0
- package/dist/modules/mcp/mcp-session-store.d.ts +74 -0
- package/dist/modules/mcp/mcp-session-store.d.ts.map +1 -0
- package/dist/modules/mcp/mcp-session-store.js +131 -0
- package/dist/modules/mcp/mcp-session-store.js.map +1 -0
- package/dist/modules/mcp/mcp.routes.d.ts +24 -0
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -0
- package/dist/modules/mcp/mcp.routes.js +229 -0
- package/dist/modules/mcp/mcp.routes.js.map +1 -0
- package/dist/modules/mcp/mcp.service.d.ts +198 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -0
- package/dist/modules/mcp/mcp.service.js +840 -0
- package/dist/modules/mcp/mcp.service.js.map +1 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +76 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +291 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +18 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +52 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -0
- package/dist/modules/mcp/oauth/oauth-state.d.ts +32 -0
- package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/oauth-state.js +34 -0
- package/dist/modules/mcp/oauth/oauth-state.js.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +92 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +728 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -0
- package/dist/modules/secrets-vault/index.d.ts +7 -0
- package/dist/modules/secrets-vault/index.d.ts.map +1 -0
- package/dist/modules/secrets-vault/index.js +6 -0
- package/dist/modules/secrets-vault/index.js.map +1 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +63 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +269 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +46 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.js +87 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +210 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js +90 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +30 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.js +490 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -0
- package/dist/modules/skills/index.d.ts +5 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +4 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/skills/skills.contract.d.ts +58 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -0
- package/dist/modules/skills/skills.contract.js +10 -0
- package/dist/modules/skills/skills.contract.js.map +1 -0
- package/dist/modules/skills/skills.routes.d.ts +15 -0
- package/dist/modules/skills/skills.routes.d.ts.map +1 -0
- package/dist/modules/skills/skills.routes.js +34 -0
- package/dist/modules/skills/skills.routes.js.map +1 -0
- package/dist/modules/skills/skills.service.d.ts +21 -0
- package/dist/modules/skills/skills.service.d.ts.map +1 -0
- package/dist/modules/skills/skills.service.js +202 -0
- package/dist/modules/skills/skills.service.js.map +1 -0
- package/dist/modules/skills/skills.tools.d.ts +15 -0
- package/dist/modules/skills/skills.tools.d.ts.map +1 -0
- package/dist/modules/skills/skills.tools.js +96 -0
- package/dist/modules/skills/skills.tools.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.errors.d.ts +14 -0
- package/dist/modules/tool-auth/external-api-key.errors.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.errors.js +23 -0
- package/dist/modules/tool-auth/external-api-key.errors.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +90 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.js +2 -0
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts +25 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.service.js +164 -0
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts +62 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -0
- package/dist/modules/tool-auth/internal-token.service.js +85 -0
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -0
- package/dist/modules/tool-auth/llm-usage-meter.d.ts +16 -0
- package/dist/modules/tool-auth/llm-usage-meter.d.ts.map +1 -0
- package/dist/modules/tool-auth/llm-usage-meter.js +6 -0
- package/dist/modules/tool-auth/llm-usage-meter.js.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +101 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.js +166 -0
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -0
- package/dist/modules/tool-helpers/index.d.ts +19 -0
- package/dist/modules/tool-helpers/index.d.ts.map +1 -0
- package/dist/modules/tool-helpers/index.js +18 -0
- package/dist/modules/tool-helpers/index.js.map +1 -0
- package/dist/modules/tool-helpers/tool-context.d.ts +35 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-context.js +66 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -0
- package/dist/modules/tool-helpers/tool-def.d.ts +33 -0
- package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-def.js +57 -0
- package/dist/modules/tool-helpers/tool-def.js.map +1 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts +19 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-handler.js +84 -0
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts +64 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool.contract.js +24 -0
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -0
- package/dist/modules/tool-helpers/validate-token.d.ts +31 -0
- package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -0
- package/dist/modules/tool-helpers/validate-token.js +20 -0
- package/dist/modules/tool-helpers/validate-token.js.map +1 -0
- package/dist/modules/tool-manuals/index.d.ts +5 -0
- package/dist/modules/tool-manuals/index.d.ts.map +1 -0
- package/dist/modules/tool-manuals/index.js +5 -0
- package/dist/modules/tool-manuals/index.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +182 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js +19 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +24 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.js +102 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +108 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js +710 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +35 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.js +157 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -0
- package/dist/modules/tool-registry/manual.routes.d.ts +6 -0
- package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -0
- package/dist/modules/tool-registry/manual.routes.js +76 -0
- package/dist/modules/tool-registry/manual.routes.js.map +1 -0
- package/dist/modules/tool-registry/tool-registry.d.ts +23 -0
- package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -0
- package/dist/modules/tool-registry/tool-registry.js +46 -0
- package/dist/modules/tool-registry/tool-registry.js.map +1 -0
- package/dist/modules/tool-registry/tool.contract.d.ts +48 -0
- package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -0
- package/dist/modules/tool-registry/tool.contract.js +2 -0
- package/dist/modules/tool-registry/tool.contract.js.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +14 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.js +437 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -0
- package/dist/modules/workflow/event-bus.d.ts +107 -0
- package/dist/modules/workflow/event-bus.d.ts.map +1 -0
- package/dist/modules/workflow/event-bus.js +224 -0
- package/dist/modules/workflow/event-bus.js.map +1 -0
- package/dist/modules/workflow/events.routes.d.ts +80 -0
- package/dist/modules/workflow/events.routes.d.ts.map +1 -0
- package/dist/modules/workflow/events.routes.js +216 -0
- package/dist/modules/workflow/events.routes.js.map +1 -0
- package/dist/modules/workflow/file-change-notifier.d.ts +38 -0
- package/dist/modules/workflow/file-change-notifier.d.ts.map +1 -0
- package/dist/modules/workflow/file-change-notifier.js +22 -0
- package/dist/modules/workflow/file-change-notifier.js.map +1 -0
- package/dist/modules/workflow/file-lock.service.d.ts +57 -0
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -0
- package/dist/modules/workflow/file-lock.service.js +202 -0
- package/dist/modules/workflow/file-lock.service.js.map +1 -0
- package/dist/modules/workflow/git/branch-name.d.ts +10 -0
- package/dist/modules/workflow/git/branch-name.d.ts.map +1 -0
- package/dist/modules/workflow/git/branch-name.js +76 -0
- package/dist/modules/workflow/git/branch-name.js.map +1 -0
- package/dist/modules/workflow/git/clone-config.d.ts +61 -0
- package/dist/modules/workflow/git/clone-config.d.ts.map +1 -0
- package/dist/modules/workflow/git/clone-config.js +69 -0
- package/dist/modules/workflow/git/clone-config.js.map +1 -0
- package/dist/modules/workflow/git/git-version.d.ts +34 -0
- package/dist/modules/workflow/git/git-version.d.ts.map +1 -0
- package/dist/modules/workflow/git/git-version.js +63 -0
- package/dist/modules/workflow/git/git-version.js.map +1 -0
- package/dist/modules/workflow/git/git.service.d.ts +427 -0
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -0
- package/dist/modules/workflow/git/git.service.js +1987 -0
- package/dist/modules/workflow/git/git.service.js.map +1 -0
- package/dist/modules/workflow/git/mutex.d.ts +11 -0
- package/dist/modules/workflow/git/mutex.d.ts.map +1 -0
- package/dist/modules/workflow/git/mutex.js +23 -0
- package/dist/modules/workflow/git/mutex.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +124 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.js +328 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -0
- package/dist/modules/workflow/locking-filesystem.d.ts +133 -0
- package/dist/modules/workflow/locking-filesystem.d.ts.map +1 -0
- package/dist/modules/workflow/locking-filesystem.js +400 -0
- package/dist/modules/workflow/locking-filesystem.js.map +1 -0
- package/dist/modules/workflow/pending-commits.service.d.ts +221 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -0
- package/dist/modules/workflow/pending-commits.service.js +364 -0
- package/dist/modules/workflow/pending-commits.service.js.map +1 -0
- package/dist/modules/workflow/pending-commits.worker.d.ts +148 -0
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -0
- package/dist/modules/workflow/pending-commits.worker.js +245 -0
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -0
- package/dist/modules/workflow/read-only-filesystem.d.ts +24 -0
- package/dist/modules/workflow/read-only-filesystem.d.ts.map +1 -0
- package/dist/modules/workflow/read-only-filesystem.js +39 -0
- package/dist/modules/workflow/read-only-filesystem.js.map +1 -0
- package/dist/modules/workflow/recovery-bot.d.ts +31 -0
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -0
- package/dist/modules/workflow/recovery-bot.js +64 -0
- package/dist/modules/workflow/recovery-bot.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +137 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.js +2 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +26 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +636 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -0
- package/dist/modules/workflow/sanitize-error.d.ts +29 -0
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -0
- package/dist/modules/workflow/sanitize-error.js +60 -0
- package/dist/modules/workflow/sanitize-error.js.map +1 -0
- package/dist/modules/workflow/session-ontology.policy.d.ts +52 -0
- package/dist/modules/workflow/session-ontology.policy.d.ts.map +1 -0
- package/dist/modules/workflow/session-ontology.policy.js +62 -0
- package/dist/modules/workflow/session-ontology.policy.js.map +1 -0
- package/dist/modules/workflow/session-ontology.service.d.ts +100 -0
- package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -0
- package/dist/modules/workflow/session-ontology.service.js +143 -0
- package/dist/modules/workflow/session-ontology.service.js.map +1 -0
- package/dist/modules/workflow/workflow-hooks.d.ts +87 -0
- package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -0
- package/dist/modules/workflow/workflow-hooks.js +35 -0
- package/dist/modules/workflow/workflow-hooks.js.map +1 -0
- package/dist/modules/workflow/workflow.errors.d.ts +171 -0
- package/dist/modules/workflow/workflow.errors.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.errors.js +260 -0
- package/dist/modules/workflow/workflow.errors.js.map +1 -0
- package/dist/modules/workflow/workflow.routes.d.ts +26 -0
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.routes.js +804 -0
- package/dist/modules/workflow/workflow.routes.js.map +1 -0
- package/dist/modules/workflow/workflow.service.d.ts +385 -0
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.service.js +1155 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -0
- package/dist/modules/workspace/bevel-ignore.d.ts +25 -0
- package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -0
- package/dist/modules/workspace/bevel-ignore.js +57 -0
- package/dist/modules/workspace/bevel-ignore.js.map +1 -0
- package/dist/modules/workspace/kb-seed.interface.d.ts +36 -0
- package/dist/modules/workspace/kb-seed.interface.d.ts.map +1 -0
- package/dist/modules/workspace/kb-seed.interface.js +2 -0
- package/dist/modules/workspace/kb-seed.interface.js.map +1 -0
- package/dist/modules/workspace/kb-seed.service.d.ts +70 -0
- package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -0
- package/dist/modules/workspace/kb-seed.service.js +325 -0
- package/dist/modules/workspace/kb-seed.service.js.map +1 -0
- package/dist/modules/workspace/routine-write-policy.d.ts +49 -0
- package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -0
- package/dist/modules/workspace/routine-write-policy.js +46 -0
- package/dist/modules/workspace/routine-write-policy.js.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts +112 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.js +161 -0
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -0
- package/dist/modules/workspace/session-sink.d.ts +25 -0
- package/dist/modules/workspace/session-sink.d.ts.map +1 -0
- package/dist/modules/workspace/session-sink.js +8 -0
- package/dist/modules/workspace/session-sink.js.map +1 -0
- package/dist/modules/workspace/spill-store.d.ts +24 -0
- package/dist/modules/workspace/spill-store.d.ts.map +1 -0
- package/dist/modules/workspace/spill-store.js +87 -0
- package/dist/modules/workspace/spill-store.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts +25 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.routes.js +1046 -0
- package/dist/modules/workspace/workspace.routes.js.map +1 -0
- package/dist/modules/workspace/workspace.service.d.ts +339 -0
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.service.js +1221 -0
- package/dist/modules/workspace/workspace.service.js.map +1 -0
- package/dist/modules/workspace/workspace.tools.d.ts +19 -0
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.tools.js +767 -0
- package/dist/modules/workspace/workspace.tools.js.map +1 -0
- package/dist/shared/frontmatter-id.d.ts +35 -0
- package/dist/shared/frontmatter-id.d.ts.map +1 -0
- package/dist/shared/frontmatter-id.js +68 -0
- package/dist/shared/frontmatter-id.js.map +1 -0
- package/dist/shared/fs-walk.d.ts +9 -0
- package/dist/shared/fs-walk.d.ts.map +1 -0
- package/dist/shared/fs-walk.js +34 -0
- package/dist/shared/fs-walk.js.map +1 -0
- package/dist/shared/hash-email.d.ts +11 -0
- package/dist/shared/hash-email.d.ts.map +1 -0
- package/dist/shared/hash-email.js +14 -0
- package/dist/shared/hash-email.js.map +1 -0
- package/dist/shared/kb-layout.d.ts +38 -0
- package/dist/shared/kb-layout.d.ts.map +1 -0
- package/dist/shared/kb-layout.js +102 -0
- package/dist/shared/kb-layout.js.map +1 -0
- package/dist/shared/kb-layout.test.d.ts +2 -0
- package/dist/shared/kb-layout.test.d.ts.map +1 -0
- package/dist/shared/kb-layout.test.js +67 -0
- package/dist/shared/kb-layout.test.js.map +1 -0
- package/dist/shared/ssrf.d.ts +20 -0
- package/dist/shared/ssrf.d.ts.map +1 -0
- package/dist/shared/ssrf.js +89 -0
- package/dist/shared/ssrf.js.map +1 -0
- package/dist/shared/token-crypto.d.ts +16 -0
- package/dist/shared/token-crypto.d.ts.map +1 -0
- package/dist/shared/token-crypto.js +49 -0
- package/dist/shared/token-crypto.js.map +1 -0
- package/dist/shared/ttl-cache.d.ts +16 -0
- package/dist/shared/ttl-cache.d.ts.map +1 -0
- package/dist/shared/ttl-cache.js +27 -0
- package/dist/shared/ttl-cache.js.map +1 -0
- package/dist/shared/utcp-namespace.d.ts +46 -0
- package/dist/shared/utcp-namespace.d.ts.map +1 -0
- package/dist/shared/utcp-namespace.js +82 -0
- package/dist/shared/utcp-namespace.js.map +1 -0
- package/dist/version.d.ts +17 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/kb-template/.bevelignore +21 -0
- package/kb-template/Agents/.gitkeep +0 -0
- package/kb-template/Agents/README.md +38 -0
- package/kb-template/CLAUDE.md +419 -0
- package/kb-template/Data/.gitkeep +0 -0
- package/kb-template/Data/README.md +39 -0
- package/kb-template/KnowledgeBase/.gitkeep +0 -0
- package/kb-template/KnowledgeBase/README.md +37 -0
- package/kb-template/Pipelines/.gitkeep +0 -0
- package/kb-template/Pipelines/README.md +38 -0
- package/kb-template/Skills/.gitkeep +0 -0
- package/kb-template/Skills/README.md +32 -0
- package/kb-template/Tools/.gitkeep +0 -0
- package/kb-template/Tools/README.md +42 -0
- package/kb-template/access.md +36 -0
- package/migrations/0000_core_init.sql +243 -0
- package/migrations/meta/0000_snapshot.json +1480 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +80 -0
- package/src/assets.ts +25 -0
- package/src/core/core-ports.ts +91 -0
- package/src/core/create-core-server.ts +338 -0
- package/src/core/create-core-services.ts +501 -0
- package/src/core-config.ts +257 -0
- package/src/index.ts +69 -0
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -0
- package/src/modules/access/__tests__/access-control.read-batch.test.ts +132 -0
- package/src/modules/access/__tests__/access-control.service.test.ts +1011 -0
- package/src/modules/access/__tests__/access-mutation.service.test.ts +439 -0
- package/src/modules/access/__tests__/access-splice.test.ts +247 -0
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +407 -0
- package/src/modules/access/__tests__/creator-access.test.ts +217 -0
- package/src/modules/access/__tests__/grant-sources.test.ts +204 -0
- package/src/modules/access/__tests__/kb-read-filter.test.ts +70 -0
- package/src/modules/access/__tests__/roles-admin.service.test.ts +469 -0
- package/src/modules/access/__tests__/roles-edit.test.ts +138 -0
- package/src/modules/access/__tests__/roles-yaml-guard.test.ts +70 -0
- package/src/modules/access/__tests__/roles.routes.test.ts +234 -0
- package/src/modules/access/access-control.interface.ts +383 -0
- package/src/modules/access/access-control.service.ts +1794 -0
- package/src/modules/access/access-errors.ts +60 -0
- package/src/modules/access/access-mutation.service.ts +369 -0
- package/src/modules/access/access-splice.ts +413 -0
- package/src/modules/access/access.routes.ts +894 -0
- package/src/modules/access/creator-access.ts +270 -0
- package/src/modules/access/kb-read-filter.ts +76 -0
- package/src/modules/access/roles-admin.service.ts +741 -0
- package/src/modules/access/roles-edit.ts +248 -0
- package/src/modules/access/roles-yaml-guard.ts +89 -0
- package/src/modules/admin/admin-access.routes.ts +29 -0
- package/src/modules/admin/admin-access.service.ts +38 -0
- package/src/modules/admin/admin.interface.ts +10 -0
- package/src/modules/auth/account-erasure.service.ts +183 -0
- package/src/modules/auth/auth.middleware.ts +78 -0
- package/src/modules/auth/auth.routes.ts +97 -0
- package/src/modules/auth/auth.service.ts +199 -0
- package/src/modules/code-mode/code-mode-names.ts +38 -0
- package/src/modules/code-mode/code-mode.tool.ts +117 -0
- package/src/modules/code-mode/index.ts +6 -0
- package/src/modules/database/connection.ts +15 -0
- package/src/modules/database/core-schema.ts +431 -0
- package/src/modules/database/migrate.ts +43 -0
- package/src/modules/database/schema.ts +11 -0
- package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +87 -0
- package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -0
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +184 -0
- package/src/modules/diff/__tests__/diff.service.test.ts +202 -0
- package/src/modules/diff/diff-paths.ts +9 -0
- package/src/modules/diff/diff.config.ts +12 -0
- package/src/modules/diff/diff.interface.ts +78 -0
- package/src/modules/diff/diff.routes.ts +277 -0
- package/src/modules/diff/diff.service.ts +508 -0
- package/src/modules/diff/line-diff.ts +79 -0
- package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +287 -0
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +249 -0
- package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +253 -0
- package/src/modules/mcp/__tests__/mcp-session-store.test.ts +151 -0
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +150 -0
- package/src/modules/mcp/__tests__/mcp.routes.delete.test.ts +92 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +414 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +126 -0
- package/src/modules/mcp/mcp-session-store.ts +162 -0
- package/src/modules/mcp/mcp.routes.ts +263 -0
- package/src/modules/mcp/mcp.service.ts +973 -0
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +401 -0
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +60 -0
- package/src/modules/mcp/oauth/oauth-state.ts +61 -0
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +277 -0
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +206 -0
- package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +178 -0
- package/src/modules/secrets-vault/__tests__/scopes-covered.test.ts +101 -0
- package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +54 -0
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +792 -0
- package/src/modules/secrets-vault/index.ts +25 -0
- package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +289 -0
- package/src/modules/secrets-vault/secrets-variable-loader.ts +104 -0
- package/src/modules/secrets-vault/secrets-vault.contract.ts +270 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +526 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +176 -0
- package/src/modules/skills/index.ts +10 -0
- package/src/modules/skills/skills.contract.ts +54 -0
- package/src/modules/skills/skills.routes.ts +38 -0
- package/src/modules/skills/skills.service.ts +245 -0
- package/src/modules/skills/skills.tools.ts +121 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +358 -0
- package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +79 -0
- package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +88 -0
- package/src/modules/tool-auth/external-api-key.errors.ts +25 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +99 -0
- package/src/modules/tool-auth/external-api-key.service.ts +209 -0
- package/src/modules/tool-auth/internal-token.service.ts +124 -0
- package/src/modules/tool-auth/llm-usage-meter.ts +19 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +220 -0
- package/src/modules/tool-helpers/__tests__/phase0-loopback-spike.test.ts +129 -0
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +95 -0
- package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +146 -0
- package/src/modules/tool-helpers/__tests__/validate-token.test.ts +75 -0
- package/src/modules/tool-helpers/index.ts +18 -0
- package/src/modules/tool-helpers/tool-context.ts +98 -0
- package/src/modules/tool-helpers/tool-def.ts +73 -0
- package/src/modules/tool-helpers/tool-handler.ts +91 -0
- package/src/modules/tool-helpers/tool.contract.ts +85 -0
- package/src/modules/tool-helpers/validate-token.ts +50 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +200 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +499 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -0
- package/src/modules/tool-manuals/index.ts +12 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +183 -0
- package/src/modules/tool-manuals/tool-manuals.routes.ts +110 -0
- package/src/modules/tool-manuals/tool-manuals.service.ts +781 -0
- package/src/modules/tool-manuals/tool-manuals.tools.ts +202 -0
- package/src/modules/tool-registry/__tests__/tool-registry.test.ts +64 -0
- package/src/modules/tool-registry/manual.routes.ts +87 -0
- package/src/modules/tool-registry/tool-registry.ts +55 -0
- package/src/modules/tool-registry/tool.contract.ts +52 -0
- package/src/modules/workflow/__tests__/event-bus.test.ts +322 -0
- package/src/modules/workflow/__tests__/file-change-notifier.test.ts +51 -0
- package/src/modules/workflow/__tests__/format-affected-owners.test.ts +67 -0
- package/src/modules/workflow/__tests__/locking-filesystem.test.ts +445 -0
- package/src/modules/workflow/__tests__/pending-commits.canonical.test.ts +36 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +243 -0
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +308 -0
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +67 -0
- package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +62 -0
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +200 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +232 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +380 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +340 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +192 -0
- package/src/modules/workflow/agent-tools/workflow.tools.ts +502 -0
- package/src/modules/workflow/event-bus.ts +262 -0
- package/src/modules/workflow/events.routes.ts +266 -0
- package/src/modules/workflow/file-change-notifier.ts +54 -0
- package/src/modules/workflow/file-lock.service.ts +269 -0
- package/src/modules/workflow/git/__tests__/branch-name.test.ts +86 -0
- package/src/modules/workflow/git/__tests__/branchAuthor.test.ts +80 -0
- package/src/modules/workflow/git/__tests__/clone-config.test.ts +15 -0
- package/src/modules/workflow/git/__tests__/git-test-helpers.ts +47 -0
- package/src/modules/workflow/git/__tests__/git-version.failure.test.ts +24 -0
- package/src/modules/workflow/git/__tests__/git-version.test.ts +49 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +389 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
- package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +105 -0
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +211 -0
- package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +154 -0
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +320 -0
- package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +202 -0
- package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +453 -0
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +198 -0
- package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +125 -0
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +219 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +145 -0
- package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +240 -0
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +272 -0
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +232 -0
- package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +101 -0
- package/src/modules/workflow/git/__tests__/git.service.status.test.ts +127 -0
- package/src/modules/workflow/git/__tests__/mutex.test.ts +78 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +225 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +101 -0
- package/src/modules/workflow/git/branch-name.ts +70 -0
- package/src/modules/workflow/git/clone-config.ts +71 -0
- package/src/modules/workflow/git/git-version.ts +70 -0
- package/src/modules/workflow/git/git.service.ts +2248 -0
- package/src/modules/workflow/git/mutex.ts +22 -0
- package/src/modules/workflow/git/pull-request.service.ts +447 -0
- package/src/modules/workflow/locking-filesystem.ts +489 -0
- package/src/modules/workflow/pending-commits.service.ts +444 -0
- package/src/modules/workflow/pending-commits.worker.ts +361 -0
- package/src/modules/workflow/read-only-filesystem.ts +54 -0
- package/src/modules/workflow/recovery-bot.ts +73 -0
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +560 -0
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +176 -0
- package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +258 -0
- package/src/modules/workflow/review-workflow/review-workflow.interface.ts +199 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +806 -0
- package/src/modules/workflow/sanitize-error.ts +62 -0
- package/src/modules/workflow/session-ontology.policy.ts +70 -0
- package/src/modules/workflow/session-ontology.service.ts +178 -0
- package/src/modules/workflow/workflow-hooks.ts +101 -0
- package/src/modules/workflow/workflow.errors.ts +285 -0
- package/src/modules/workflow/workflow.routes.ts +858 -0
- package/src/modules/workflow/workflow.service.ts +1555 -0
- package/src/modules/workspace/__tests__/kb-seed.service.test.ts +213 -0
- package/src/modules/workspace/__tests__/routine-write-policy.test.ts +68 -0
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -0
- package/src/modules/workspace/__tests__/spill-store.test.ts +43 -0
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +233 -0
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +176 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +303 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +276 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +120 -0
- package/src/modules/workspace/__tests__/workspace.service.test.ts +565 -0
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +504 -0
- package/src/modules/workspace/bevel-ignore.ts +62 -0
- package/src/modules/workspace/kb-seed.interface.ts +36 -0
- package/src/modules/workspace/kb-seed.service.ts +361 -0
- package/src/modules/workspace/routine-write-policy.ts +79 -0
- package/src/modules/workspace/session-ontology.gate.ts +189 -0
- package/src/modules/workspace/session-sink.ts +25 -0
- package/src/modules/workspace/spill-store.ts +87 -0
- package/src/modules/workspace/workspace.routes.ts +1114 -0
- package/src/modules/workspace/workspace.service.ts +1343 -0
- package/src/modules/workspace/workspace.tools.ts +885 -0
- package/src/shared/__tests__/frontmatter-id.test.ts +88 -0
- package/src/shared/__tests__/fs-walk.test.ts +42 -0
- package/src/shared/__tests__/ssrf.test.ts +53 -0
- package/src/shared/__tests__/utcp-namespace.test.ts +19 -0
- package/src/shared/frontmatter-id.ts +72 -0
- package/src/shared/fs-walk.ts +30 -0
- package/src/shared/hash-email.ts +14 -0
- package/src/shared/kb-layout.test.ts +88 -0
- package/src/shared/kb-layout.ts +101 -0
- package/src/shared/ssrf.ts +78 -0
- package/src/shared/token-crypto.ts +54 -0
- package/src/shared/ttl-cache.ts +27 -0
- package/src/shared/utcp-namespace.ts +88 -0
- package/src/version.ts +19 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Database } from '../database/connection.js';
|
|
2
|
+
/** A user row as the admin surface needs it (no avatar, no timestamps churn). */
|
|
3
|
+
export interface AdminUserView {
|
|
4
|
+
id: string;
|
|
5
|
+
email: string;
|
|
6
|
+
name: string;
|
|
7
|
+
createdAt: number;
|
|
8
|
+
}
|
|
9
|
+
/** The drizzle client erasure participants receive inside the transaction. */
|
|
10
|
+
export type ErasureTx = Parameters<Parameters<Database['transaction']>[0]>[0];
|
|
11
|
+
/** Identity context for one erasure run. */
|
|
12
|
+
export interface ErasureTarget {
|
|
13
|
+
userId: string;
|
|
14
|
+
/** The user's (lowercased) email at erasure time — for email-keyed rows. */
|
|
15
|
+
email: string;
|
|
16
|
+
/**
|
|
17
|
+
* Per-erasure placeholder identity for anonymized audit rows. Random per
|
|
18
|
+
* erasure: no link back to the person, but rows from ONE erasure stay
|
|
19
|
+
* correlated and email-keyed unique indexes can't collide across erasures.
|
|
20
|
+
*/
|
|
21
|
+
erasedEmail: string;
|
|
22
|
+
erasedName: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A module-owned slice of account erasure. The core service erases the rows
|
|
26
|
+
* it owns (tokens, locks, review-trail anonymization, the user row) and runs
|
|
27
|
+
* every registered participant so each module cleans up its own tables —
|
|
28
|
+
* chat threads, connector links, routine authorship, … — without the auth
|
|
29
|
+
* module knowing they exist. Registered at the composition root.
|
|
30
|
+
*
|
|
31
|
+
* - `before` runs OUTSIDE the transaction, first. For idempotent pre-cleanup
|
|
32
|
+
* against external stores (e.g. chat-thread message memory) where a failure
|
|
33
|
+
* must leave a retryable state, not a half-committed one.
|
|
34
|
+
* - `inTransaction` runs INSIDE the erasure transaction, BEFORE the users row
|
|
35
|
+
* is deleted (so FKs onto users are still satisfiable and RESTRICT FKs make
|
|
36
|
+
* missed rows fail loudly). It may return a callback, which runs after the
|
|
37
|
+
* transaction commits — for external-store cleanup of rows captured during
|
|
38
|
+
* the transaction.
|
|
39
|
+
*/
|
|
40
|
+
export interface IErasureParticipant {
|
|
41
|
+
before?(target: ErasureTarget): Promise<void>;
|
|
42
|
+
inTransaction?(tx: ErasureTx, target: ErasureTarget): Promise<void | (() => Promise<void>)>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* GDPR account erasure (Art. 17). Operator-driven: an admin deletes a user in
|
|
46
|
+
* response to an erasure request. What it guarantees:
|
|
47
|
+
*
|
|
48
|
+
* - Rows that ARE the user's personal data are hard-deleted: API/OAuth
|
|
49
|
+
* tokens, held file locks, the user row itself, and every registered
|
|
50
|
+
* participant's module-owned rows (chat threads incl. message memory,
|
|
51
|
+
* Microsoft connection, feedback, revalidation requests, upload tokens).
|
|
52
|
+
* Deleting the user row cascades whatever FKs onto it with ON DELETE
|
|
53
|
+
* CASCADE (account links, watchlist sources/findings, connector configs,
|
|
54
|
+
* vault secrets); deleting a connection key cascades its usage metering.
|
|
55
|
+
* - Audit rows that must survive for the review trail (approvals, merge log,
|
|
56
|
+
* review comments, change requests, queued commits — and, via participants,
|
|
57
|
+
* e.g. routine authorship) are kept but ANONYMIZED with the per-erasure
|
|
58
|
+
* placeholder identity.
|
|
59
|
+
*
|
|
60
|
+
* Out of scope, by firm policy (disclosed in the DPA): git history is never
|
|
61
|
+
* rewritten. Commit authorship and historical access-file entries stay in the
|
|
62
|
+
* KB's version history permanently as part of the tamper-evident record;
|
|
63
|
+
* erasure covers every database/filesystem store plus the CURRENT KB state.
|
|
64
|
+
*
|
|
65
|
+
* Note: sign-in is get-or-create by email, so a person who authenticates again
|
|
66
|
+
* after erasure simply gets a fresh, empty account — that is intended.
|
|
67
|
+
*/
|
|
68
|
+
export interface IAccountErasureService {
|
|
69
|
+
listUsers(): Promise<AdminUserView[]>;
|
|
70
|
+
/** Erase `userId`. Returns false when no such user exists. */
|
|
71
|
+
eraseUser(userId: string): Promise<boolean>;
|
|
72
|
+
}
|
|
73
|
+
export declare class AccountErasureService implements IAccountErasureService {
|
|
74
|
+
private readonly db;
|
|
75
|
+
private readonly participants;
|
|
76
|
+
constructor(db: Database, participants?: IErasureParticipant[]);
|
|
77
|
+
listUsers(): Promise<AdminUserView[]>;
|
|
78
|
+
eraseUser(userId: string): Promise<boolean>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=account-erasure.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-erasure.service.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/account-erasure.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAc1D,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,aAAa,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CAC7F;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACtC,8DAA8D;IAC9D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAED,qBAAa,qBAAsB,YAAW,sBAAsB;IAEhE,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,EAAE,EAAE,QAAQ,EACZ,YAAY,GAAE,mBAAmB,EAAO;IAGrD,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAQrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA4ElD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { eq } from 'drizzle-orm';
|
|
3
|
+
import { changeRequests, externalApiKeys, fileLocks, oauthAuthCodes, oauthTokens, pendingCommits, prComments, prFileApprovals, prMergeLog, users, } from '../database/schema.js';
|
|
4
|
+
export class AccountErasureService {
|
|
5
|
+
db;
|
|
6
|
+
participants;
|
|
7
|
+
constructor(db, participants = []) {
|
|
8
|
+
this.db = db;
|
|
9
|
+
this.participants = participants;
|
|
10
|
+
}
|
|
11
|
+
async listUsers() {
|
|
12
|
+
const rows = await this.db
|
|
13
|
+
.select({ id: users.id, email: users.email, name: users.name, createdAt: users.createdAt })
|
|
14
|
+
.from(users)
|
|
15
|
+
.orderBy(users.email);
|
|
16
|
+
return rows.map((r) => ({ ...r, createdAt: r.createdAt.getTime() }));
|
|
17
|
+
}
|
|
18
|
+
async eraseUser(userId) {
|
|
19
|
+
const [user] = await this.db.select().from(users).where(eq(users.id, userId)).limit(1);
|
|
20
|
+
if (!user)
|
|
21
|
+
return false;
|
|
22
|
+
const target = {
|
|
23
|
+
userId,
|
|
24
|
+
email: user.email.toLowerCase(),
|
|
25
|
+
erasedEmail: `deleted-${randomUUID()}@erased.invalid`,
|
|
26
|
+
erasedName: 'Deleted user',
|
|
27
|
+
};
|
|
28
|
+
// Participant pre-passes (e.g. chat threads + their Mastra memory) run
|
|
29
|
+
// outside the transaction on purpose: external stores are separate
|
|
30
|
+
// systems, and the pre-passes are idempotent, so a failure here leaves a
|
|
31
|
+
// retryable state rather than a half-committed one.
|
|
32
|
+
for (const p of this.participants) {
|
|
33
|
+
if (p.before)
|
|
34
|
+
await p.before(target);
|
|
35
|
+
}
|
|
36
|
+
const postCommit = [];
|
|
37
|
+
await this.db.transaction(async (tx) => {
|
|
38
|
+
// Token-shaped rows (all hashed, but they key to the user). Dependents
|
|
39
|
+
// like the LLM-usage metering rows cascade at the DB layer.
|
|
40
|
+
await tx.delete(externalApiKeys).where(eq(externalApiKeys.userId, userId));
|
|
41
|
+
await tx.delete(oauthAuthCodes).where(eq(oauthAuthCodes.userId, userId));
|
|
42
|
+
await tx.delete(oauthTokens).where(eq(oauthTokens.userId, userId));
|
|
43
|
+
// Personal-data rows the core owns.
|
|
44
|
+
await tx.delete(fileLocks).where(eq(fileLocks.holderUserId, userId));
|
|
45
|
+
// Audit rows: anonymize in place (no user FK on these; they key by email).
|
|
46
|
+
await tx
|
|
47
|
+
.update(prFileApprovals)
|
|
48
|
+
.set({ approverEmail: target.erasedEmail, approverName: target.erasedName })
|
|
49
|
+
.where(eq(prFileApprovals.approverEmail, target.email));
|
|
50
|
+
await tx
|
|
51
|
+
.update(prMergeLog)
|
|
52
|
+
.set({ triggeredByEmail: target.erasedEmail, triggeredByName: target.erasedName })
|
|
53
|
+
.where(eq(prMergeLog.triggeredByEmail, target.email));
|
|
54
|
+
await tx
|
|
55
|
+
.update(prComments)
|
|
56
|
+
.set({ authorEmail: target.erasedEmail, authorName: target.erasedName })
|
|
57
|
+
.where(eq(prComments.authorEmail, target.email));
|
|
58
|
+
await tx
|
|
59
|
+
.update(changeRequests)
|
|
60
|
+
.set({ authorEmail: target.erasedEmail, authorName: target.erasedName })
|
|
61
|
+
.where(eq(changeRequests.authorEmail, target.email));
|
|
62
|
+
// Queued-but-uncommitted saves: the eventual git commit is authored with
|
|
63
|
+
// the placeholder instead of the erased identity. The file content still
|
|
64
|
+
// lands — erasing an account must not lose other people's KB state.
|
|
65
|
+
await tx
|
|
66
|
+
.update(pendingCommits)
|
|
67
|
+
.set({ authorEmail: target.erasedEmail, authorName: target.erasedName })
|
|
68
|
+
.where(eq(pendingCommits.authorEmail, target.email));
|
|
69
|
+
// Module-owned rows, before the users delete so FKs onto users are
|
|
70
|
+
// still satisfiable — and so a participant that MISSES rows makes the
|
|
71
|
+
// users delete below fail on its RESTRICT FK, rolling everything back:
|
|
72
|
+
// a loud retry, never a silent orphan.
|
|
73
|
+
for (const p of this.participants) {
|
|
74
|
+
if (!p.inTransaction)
|
|
75
|
+
continue;
|
|
76
|
+
const cb = await p.inTransaction(tx, target);
|
|
77
|
+
if (cb)
|
|
78
|
+
postCommit.push(cb);
|
|
79
|
+
}
|
|
80
|
+
// Finally the user row (plus its ON DELETE CASCADE dependents).
|
|
81
|
+
await tx.delete(users).where(eq(users.id, userId));
|
|
82
|
+
});
|
|
83
|
+
// Post-commit callbacks (e.g. Mastra memory cleanup for chat threads
|
|
84
|
+
// captured inside the transaction).
|
|
85
|
+
for (const cb of postCommit)
|
|
86
|
+
await cb();
|
|
87
|
+
console.log(`[account-erasure] erased user id=${userId}`);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=account-erasure.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-erasure.service.js","sourceRoot":"","sources":["../../../src/modules/auth/account-erasure.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import type { AuthService } from './auth.service.js';
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Request {
|
|
6
|
+
userId?: string;
|
|
7
|
+
userEmail?: string;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Name of the auth cookie set alongside the Bearer JWT at login. The cookie
|
|
13
|
+
* exists solely so the SSE route can authenticate — the browser's
|
|
14
|
+
* `EventSource` API can't set custom headers, so a Bearer token in
|
|
15
|
+
* `Authorization` can't reach it. All other routes still use the Bearer
|
|
16
|
+
* header, which the frontend stores in memory and attaches via `authFetch`.
|
|
17
|
+
*
|
|
18
|
+
* Same JWT value as the Bearer token. The cookie is `HttpOnly` + `SameSite=Lax`
|
|
19
|
+
* + `Secure` (in prod) — see `auth.routes.ts` for the issue site.
|
|
20
|
+
*/
|
|
21
|
+
export declare const AUTH_COOKIE_NAME = "bevel_token";
|
|
22
|
+
export declare function createAuthMiddleware(authService: AuthService): (req: Request, res: Response, next: NextFunction) => void;
|
|
23
|
+
//# sourceMappingURL=auth.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB;KACF;CACF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAyB9C,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,IACnD,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UA4BxD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name of the auth cookie set alongside the Bearer JWT at login. The cookie
|
|
3
|
+
* exists solely so the SSE route can authenticate — the browser's
|
|
4
|
+
* `EventSource` API can't set custom headers, so a Bearer token in
|
|
5
|
+
* `Authorization` can't reach it. All other routes still use the Bearer
|
|
6
|
+
* header, which the frontend stores in memory and attaches via `authFetch`.
|
|
7
|
+
*
|
|
8
|
+
* Same JWT value as the Bearer token. The cookie is `HttpOnly` + `SameSite=Lax`
|
|
9
|
+
* + `Secure` (in prod) — see `auth.routes.ts` for the issue site.
|
|
10
|
+
*/
|
|
11
|
+
export const AUTH_COOKIE_NAME = 'bevel_token';
|
|
12
|
+
/**
|
|
13
|
+
* Read the auth cookie out of the raw `Cookie` header without pulling in
|
|
14
|
+
* `cookie-parser`. We only ever look for one cookie, so a tiny parser
|
|
15
|
+
* beats the dep surface of a middleware. Returns `null` if the cookie
|
|
16
|
+
* is absent or empty.
|
|
17
|
+
*/
|
|
18
|
+
function readAuthCookie(req) {
|
|
19
|
+
const header = req.headers.cookie;
|
|
20
|
+
if (!header)
|
|
21
|
+
return null;
|
|
22
|
+
for (const segment of header.split(';')) {
|
|
23
|
+
const trimmed = segment.trim();
|
|
24
|
+
if (!trimmed.startsWith(`${AUTH_COOKIE_NAME}=`))
|
|
25
|
+
continue;
|
|
26
|
+
const value = trimmed.slice(AUTH_COOKIE_NAME.length + 1);
|
|
27
|
+
if (!value)
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
return decodeURIComponent(value);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
export function createAuthMiddleware(authService) {
|
|
39
|
+
return (req, res, next) => {
|
|
40
|
+
// Bearer is the primary path — every JSON API call in the frontend
|
|
41
|
+
// attaches it via `authFetch`. Cookie is the fallback for transports
|
|
42
|
+
// that can't carry headers (EventSource, image tags), set at login by
|
|
43
|
+
// `/auth/login` so SSE in particular Just Works after login without
|
|
44
|
+
// any frontend cooperation.
|
|
45
|
+
const header = req.headers.authorization;
|
|
46
|
+
let token = null;
|
|
47
|
+
if (header && header.startsWith('Bearer ')) {
|
|
48
|
+
token = header.slice('Bearer '.length).trim() || null;
|
|
49
|
+
}
|
|
50
|
+
if (!token) {
|
|
51
|
+
token = readAuthCookie(req);
|
|
52
|
+
}
|
|
53
|
+
if (!token) {
|
|
54
|
+
res.status(401).json({ error: 'Missing or invalid Authorization header or auth cookie' });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const { userId, email } = authService.verifyToken(token);
|
|
59
|
+
req.userId = userId;
|
|
60
|
+
req.userEmail = email;
|
|
61
|
+
next();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
res.status(401).json({ error: 'Invalid or expired token' });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=auth.middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.middleware.ts"],"names":[],"mappings":"AAaA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAE9C;;;;;GAKG;AACH,SAAS,cAAc,CAAC,GAAY;IAClC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,gBAAgB,GAAG,CAAC;YAAE,SAAS;QAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,CAAC;YACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,WAAwB;IAC3D,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACzD,mEAAmE;QACnE,qEAAqE;QACrE,sEAAsE;QACtE,oEAAoE;QACpE,4BAA4B;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QACzC,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3C,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wDAAwD,EAAE,CAAC,CAAC;YAC1F,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACzD,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;YACpB,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC;YACtB,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { AuthService } from './auth.service.js';
|
|
3
|
+
/**
|
|
4
|
+
* Max age of the JWT cookie (seconds). Matches the JWT's own `expiresIn:
|
|
5
|
+
* '7d'` so the cookie expires when the token does — browsers stop
|
|
6
|
+
* sending it past expiry, sparing the auth middleware verifying tokens
|
|
7
|
+
* that are guaranteed to fail.
|
|
8
|
+
*/
|
|
9
|
+
export declare const AUTH_COOKIE_MAX_AGE_S: number;
|
|
10
|
+
/**
|
|
11
|
+
* A pluggable SSO login method. Core ships password login only; the
|
|
12
|
+
* composition root passes provider plugins (e.g. Microsoft OIDC, owned by the
|
|
13
|
+
* sharepoint module) which mount their own routes under `/auth/<key>/…` and
|
|
14
|
+
* are advertised to the login screen under `key` by the capability probe.
|
|
15
|
+
* A plugin is only passed in when its machinery is configured AND the
|
|
16
|
+
* instance hasn't switched it off — presence means enabled.
|
|
17
|
+
*/
|
|
18
|
+
export interface AuthProviderPlugin {
|
|
19
|
+
/** Probe key + route namespace (e.g. 'microsoft' → /auth/microsoft/…). */
|
|
20
|
+
readonly key: string;
|
|
21
|
+
/** Mount the provider's routes (login redirect, callback) on the auth router. */
|
|
22
|
+
mountRoutes(router: express.Router, authService: AuthService): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function createAuthRoutes(authService: AuthService, authMiddleware: express.RequestHandler, providers?: AuthProviderPlugin[], passwordLoginEnabled?: boolean): express.Router;
|
|
25
|
+
//# sourceMappingURL=auth.routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAmB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CACrE;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,OAAO,CAAC,cAAc,EACtC,SAAS,GAAE,kBAAkB,EAAO,EACpC,oBAAoB,UAAO,GAC1B,OAAO,CAAC,MAAM,CAgEhB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { AUTH_COOKIE_NAME } from './auth.middleware.js'; // also imports Express Request augmentation
|
|
3
|
+
/**
|
|
4
|
+
* Max age of the JWT cookie (seconds). Matches the JWT's own `expiresIn:
|
|
5
|
+
* '7d'` so the cookie expires when the token does — browsers stop
|
|
6
|
+
* sending it past expiry, sparing the auth middleware verifying tokens
|
|
7
|
+
* that are guaranteed to fail.
|
|
8
|
+
*/
|
|
9
|
+
export const AUTH_COOKIE_MAX_AGE_S = 7 * 24 * 60 * 60;
|
|
10
|
+
export function createAuthRoutes(authService, authMiddleware, providers = [], passwordLoginEnabled = true) {
|
|
11
|
+
const router = express.Router();
|
|
12
|
+
// POST /api/auth/login — email + shared-password login (unprotected)
|
|
13
|
+
router.post('/auth/login', async (req, res) => {
|
|
14
|
+
if (!passwordLoginEnabled) {
|
|
15
|
+
res.status(403).json({ error: 'Password login is disabled' });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const { email, password } = req.body;
|
|
19
|
+
if (!email || !password) {
|
|
20
|
+
res.status(400).json({ error: 'email and password are required' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const result = await authService.loginWithPassword(email, password);
|
|
25
|
+
// Also set the JWT as an HttpOnly cookie so transports that can't
|
|
26
|
+
// carry headers (EventSource for SSE, image tags) authenticate
|
|
27
|
+
// automatically. JSON callers continue to use the Bearer header
|
|
28
|
+
// returned in the body. Secure in production; off in dev so the
|
|
29
|
+
// cookie survives `http://localhost` requests.
|
|
30
|
+
res.cookie(AUTH_COOKIE_NAME, result.token, {
|
|
31
|
+
httpOnly: true,
|
|
32
|
+
sameSite: 'lax',
|
|
33
|
+
secure: process.env.NODE_ENV === 'production',
|
|
34
|
+
maxAge: AUTH_COOKIE_MAX_AGE_S * 1000,
|
|
35
|
+
path: '/',
|
|
36
|
+
});
|
|
37
|
+
res.json(result);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
41
|
+
console.error('Login error:', msg);
|
|
42
|
+
res.status(401).json({ error: 'Authentication failed' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// GET /api/auth/providers — unprotected capability probe so the login screen
|
|
46
|
+
// knows which login methods to render. SSO providers appear under their key.
|
|
47
|
+
router.get('/auth/providers', (_req, res) => {
|
|
48
|
+
res.json({
|
|
49
|
+
password: passwordLoginEnabled,
|
|
50
|
+
...Object.fromEntries(providers.map((p) => [p.key, true])),
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
for (const provider of providers)
|
|
54
|
+
provider.mountRoutes(router, authService);
|
|
55
|
+
// GET /api/auth/me — validate stored JWT, return user info (protected)
|
|
56
|
+
router.get('/auth/me', authMiddleware, async (req, res) => {
|
|
57
|
+
try {
|
|
58
|
+
const user = await authService.getUserById(req.userId);
|
|
59
|
+
if (!user) {
|
|
60
|
+
res.status(404).json({ error: 'User not found' });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
res.json(user);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
67
|
+
res.status(500).json({ error: msg });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return router;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=auth.routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.routes.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Database } from '../database/connection.js';
|
|
2
|
+
import type { CoreConfig } from '../../core-config.js';
|
|
3
|
+
import type { AuthUser } from '@bevel-software/platform-shared';
|
|
4
|
+
export declare class AuthService {
|
|
5
|
+
private readonly db;
|
|
6
|
+
private readonly config;
|
|
7
|
+
constructor(db: Database, config: CoreConfig);
|
|
8
|
+
loginWithPassword(email: string, password: string): Promise<{
|
|
9
|
+
token: string;
|
|
10
|
+
user: AuthUser;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Establish a session for a user who authenticated via "Sign in with
|
|
14
|
+
* Microsoft". Same upsert-by-email + JWT path as password login — the only
|
|
15
|
+
* difference is identity came from a verified Microsoft id_token instead of
|
|
16
|
+
* the shared password. Email is the idempotency key, so a user who first
|
|
17
|
+
* used password login and later signs in with Microsoft (same email) keeps
|
|
18
|
+
* the same account/id.
|
|
19
|
+
*/
|
|
20
|
+
loginWithMicrosoft(email: string, name: string): Promise<{
|
|
21
|
+
token: string;
|
|
22
|
+
user: AuthUser;
|
|
23
|
+
}>;
|
|
24
|
+
private signToken;
|
|
25
|
+
/**
|
|
26
|
+
* Get-or-create a user record by email, without issuing a session token.
|
|
27
|
+
* Used by the embed surface: an Atlassian (Forge) editor whose identity was
|
|
28
|
+
* verified server-side needs a real user row so file-lock commits attribute
|
|
29
|
+
* to them — but they never get a Bevel browser session. Same email-keyed
|
|
30
|
+
* upsert as the login paths, so an embed editor who later logs in keeps the
|
|
31
|
+
* same account/id. Returns `null` for a malformed email.
|
|
32
|
+
*/
|
|
33
|
+
getOrCreateByEmail(email: string, name?: string): Promise<{
|
|
34
|
+
id: string;
|
|
35
|
+
email: string;
|
|
36
|
+
name: string;
|
|
37
|
+
} | null>;
|
|
38
|
+
private upsertUserByEmail;
|
|
39
|
+
verifyToken(token: string): {
|
|
40
|
+
userId: string;
|
|
41
|
+
email: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a set of `authorId` hashes back to the app users that produced
|
|
45
|
+
* them. Used by the PR list to display the human who triggered each PR
|
|
46
|
+
* instead of the shared GitHub service account.
|
|
47
|
+
*
|
|
48
|
+
* Loads all users and hashes them in-process rather than indexing on a
|
|
49
|
+
* stored hash column — the user table is small (one row per team member)
|
|
50
|
+
* and refreshes are infrequent (PR list polls at 60s), so the cost is
|
|
51
|
+
* negligible and we avoid carrying a denormalised hash column.
|
|
52
|
+
*/
|
|
53
|
+
findUsersByEmailHash(hashes: Set<string>): Promise<Map<string, {
|
|
54
|
+
id: string;
|
|
55
|
+
email: string;
|
|
56
|
+
name: string;
|
|
57
|
+
}>>;
|
|
58
|
+
getUserById(userId: string): Promise<AuthUser | null>;
|
|
59
|
+
/**
|
|
60
|
+
* Whether `email` passes the optional `ALLOWED_EMAIL_DOMAINS` guard. Returns
|
|
61
|
+
* true when no guard is configured (the default). Matches the email's domain
|
|
62
|
+
* exactly or as a subdomain, so `bevel.software` admits `a@bevel.software`
|
|
63
|
+
* and `a@eu.bevel.software` but not `a@notbevel.software`. When a guard IS
|
|
64
|
+
* configured, a missing/blank email fails closed. Exposed so non-login
|
|
65
|
+
* surfaces (the embed panel) can apply the same gate.
|
|
66
|
+
*/
|
|
67
|
+
isEmailDomainAllowed(email: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Enforce {@link isEmailDomainAllowed} at the login paths. No-op when the
|
|
70
|
+
* guard is unset. Expects an already-normalized (trimmed, lower-cased,
|
|
71
|
+
* regex-validated) email.
|
|
72
|
+
*/
|
|
73
|
+
private assertAllowedDomain;
|
|
74
|
+
private checkPassword;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=auth.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.service.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/auth.service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAmBhE,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,UAAU;IAG/B,iBAAiB,CACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IAiB7C;;;;;;;OAOG;IACG,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IAW7C,OAAO,CAAC,SAAS;IAIjB;;;;;;;OAOG;IACG,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;YAQhD,iBAAiB;IAS/B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAQ7D;;;;;;;;;OASG;IACG,oBAAoB,CACxB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAY9D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAiB3D;;;;;;;OAOG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ5C;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,aAAa;CAiBtB"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
import { eq } from 'drizzle-orm';
|
|
4
|
+
import { users } from '../database/schema.js';
|
|
5
|
+
import { hashEmail } from '../../shared/hash-email.js';
|
|
6
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
7
|
+
function toAuthUser(user) {
|
|
8
|
+
return {
|
|
9
|
+
id: user.id,
|
|
10
|
+
email: user.email,
|
|
11
|
+
name: user.name,
|
|
12
|
+
avatarUrl: user.avatarUrl ?? undefined,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export class AuthService {
|
|
16
|
+
db;
|
|
17
|
+
config;
|
|
18
|
+
constructor(db, config) {
|
|
19
|
+
this.db = db;
|
|
20
|
+
this.config = config;
|
|
21
|
+
}
|
|
22
|
+
async loginWithPassword(email, password) {
|
|
23
|
+
const normalizedEmail = (email ?? '').trim().toLowerCase();
|
|
24
|
+
if (!EMAIL_REGEX.test(normalizedEmail)) {
|
|
25
|
+
throw new Error('Invalid email');
|
|
26
|
+
}
|
|
27
|
+
this.assertAllowedDomain(normalizedEmail);
|
|
28
|
+
if (!this.checkPassword(password ?? '')) {
|
|
29
|
+
throw new Error('Invalid password');
|
|
30
|
+
}
|
|
31
|
+
// Derive a default display name from the local-part of the email
|
|
32
|
+
const defaultName = normalizedEmail.split('@')[0] || normalizedEmail;
|
|
33
|
+
const user = await this.upsertUserByEmail(normalizedEmail, defaultName);
|
|
34
|
+
return { token: this.signToken(user.id, user.email), user: toAuthUser(user) };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Establish a session for a user who authenticated via "Sign in with
|
|
38
|
+
* Microsoft". Same upsert-by-email + JWT path as password login — the only
|
|
39
|
+
* difference is identity came from a verified Microsoft id_token instead of
|
|
40
|
+
* the shared password. Email is the idempotency key, so a user who first
|
|
41
|
+
* used password login and later signs in with Microsoft (same email) keeps
|
|
42
|
+
* the same account/id.
|
|
43
|
+
*/
|
|
44
|
+
async loginWithMicrosoft(email, name) {
|
|
45
|
+
const normalizedEmail = (email ?? '').trim().toLowerCase();
|
|
46
|
+
if (!EMAIL_REGEX.test(normalizedEmail)) {
|
|
47
|
+
throw new Error('Microsoft sign-in returned an invalid email');
|
|
48
|
+
}
|
|
49
|
+
this.assertAllowedDomain(normalizedEmail);
|
|
50
|
+
const displayName = (name ?? '').trim() || normalizedEmail.split('@')[0] || normalizedEmail;
|
|
51
|
+
const user = await this.upsertUserByEmail(normalizedEmail, displayName);
|
|
52
|
+
return { token: this.signToken(user.id, user.email), user: toAuthUser(user) };
|
|
53
|
+
}
|
|
54
|
+
signToken(userId, email) {
|
|
55
|
+
return jwt.sign({ userId, email }, this.config.jwtSecret, { expiresIn: '7d' });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get-or-create a user record by email, without issuing a session token.
|
|
59
|
+
* Used by the embed surface: an Atlassian (Forge) editor whose identity was
|
|
60
|
+
* verified server-side needs a real user row so file-lock commits attribute
|
|
61
|
+
* to them — but they never get a Bevel browser session. Same email-keyed
|
|
62
|
+
* upsert as the login paths, so an embed editor who later logs in keeps the
|
|
63
|
+
* same account/id. Returns `null` for a malformed email.
|
|
64
|
+
*/
|
|
65
|
+
async getOrCreateByEmail(email, name) {
|
|
66
|
+
const normalizedEmail = (email ?? '').trim().toLowerCase();
|
|
67
|
+
if (!EMAIL_REGEX.test(normalizedEmail))
|
|
68
|
+
return null;
|
|
69
|
+
const displayName = (name ?? '').trim() || normalizedEmail.split('@')[0] || normalizedEmail;
|
|
70
|
+
const user = await this.upsertUserByEmail(normalizedEmail, displayName);
|
|
71
|
+
return { id: user.id, email: user.email, name: user.name };
|
|
72
|
+
}
|
|
73
|
+
async upsertUserByEmail(email, name) {
|
|
74
|
+
const [user] = await this.db
|
|
75
|
+
.insert(users)
|
|
76
|
+
.values({ email, name })
|
|
77
|
+
.onConflictDoUpdate({ target: users.email, set: { updatedAt: new Date() } })
|
|
78
|
+
.returning();
|
|
79
|
+
return user;
|
|
80
|
+
}
|
|
81
|
+
verifyToken(token) {
|
|
82
|
+
const decoded = jwt.verify(token, this.config.jwtSecret);
|
|
83
|
+
return { userId: decoded.userId, email: decoded.email };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a set of `authorId` hashes back to the app users that produced
|
|
87
|
+
* them. Used by the PR list to display the human who triggered each PR
|
|
88
|
+
* instead of the shared GitHub service account.
|
|
89
|
+
*
|
|
90
|
+
* Loads all users and hashes them in-process rather than indexing on a
|
|
91
|
+
* stored hash column — the user table is small (one row per team member)
|
|
92
|
+
* and refreshes are infrequent (PR list polls at 60s), so the cost is
|
|
93
|
+
* negligible and we avoid carrying a denormalised hash column.
|
|
94
|
+
*/
|
|
95
|
+
async findUsersByEmailHash(hashes) {
|
|
96
|
+
const result = new Map();
|
|
97
|
+
if (hashes.size === 0)
|
|
98
|
+
return result;
|
|
99
|
+
const rows = await this.db.select().from(users);
|
|
100
|
+
for (const row of rows) {
|
|
101
|
+
const h = hashEmail(row.email);
|
|
102
|
+
if (!hashes.has(h))
|
|
103
|
+
continue;
|
|
104
|
+
result.set(h, { id: row.id, email: row.email, name: row.name });
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
async getUserById(userId) {
|
|
109
|
+
const [user] = await this.db
|
|
110
|
+
.select()
|
|
111
|
+
.from(users)
|
|
112
|
+
.where(eq(users.id, userId))
|
|
113
|
+
.limit(1);
|
|
114
|
+
if (!user)
|
|
115
|
+
return null;
|
|
116
|
+
return {
|
|
117
|
+
id: user.id,
|
|
118
|
+
email: user.email,
|
|
119
|
+
name: user.name,
|
|
120
|
+
avatarUrl: user.avatarUrl ?? undefined,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Whether `email` passes the optional `ALLOWED_EMAIL_DOMAINS` guard. Returns
|
|
125
|
+
* true when no guard is configured (the default). Matches the email's domain
|
|
126
|
+
* exactly or as a subdomain, so `bevel.software` admits `a@bevel.software`
|
|
127
|
+
* and `a@eu.bevel.software` but not `a@notbevel.software`. When a guard IS
|
|
128
|
+
* configured, a missing/blank email fails closed. Exposed so non-login
|
|
129
|
+
* surfaces (the embed panel) can apply the same gate.
|
|
130
|
+
*/
|
|
131
|
+
isEmailDomainAllowed(email) {
|
|
132
|
+
const allowed = this.config.allowedEmailDomains;
|
|
133
|
+
if (allowed.length === 0)
|
|
134
|
+
return true;
|
|
135
|
+
const domain = (email ?? '').trim().toLowerCase().split('@')[1] ?? '';
|
|
136
|
+
if (!domain)
|
|
137
|
+
return false;
|
|
138
|
+
return allowed.some((d) => domain === d || domain.endsWith(`.${d}`));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Enforce {@link isEmailDomainAllowed} at the login paths. No-op when the
|
|
142
|
+
* guard is unset. Expects an already-normalized (trimmed, lower-cased,
|
|
143
|
+
* regex-validated) email.
|
|
144
|
+
*/
|
|
145
|
+
assertAllowedDomain(normalizedEmail) {
|
|
146
|
+
if (!this.isEmailDomainAllowed(normalizedEmail)) {
|
|
147
|
+
throw new Error('Email domain is not allowed');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
checkPassword(provided) {
|
|
151
|
+
const expected = this.config.testPassword;
|
|
152
|
+
// Reject if no password is configured on the server
|
|
153
|
+
if (!expected)
|
|
154
|
+
return false;
|
|
155
|
+
const a = Buffer.from(provided, 'utf8');
|
|
156
|
+
const b = Buffer.from(expected, 'utf8');
|
|
157
|
+
// Pad both buffers to the same length so timingSafeEqual runs unconditionally —
|
|
158
|
+
// returning early on length mismatch would leak the expected password's length via timing.
|
|
159
|
+
const len = Math.max(a.length, b.length);
|
|
160
|
+
const aPadded = Buffer.alloc(len);
|
|
161
|
+
const bPadded = Buffer.alloc(len);
|
|
162
|
+
a.copy(aPadded);
|
|
163
|
+
b.copy(bPadded);
|
|
164
|
+
const equal = timingSafeEqual(aPadded, bPadded);
|
|
165
|
+
return equal && a.length === b.length;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=auth.service.js.map
|