@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,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process event bus that fans workflow state-change events out to
|
|
3
|
+
* subscribed SSE sessions. The shape and scope rules live in
|
|
4
|
+
* `@bevel-software/platform-shared/workflow/events.ts` — this module is the runtime that
|
|
5
|
+
* makes them deliverable.
|
|
6
|
+
*
|
|
7
|
+
* **What this owns**
|
|
8
|
+
*
|
|
9
|
+
* 1. **The monotonic event id.** Each `emit` stamps the next id; clients
|
|
10
|
+
* reconnecting with `Last-Event-ID: <n>` use it to replay everything
|
|
11
|
+
* they missed.
|
|
12
|
+
*
|
|
13
|
+
* 2. **A per-process ring buffer** of the last `BUFFER_CAPACITY` events.
|
|
14
|
+
* Replay works if the gap is short. Long disconnects fall back to
|
|
15
|
+
* `{ kind: 'resync' }` so the client refetches cleanly.
|
|
16
|
+
*
|
|
17
|
+
* 3. **A registry of subscribers**, each owning a per-session push
|
|
18
|
+
* function. On `emit`, every subscriber that matches the event's scope
|
|
19
|
+
* (see `isWorkspaceScoped` / `isUserScoped`) gets the event pushed
|
|
20
|
+
* synchronously to its push callback — the route layer translates that
|
|
21
|
+
* to an SSE `data:` line.
|
|
22
|
+
*
|
|
23
|
+
* **What this does NOT own**
|
|
24
|
+
*
|
|
25
|
+
* - Transport (SSE framing, heartbeats): the route layer.
|
|
26
|
+
* - Auth (which user owns a session): the route layer wires
|
|
27
|
+
* userId + sessionId in at subscription time, this just stores them.
|
|
28
|
+
* - Persistence: in-memory only. A server restart resets the id counter
|
|
29
|
+
* and empties the buffer; clients that reconnect after a restart will
|
|
30
|
+
* get a `resync` (their stored Last-Event-ID is necessarily older than
|
|
31
|
+
* the new buffer can serve), which is exactly the right behavior.
|
|
32
|
+
*
|
|
33
|
+
* **Concurrency** — Node is single-threaded for JS, so a synchronous fan-out
|
|
34
|
+
* inside `emit` is safe. Subscribers must not throw from their push
|
|
35
|
+
* callback; we wrap every push in try/catch and log so one bad subscriber
|
|
36
|
+
* never blocks the rest.
|
|
37
|
+
*/
|
|
38
|
+
import { isUserScoped, isWorkspaceScoped, } from '@bevel-software/platform-shared';
|
|
39
|
+
/**
|
|
40
|
+
* Capacity of the global event ring buffer. A new event evicts the oldest
|
|
41
|
+
* when full. Sized for "should comfortably catch any client through a brief
|
|
42
|
+
* network blip" — 500 events at e.g. one edit per second buys ~8 minutes of
|
|
43
|
+
* coverage, plenty for transient reconnects. Sized down would push more
|
|
44
|
+
* clients onto the `resync` path; sized up wastes RSS on no-op edits.
|
|
45
|
+
*/
|
|
46
|
+
const BUFFER_CAPACITY = 500;
|
|
47
|
+
/**
|
|
48
|
+
* Decode-once, idempotent. Both sides of the focus / workspaceId
|
|
49
|
+
* comparison get fed through this so we don't care whether the caller
|
|
50
|
+
* sent the URL-encoded form (`razvan-radulescu%2Fsc`) or the canonical
|
|
51
|
+
* form (`razvan-radulescu/sc`). Catches malformed input by returning the
|
|
52
|
+
* original string — broken encoding shouldn't crash the dispatcher.
|
|
53
|
+
*/
|
|
54
|
+
function canonicalize(workspaceId) {
|
|
55
|
+
try {
|
|
56
|
+
return decodeURIComponent(workspaceId);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return workspaceId;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export class WorkflowEventBus {
|
|
63
|
+
nextId = 1;
|
|
64
|
+
buffer = [];
|
|
65
|
+
subscribers = new Map();
|
|
66
|
+
/**
|
|
67
|
+
* Stamp `payload` with `id` + `ts`, append to the ring buffer, then fan
|
|
68
|
+
* out synchronously to every matching subscriber. Returns the stamped
|
|
69
|
+
* event so callers (e.g. tests, debug logs) can see what was actually
|
|
70
|
+
* delivered.
|
|
71
|
+
*/
|
|
72
|
+
emit(payload) {
|
|
73
|
+
const event = {
|
|
74
|
+
id: this.nextId++,
|
|
75
|
+
ts: new Date().toISOString(),
|
|
76
|
+
...payload,
|
|
77
|
+
};
|
|
78
|
+
this.buffer.push(event);
|
|
79
|
+
if (this.buffer.length > BUFFER_CAPACITY) {
|
|
80
|
+
this.buffer.shift();
|
|
81
|
+
}
|
|
82
|
+
// Single-line emit log with all the fields most useful for tracing a
|
|
83
|
+
// failed delivery: which event, which scope it'll filter on, and the
|
|
84
|
+
// total subscriber pool size before fan-out. Per-subscriber matched/
|
|
85
|
+
// skipped decisions are logged below at debug level.
|
|
86
|
+
const scope = 'workspaceId' in event && event.workspaceId
|
|
87
|
+
? `ws=${event.workspaceId}`
|
|
88
|
+
: 'forUserId' in event && event.forUserId
|
|
89
|
+
? `user=${event.forUserId}`
|
|
90
|
+
: 'global';
|
|
91
|
+
const extra = [];
|
|
92
|
+
if ('path' in event && event.path)
|
|
93
|
+
extra.push(`path=${event.path}`);
|
|
94
|
+
if ('branch' in event && event.branch)
|
|
95
|
+
extra.push(`branch=${event.branch}`);
|
|
96
|
+
if ('newSha' in event && event.newSha !== undefined)
|
|
97
|
+
extra.push(`sha=${event.newSha ?? 'null'}`);
|
|
98
|
+
if ('holderName' in event && event.holderName)
|
|
99
|
+
extra.push(`holder=${event.holderName}`);
|
|
100
|
+
console.log(`[event-bus] EMIT id=${event.id} kind=${event.kind} ${scope}${extra.length ? ' ' + extra.join(' ') : ''} subs=${this.subscribers.size}`);
|
|
101
|
+
let matched = 0;
|
|
102
|
+
let skipped = 0;
|
|
103
|
+
for (const sub of this.subscribers.values()) {
|
|
104
|
+
// Best-effort per subscriber — one bad subscriber must not block
|
|
105
|
+
// the rest of the fan-out OR propagate back to the caller. The
|
|
106
|
+
// try/catch covers both the scope check (`matches` reaches into
|
|
107
|
+
// `sub.getFocusedWorkspaceId()`, which could throw if a bizarre
|
|
108
|
+
// subscriber holds buggy state) and the dispatch itself, so
|
|
109
|
+
// workflow mutations stay successful even if a listener throws.
|
|
110
|
+
// Callers can rely on `emit` never throwing, so they don't need
|
|
111
|
+
// to wrap every emit call site in their own try/catch.
|
|
112
|
+
try {
|
|
113
|
+
if (!this.matches(event, sub)) {
|
|
114
|
+
skipped++;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
sub.push(event);
|
|
118
|
+
matched++;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.warn(`[event-bus] dispatch to session ${sub.sessionId} threw:`, err instanceof Error ? err.message : err);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
console.log(`[event-bus] EMIT id=${event.id} kind=${event.kind} → delivered=${matched} skipped=${skipped}`);
|
|
125
|
+
return event;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Register a subscriber. Returns an `unsubscribe` function the route
|
|
129
|
+
* layer is expected to call from `res.on('close', …)` — without it a
|
|
130
|
+
* disconnected client leaks the session entry forever.
|
|
131
|
+
*/
|
|
132
|
+
subscribe(sub) {
|
|
133
|
+
this.subscribers.set(sub.sessionId, sub);
|
|
134
|
+
console.log(`[event-bus] SUBSCRIBE session=${sub.sessionId} user=${sub.userId} → total=${this.subscribers.size}`);
|
|
135
|
+
return () => {
|
|
136
|
+
// Only delete if the same Subscriber is still registered — protects
|
|
137
|
+
// against a stale unsubscribe (e.g. a reconnect replaced the entry
|
|
138
|
+
// before the old `close` handler fired).
|
|
139
|
+
if (this.subscribers.get(sub.sessionId) === sub) {
|
|
140
|
+
this.subscribers.delete(sub.sessionId);
|
|
141
|
+
console.log(`[event-bus] UNSUBSCRIBE session=${sub.sessionId} user=${sub.userId} → total=${this.subscribers.size}`);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Snapshot of every event in the ring buffer strictly newer than
|
|
147
|
+
* `lastSeenId` that this `sub` would have received if it had been
|
|
148
|
+
* subscribed at the time. Used by the SSE route on reconnect:
|
|
149
|
+
*
|
|
150
|
+
* - The client sends `Last-Event-ID: <n>` (browser does this
|
|
151
|
+
* automatically when an `EventSource` reconnects).
|
|
152
|
+
* - The route fetches `replayAfter(n, sub)` and emits each event
|
|
153
|
+
* before resuming live delivery.
|
|
154
|
+
*
|
|
155
|
+
* Returns `null` when the gap is larger than the buffer — the route
|
|
156
|
+
* sends a `resync` event in that case and the client refetches everything.
|
|
157
|
+
* "Gap is larger" is detected by checking whether the buffer's oldest id
|
|
158
|
+
* is greater than `lastSeenId + 1` (i.e. we evicted events the client
|
|
159
|
+
* needs to see).
|
|
160
|
+
*/
|
|
161
|
+
replayAfter(lastSeenId, sub) {
|
|
162
|
+
// Empty buffer: a client that never saw anything (lastSeenId === 0) has
|
|
163
|
+
// nothing to replay and the empty array is correct. A client that DID
|
|
164
|
+
// see events (lastSeenId > 0) but reached an empty buffer means the
|
|
165
|
+
// process restarted — the id counter reset to 1, so anything the client
|
|
166
|
+
// saw before is unreachable. Force a `resync` rather than silently
|
|
167
|
+
// delivering nothing.
|
|
168
|
+
if (this.buffer.length === 0) {
|
|
169
|
+
return lastSeenId === 0 ? [] : null;
|
|
170
|
+
}
|
|
171
|
+
const oldestBufferedId = this.buffer[0].id;
|
|
172
|
+
const newestBufferedId = this.buffer[this.buffer.length - 1].id;
|
|
173
|
+
if (oldestBufferedId > lastSeenId + 1) {
|
|
174
|
+
return null; // Caller emits a `resync`.
|
|
175
|
+
}
|
|
176
|
+
// Process restart can also leave `lastSeenId` ahead of the buffer's
|
|
177
|
+
// newest id (counter reset → newer events have lower ids than what the
|
|
178
|
+
// client last saw). Same outcome: client must resync from scratch.
|
|
179
|
+
if (lastSeenId > newestBufferedId) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const tail = this.buffer.filter((e) => e.id > lastSeenId);
|
|
183
|
+
return tail.filter((e) => this.matches(e, sub));
|
|
184
|
+
}
|
|
185
|
+
/** Subscriber count — exposed for `/health` and tests. */
|
|
186
|
+
size() {
|
|
187
|
+
return this.subscribers.size;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Filter rule that decides whether `event` should reach `sub`:
|
|
191
|
+
*
|
|
192
|
+
* - Workspace-scoped events: only sessions currently focused on the
|
|
193
|
+
* same `workspaceId`.
|
|
194
|
+
* - User-scoped events: only sessions whose `userId` matches `forUserId`.
|
|
195
|
+
* - Global events (heartbeat, resync, change-request-*): everyone.
|
|
196
|
+
*
|
|
197
|
+
* The focus check resolves through `getFocusedWorkspaceId()` so a session
|
|
198
|
+
* that hasn't yet POSTed its focus gets no workspace events (correct —
|
|
199
|
+
* we don't know what it cares about).
|
|
200
|
+
*/
|
|
201
|
+
matches(event, sub) {
|
|
202
|
+
if (isWorkspaceScoped(event)) {
|
|
203
|
+
const focus = sub.getFocusedWorkspaceId();
|
|
204
|
+
if (focus === null)
|
|
205
|
+
return false;
|
|
206
|
+
// **Normalise URL encoding before comparing.** The frontend stores
|
|
207
|
+
// `workspace.id` as `encodeURIComponent(branch)` (e.g.
|
|
208
|
+
// `razvan-radulescu%2Fsc`) and sends that as the focus value via
|
|
209
|
+
// the POST /focus endpoint. The backend route handlers, however,
|
|
210
|
+
// extract `req.params.id` which Express auto-decodes — so events
|
|
211
|
+
// fire with `workspaceId = razvan-radulescu/sc`. Naïve `===` then
|
|
212
|
+
// rejects every workspace-scoped event for any branch that
|
|
213
|
+
// contains a `/`, silently dropping all live updates (lock state,
|
|
214
|
+
// file-changed, fs-tree) on feature branches. Decoding both sides
|
|
215
|
+
// collapses the two forms into the same canonical key.
|
|
216
|
+
return canonicalize(focus) === canonicalize(event.workspaceId);
|
|
217
|
+
}
|
|
218
|
+
if (isUserScoped(event)) {
|
|
219
|
+
return sub.userId === event.forUserId;
|
|
220
|
+
}
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../src/modules/workflow/event-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE event-bus HTTP surface.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/events?session=<sessionId> — open the long-lived SSE stream
|
|
5
|
+
* POST /api/events/:sessionId/focus — update which workspace this
|
|
6
|
+
* session cares about (changes
|
|
7
|
+
* over the connection's lifetime
|
|
8
|
+
* as the user / agent switches
|
|
9
|
+
* branches)
|
|
10
|
+
*
|
|
11
|
+
* **Why a per-tab session id, not per-workspace** — the connection must
|
|
12
|
+
* survive a workspace re-focus (when the user navigates between branches
|
|
13
|
+
* the URL changes and the workspace bootstrap rebinds `workspaceId`, but
|
|
14
|
+
* the EventSource stays open). So scope = `(userId, sessionId)`; the
|
|
15
|
+
* "what workspace events do I want" state is mutable and lives in the
|
|
16
|
+
* focus endpoint above.
|
|
17
|
+
*
|
|
18
|
+
* **Auth** — the SSE route can't read `Authorization: Bearer …` (the
|
|
19
|
+
* browser's EventSource API can't set headers), so the auth middleware
|
|
20
|
+
* also accepts the JWT from the `bevel_token` cookie set at login. The
|
|
21
|
+
* focus POST goes through the regular auth middleware too, and verifies
|
|
22
|
+
* that the cookie-authed user matches the session's owner.
|
|
23
|
+
*
|
|
24
|
+
* **Reconnect** — the browser's EventSource auto-reconnects on close
|
|
25
|
+
* (~3 s backoff). On reconnect it sends `Last-Event-ID: <n>` and the
|
|
26
|
+
* route replays anything still in the bus's ring buffer; if the buffer
|
|
27
|
+
* has evicted past `n`, the route emits `{ kind: 'resync' }` so the
|
|
28
|
+
* client refetches state from scratch.
|
|
29
|
+
*
|
|
30
|
+
* **Heartbeat** — every 25 s the route writes an SSE comment (`:\n\n`).
|
|
31
|
+
* Keeps proxies (nginx, Coolify's Traefik, Cloudflare) from killing the
|
|
32
|
+
* connection as idle. Cheap (~15 bytes), eliminates a whole class of bug.
|
|
33
|
+
*/
|
|
34
|
+
import type { Response } from 'express';
|
|
35
|
+
import express from 'express';
|
|
36
|
+
import type { WorkflowEvent } from '@bevel-software/platform-shared';
|
|
37
|
+
import type { WorkflowEventBus } from './event-bus.js';
|
|
38
|
+
import '../auth/auth.middleware.js';
|
|
39
|
+
/**
|
|
40
|
+
* Per-session bookkeeping the route owns. The bus's `Subscriber` holds a
|
|
41
|
+
* `getFocusedWorkspaceId()` getter pointing at `session.focusedWorkspaceId`,
|
|
42
|
+
* so the focus POST mutates this object and the next event fan-out picks
|
|
43
|
+
* up the new value with no re-subscribe.
|
|
44
|
+
*/
|
|
45
|
+
interface ActiveSession {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
focusedWorkspaceId: string | null;
|
|
49
|
+
/** Set when the SSE connection closes. Used by the focus POST so a
|
|
50
|
+
* request that arrives after the connection drops 404s cleanly. */
|
|
51
|
+
closed: boolean;
|
|
52
|
+
/** The Express response stream backing this session. Stored so a
|
|
53
|
+
* same-id reconnect can `end()` the old response and close its TCP
|
|
54
|
+
* socket immediately, rather than leaving a dangling connection that
|
|
55
|
+
* silently accumulates server-side resources. */
|
|
56
|
+
res: Response;
|
|
57
|
+
/** Tear down bus subscription + heartbeat. Stored on the session so a
|
|
58
|
+
* same-id reconnect can run cleanup directly rather than relying on
|
|
59
|
+
* the old `res.on('close')` path (which short-circuits if we mark the
|
|
60
|
+
* session closed before the OS-level close event fires). */
|
|
61
|
+
cleanup: () => void;
|
|
62
|
+
}
|
|
63
|
+
export declare function createEventsRoutes(bus: WorkflowEventBus, authMiddleware: express.RequestHandler): express.Router;
|
|
64
|
+
/**
|
|
65
|
+
* Serialise `event` into the SSE wire format. Each frame is:
|
|
66
|
+
*
|
|
67
|
+
* id: <event.id>
|
|
68
|
+
* data: <JSON payload>
|
|
69
|
+
* \n
|
|
70
|
+
*
|
|
71
|
+
* The `id` field is what the browser's EventSource exposes as
|
|
72
|
+
* `event.lastEventId` and re-sends as `Last-Event-ID` on reconnect.
|
|
73
|
+
* Data is a single line of JSON — never embedded newlines, which would
|
|
74
|
+
* break the SSE parser. JSON.stringify guarantees that.
|
|
75
|
+
*/
|
|
76
|
+
declare function writeSseEvent(res: Response, event: WorkflowEvent): void;
|
|
77
|
+
/** Re-exported so tests / future hooks can construct the response shape. */
|
|
78
|
+
export { writeSseEvent as _writeSseEventForTests };
|
|
79
|
+
export type { ActiveSession };
|
|
80
|
+
//# sourceMappingURL=events.routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/workflow/events.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,4BAA4B,CAAC;AAMpC;;;;;GAKG;AACH,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;wEACoE;IACpE,MAAM,EAAE,OAAO,CAAC;IAChB;;;sDAGkD;IAClD,GAAG,EAAE,QAAQ,CAAC;IACd;;;iEAG6D;IAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,gBAAgB,EACrB,cAAc,EAAE,OAAO,CAAC,cAAc,GACrC,OAAO,CAAC,MAAM,CA4KhB;AAED;;;;;;;;;;;GAWG;AACH,iBAAS,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAGhE;AAED,4EAA4E;AAC5E,OAAO,EAAE,aAAa,IAAI,sBAAsB,EAAE,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE event-bus HTTP surface.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/events?session=<sessionId> — open the long-lived SSE stream
|
|
5
|
+
* POST /api/events/:sessionId/focus — update which workspace this
|
|
6
|
+
* session cares about (changes
|
|
7
|
+
* over the connection's lifetime
|
|
8
|
+
* as the user / agent switches
|
|
9
|
+
* branches)
|
|
10
|
+
*
|
|
11
|
+
* **Why a per-tab session id, not per-workspace** — the connection must
|
|
12
|
+
* survive a workspace re-focus (when the user navigates between branches
|
|
13
|
+
* the URL changes and the workspace bootstrap rebinds `workspaceId`, but
|
|
14
|
+
* the EventSource stays open). So scope = `(userId, sessionId)`; the
|
|
15
|
+
* "what workspace events do I want" state is mutable and lives in the
|
|
16
|
+
* focus endpoint above.
|
|
17
|
+
*
|
|
18
|
+
* **Auth** — the SSE route can't read `Authorization: Bearer …` (the
|
|
19
|
+
* browser's EventSource API can't set headers), so the auth middleware
|
|
20
|
+
* also accepts the JWT from the `bevel_token` cookie set at login. The
|
|
21
|
+
* focus POST goes through the regular auth middleware too, and verifies
|
|
22
|
+
* that the cookie-authed user matches the session's owner.
|
|
23
|
+
*
|
|
24
|
+
* **Reconnect** — the browser's EventSource auto-reconnects on close
|
|
25
|
+
* (~3 s backoff). On reconnect it sends `Last-Event-ID: <n>` and the
|
|
26
|
+
* route replays anything still in the bus's ring buffer; if the buffer
|
|
27
|
+
* has evicted past `n`, the route emits `{ kind: 'resync' }` so the
|
|
28
|
+
* client refetches state from scratch.
|
|
29
|
+
*
|
|
30
|
+
* **Heartbeat** — every 25 s the route writes an SSE comment (`:\n\n`).
|
|
31
|
+
* Keeps proxies (nginx, Coolify's Traefik, Cloudflare) from killing the
|
|
32
|
+
* connection as idle. Cheap (~15 bytes), eliminates a whole class of bug.
|
|
33
|
+
*/
|
|
34
|
+
import express from 'express';
|
|
35
|
+
import '../auth/auth.middleware.js'; // Express Request augmentation
|
|
36
|
+
/** Interval between SSE keep-alive comments (ms). 25 s sits comfortably under
|
|
37
|
+
* the typical 30–100 s proxy idle timeout. */
|
|
38
|
+
const HEARTBEAT_INTERVAL_MS = 25_000;
|
|
39
|
+
export function createEventsRoutes(bus, authMiddleware) {
|
|
40
|
+
const router = express.Router();
|
|
41
|
+
/**
|
|
42
|
+
* Process-wide session registry. The same map services the SSE open
|
|
43
|
+
* (creates the entry) and the focus POST (mutates `focusedWorkspaceId`).
|
|
44
|
+
* Entries clear when the SSE connection closes.
|
|
45
|
+
*/
|
|
46
|
+
const sessions = new Map();
|
|
47
|
+
router.get('/events', authMiddleware, (req, res) => {
|
|
48
|
+
const sessionId = typeof req.query.session === 'string' ? req.query.session : '';
|
|
49
|
+
if (!sessionId) {
|
|
50
|
+
res.status(400).json({ error: 'session query parameter is required' });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const userId = req.userId;
|
|
54
|
+
// SSE headers. `X-Accel-Buffering: no` tells nginx not to buffer the
|
|
55
|
+
// response (would batch events behind a flush boundary, killing
|
|
56
|
+
// latency). `Cache-Control: no-cache` + omitted `Content-Length`
|
|
57
|
+
// signal "long-lived stream, don't cache."
|
|
58
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
59
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
60
|
+
res.setHeader('Connection', 'keep-alive');
|
|
61
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
62
|
+
res.flushHeaders();
|
|
63
|
+
// If a previous session with the same id is still registered (e.g.
|
|
64
|
+
// browser refresh that reuses sessionStorage), close it gracefully
|
|
65
|
+
// before we replace it. Two SSE streams for one session id would
|
|
66
|
+
// double-fire every event to that browser. We also `end()` the old
|
|
67
|
+
// response so the underlying TCP socket goes away immediately —
|
|
68
|
+
// without that, the previous `res` lingers in keep-alive state
|
|
69
|
+
// until the network times it out (minutes), wasting an FD per
|
|
70
|
+
// refresh.
|
|
71
|
+
const existing = sessions.get(sessionId);
|
|
72
|
+
if (existing && !existing.closed) {
|
|
73
|
+
// Tear down the bus subscription + heartbeat FIRST, then mark
|
|
74
|
+
// closed, then end the response. Order matters: marking `closed`
|
|
75
|
+
// before cleanup would make the OS-close handler's own cleanup
|
|
76
|
+
// short-circuit (it returns early on `closed`), leaking the
|
|
77
|
+
// subscriber + heartbeat for this session id forever.
|
|
78
|
+
try {
|
|
79
|
+
existing.cleanup();
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.warn(`[events] supersede cleanup threw for session=${sessionId}:`, err instanceof Error ? err.message : err);
|
|
83
|
+
}
|
|
84
|
+
existing.closed = true;
|
|
85
|
+
try {
|
|
86
|
+
if (!existing.res.writableEnded)
|
|
87
|
+
existing.res.end();
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
console.warn(`[events] failed to end superseded SSE response for session=${sessionId}:`, err instanceof Error ? err.message : err);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const session = {
|
|
94
|
+
sessionId,
|
|
95
|
+
userId,
|
|
96
|
+
focusedWorkspaceId: null,
|
|
97
|
+
closed: false,
|
|
98
|
+
res,
|
|
99
|
+
// Filled in below once `unsubscribe` + `heartbeat` exist.
|
|
100
|
+
cleanup: () => { },
|
|
101
|
+
};
|
|
102
|
+
sessions.set(sessionId, session);
|
|
103
|
+
const push = (event) => {
|
|
104
|
+
if (session.closed)
|
|
105
|
+
return;
|
|
106
|
+
writeSseEvent(res, event);
|
|
107
|
+
};
|
|
108
|
+
const unsubscribe = bus.subscribe({
|
|
109
|
+
sessionId,
|
|
110
|
+
userId,
|
|
111
|
+
getFocusedWorkspaceId: () => session.focusedWorkspaceId,
|
|
112
|
+
push,
|
|
113
|
+
});
|
|
114
|
+
// Replay anything the client missed since their last seen id. Browsers
|
|
115
|
+
// auto-send `Last-Event-ID` when EventSource reconnects, so this just
|
|
116
|
+
// works — no client cooperation needed beyond using the standard API.
|
|
117
|
+
const lastSeenHeader = req.headers['last-event-id'];
|
|
118
|
+
const lastSeenId = typeof lastSeenHeader === 'string' ? Number(lastSeenHeader) : NaN;
|
|
119
|
+
if (Number.isFinite(lastSeenId) && lastSeenId > 0) {
|
|
120
|
+
const replay = bus.replayAfter(lastSeenId, {
|
|
121
|
+
userId,
|
|
122
|
+
getFocusedWorkspaceId: () => session.focusedWorkspaceId,
|
|
123
|
+
});
|
|
124
|
+
if (replay === null) {
|
|
125
|
+
// Buffer evicted past `lastSeenId` — client must refetch from
|
|
126
|
+
// scratch rather than trust a partial replay.
|
|
127
|
+
writeSseEvent(res, {
|
|
128
|
+
id: 0,
|
|
129
|
+
ts: new Date().toISOString(),
|
|
130
|
+
kind: 'resync',
|
|
131
|
+
reason: 'last-event-id too old; ring buffer evicted',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
for (const event of replay)
|
|
136
|
+
writeSseEvent(res, event);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const heartbeat = setInterval(() => {
|
|
140
|
+
if (session.closed)
|
|
141
|
+
return;
|
|
142
|
+
// SSE comments start with `:` and are ignored by the EventSource
|
|
143
|
+
// parser. Cheapest possible keep-alive payload.
|
|
144
|
+
res.write(': heartbeat\n\n');
|
|
145
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
146
|
+
const cleanup = () => {
|
|
147
|
+
if (session.closed)
|
|
148
|
+
return;
|
|
149
|
+
session.closed = true;
|
|
150
|
+
clearInterval(heartbeat);
|
|
151
|
+
unsubscribe();
|
|
152
|
+
// Only delete if we're still the registered session — a reconnect
|
|
153
|
+
// for the same id may have already replaced us.
|
|
154
|
+
if (sessions.get(sessionId) === session) {
|
|
155
|
+
sessions.delete(sessionId);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
session.cleanup = cleanup;
|
|
159
|
+
res.on('close', cleanup);
|
|
160
|
+
res.on('error', cleanup);
|
|
161
|
+
console.log(`[events] open session=${sessionId} user=${userId} subscribers=${bus.size()}`);
|
|
162
|
+
});
|
|
163
|
+
router.post('/events/:sessionId/focus', authMiddleware, express.json(), (req, res) => {
|
|
164
|
+
const sessionId = String(req.params.sessionId ?? '');
|
|
165
|
+
const userId = req.userId;
|
|
166
|
+
if (!sessionId) {
|
|
167
|
+
res.status(400).json({ error: 'sessionId is required' });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const session = sessions.get(sessionId);
|
|
171
|
+
if (!session || session.closed) {
|
|
172
|
+
// 404 is the cleanest signal — the client should open a new SSE
|
|
173
|
+
// stream and POST focus again on success. (Browser EventSource
|
|
174
|
+
// auto-reconnects, so this should be rare in practice.)
|
|
175
|
+
res.status(404).json({ error: 'Session not found' });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (session.userId !== userId) {
|
|
179
|
+
// Hard 403 — a user must never be able to set focus on another
|
|
180
|
+
// user's session, which would let them mirror that user's events
|
|
181
|
+
// into their own connection. Belt-and-braces; cookie auth already
|
|
182
|
+
// gates which userId reaches this handler.
|
|
183
|
+
res.status(403).json({ error: 'Session belongs to another user' });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const { workspaceId } = (req.body ?? {});
|
|
187
|
+
if (typeof workspaceId !== 'string' || workspaceId.length === 0) {
|
|
188
|
+
res.status(400).json({ error: 'workspaceId is required in body' });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const previous = session.focusedWorkspaceId;
|
|
192
|
+
session.focusedWorkspaceId = workspaceId;
|
|
193
|
+
console.log(`[events] FOCUS session=${sessionId} user=${userId} ${previous ?? '(none)'} → ${workspaceId}`);
|
|
194
|
+
res.json({ status: 'ok', focusedWorkspaceId: workspaceId });
|
|
195
|
+
});
|
|
196
|
+
return router;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Serialise `event` into the SSE wire format. Each frame is:
|
|
200
|
+
*
|
|
201
|
+
* id: <event.id>
|
|
202
|
+
* data: <JSON payload>
|
|
203
|
+
* \n
|
|
204
|
+
*
|
|
205
|
+
* The `id` field is what the browser's EventSource exposes as
|
|
206
|
+
* `event.lastEventId` and re-sends as `Last-Event-ID` on reconnect.
|
|
207
|
+
* Data is a single line of JSON — never embedded newlines, which would
|
|
208
|
+
* break the SSE parser. JSON.stringify guarantees that.
|
|
209
|
+
*/
|
|
210
|
+
function writeSseEvent(res, event) {
|
|
211
|
+
res.write(`id: ${event.id}\n`);
|
|
212
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
213
|
+
}
|
|
214
|
+
/** Re-exported so tests / future hooks can construct the response shape. */
|
|
215
|
+
export { writeSseEvent as _writeSseEventForTests };
|
|
216
|
+
//# sourceMappingURL=events.routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.routes.js","sourceRoot":"","sources":["../../../src/modules/workflow/events.routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One in-process notification fired AFTER a set of file changes is committed +
|
|
3
|
+
* pushed (post-lock-release), so backend services can react to KB writes without
|
|
4
|
+
* the per-file TTL wait. Distinct from the SSE `WorkflowEventBus`, which fans
|
|
5
|
+
* scoped events to browser sessions; this is an unscoped, server-side domain hook.
|
|
6
|
+
*
|
|
7
|
+
* BATCHED by design: a single-file save emits `paths: [p]`, a batch write
|
|
8
|
+
* (`LockingFilesystem.writeFiles`, e.g. a bulk node upload) emits ONE event with
|
|
9
|
+
* every path it committed. Subscribers that do expensive per-event work (the
|
|
10
|
+
* id-repair rebuilds the id index) handle a whole batch off one rebuild instead
|
|
11
|
+
* of N back-to-back ones.
|
|
12
|
+
*
|
|
13
|
+
* Emitted from the two post-commit chokepoints (`WorkflowService.runPendingCommit`
|
|
14
|
+
* for single-file writes, `LockingFilesystem.writeFiles` for batches).
|
|
15
|
+
*
|
|
16
|
+
* Every listener is invoked inside try/catch — a throwing subscriber must never
|
|
17
|
+
* fail the commit that triggered it (mirrors the SSE bus's per-subscriber
|
|
18
|
+
* isolation). Firing is fire-and-forget; a listener that needs to write files
|
|
19
|
+
* (id-repair) does so on its own, after the locks have already been released.
|
|
20
|
+
*/
|
|
21
|
+
import type { AuthUser } from '@bevel-software/platform-shared';
|
|
22
|
+
export interface FilesChange {
|
|
23
|
+
workspaceId: string;
|
|
24
|
+
branch: string;
|
|
25
|
+
/** Workspace-relative paths committed in this change (≥1; sorted for batches). */
|
|
26
|
+
paths: string[];
|
|
27
|
+
/** Who the change was committed as — a reacting write (id-repair) acts as the same user. */
|
|
28
|
+
byUser: AuthUser;
|
|
29
|
+
}
|
|
30
|
+
export type FilesChangedListener = (change: FilesChange) => void;
|
|
31
|
+
export declare class FileChangeNotifier {
|
|
32
|
+
private readonly listeners;
|
|
33
|
+
/** Register a listener. Returns an unsubscribe fn. */
|
|
34
|
+
onFilesChanged(listener: FilesChangedListener): () => void;
|
|
35
|
+
/** Fan a change out to every listener; isolate + log each so one can't break the commit. */
|
|
36
|
+
emit(change: FilesChange): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=file-change-notifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-change-notifier.d.ts","sourceRoot":"","sources":["../../../src/modules/workflow/file-change-notifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4FAA4F;IAC5F,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;AAEjE,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;IAE7D,sDAAsD;IACtD,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAK1D,4FAA4F;IAC5F,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;CAUhC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class FileChangeNotifier {
|
|
2
|
+
listeners = new Set();
|
|
3
|
+
/** Register a listener. Returns an unsubscribe fn. */
|
|
4
|
+
onFilesChanged(listener) {
|
|
5
|
+
this.listeners.add(listener);
|
|
6
|
+
return () => this.listeners.delete(listener);
|
|
7
|
+
}
|
|
8
|
+
/** Fan a change out to every listener; isolate + log each so one can't break the commit. */
|
|
9
|
+
emit(change) {
|
|
10
|
+
if (change.paths.length === 0)
|
|
11
|
+
return;
|
|
12
|
+
for (const listener of this.listeners) {
|
|
13
|
+
try {
|
|
14
|
+
listener(change);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error('[file-change] listener threw:', err instanceof Error ? err.message : err);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=file-change-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-change-notifier.js","sourceRoot":"","sources":["../../../src/modules/workflow/file-change-notifier.ts"],"names":[],"mappings":"AAiCA,MAAM,OAAO,kBAAkB;IACZ,SAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE7D,sDAAsD;IACtD,cAAc,CAAC,QAA8B;QAC3C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,4FAA4F;IAC5F,IAAI,CAAC,MAAmB;QACtB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACtC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,QAAQ,CAAC,MAAM,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|