@bevel-software/platform-core-backend 0.20.0 → 0.22.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/dist/core/catalog-cache-invalidation.d.ts +7 -2
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +8 -9
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/core-ports.d.ts +19 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts +2 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +55 -107
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +41 -4
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +183 -82
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +74 -28
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +157 -20
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/public-config.d.ts +5 -1
- package/dist/core/public-config.d.ts.map +1 -1
- package/dist/core/public-config.js +7 -5
- package/dist/core/public-config.js.map +1 -1
- package/dist/core-config.d.ts +95 -1
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +24 -8
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +18 -1
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +19 -8
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-requests.contract.d.ts +75 -0
- package/dist/modules/access/access-requests.contract.d.ts.map +1 -0
- package/dist/modules/access/access-requests.contract.js +20 -0
- package/dist/modules/access/access-requests.contract.js.map +1 -0
- package/dist/modules/access/access-requests.routes.d.ts +35 -0
- package/dist/modules/access/access-requests.routes.d.ts.map +1 -0
- package/dist/modules/access/access-requests.routes.js +237 -0
- package/dist/modules/access/access-requests.routes.js.map +1 -0
- package/dist/modules/access/access-requests.service.d.ts +123 -0
- package/dist/modules/access/access-requests.service.d.ts.map +1 -0
- package/dist/modules/access/access-requests.service.js +337 -0
- package/dist/modules/access/access-requests.service.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts +2 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +10 -10
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +6 -3
- package/dist/modules/access/change-read-gate.d.ts.map +1 -1
- package/dist/modules/access/change-read-gate.js +9 -6
- package/dist/modules/access/change-read-gate.js.map +1 -1
- package/dist/modules/access/creator-access.d.ts +4 -2
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +7 -4
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +12 -0
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +24 -0
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.js +6 -9
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +40 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -0
- package/dist/modules/auth/account-admission.js +17 -0
- package/dist/modules/auth/account-admission.js.map +1 -0
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +4 -1
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +45 -2
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +44 -3
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +9 -0
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +10 -2
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +17 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -1
- package/dist/modules/database/advisory-lock.js +24 -3
- package/dist/modules/database/advisory-lock.js.map +1 -1
- package/dist/modules/database/connection.d.ts +67 -2
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +118 -12
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +27 -3
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/github-app/github-app.client.d.ts +101 -0
- package/dist/modules/github-app/github-app.client.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.client.js +222 -0
- package/dist/modules/github-app/github-app.client.js.map +1 -0
- package/dist/modules/github-app/github-app.connection.d.ts +102 -0
- package/dist/modules/github-app/github-app.connection.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.connection.js +185 -0
- package/dist/modules/github-app/github-app.connection.js.map +1 -0
- package/dist/modules/github-app/github-app.routes.d.ts +59 -0
- package/dist/modules/github-app/github-app.routes.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.routes.js +323 -0
- package/dist/modules/github-app/github-app.routes.js.map +1 -0
- package/dist/modules/github-app/index.d.ts +4 -0
- package/dist/modules/github-app/index.d.ts.map +1 -0
- package/dist/modules/github-app/index.js +4 -0
- package/dist/modules/github-app/index.js.map +1 -0
- package/dist/modules/kb-fs/branch-name.d.ts +0 -1
- package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
- package/dist/modules/kb-fs/branch-name.js +3 -3
- package/dist/modules/kb-fs/branch-name.js.map +1 -1
- package/dist/modules/kb-fs/clone-config.d.ts +9 -8
- package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
- package/dist/modules/kb-fs/clone-config.js +14 -12
- package/dist/modules/kb-fs/clone-config.js.map +1 -1
- package/dist/modules/kb-fs/remote-url.d.ts +22 -0
- package/dist/modules/kb-fs/remote-url.d.ts.map +1 -0
- package/dist/modules/kb-fs/remote-url.js +35 -0
- package/dist/modules/kb-fs/remote-url.js.map +1 -0
- package/dist/modules/mcp/mcp.service.d.ts +7 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +4 -4
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +4 -2
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/index.d.ts +1 -1
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-proposals.d.ts +17 -5
- package/dist/modules/plugins/join-proposals.d.ts.map +1 -1
- package/dist/modules/plugins/join-proposals.js +76 -22
- package/dist/modules/plugins/join-proposals.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.js +6 -6
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
- package/dist/modules/plugins/join-requests.service.d.ts +113 -18
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +178 -33
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +65 -10
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +136 -31
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +151 -21
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +33 -26
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +10 -12
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +3 -0
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +48 -17
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +4 -4
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +7 -10
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/teams.routes.d.ts +4 -1
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
- package/dist/modules/plugins/teams.routes.js +11 -9
- package/dist/modules/plugins/teams.routes.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +34 -9
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +113 -26
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/managed-repository.d.ts +43 -0
- package/dist/modules/settings/managed-repository.d.ts.map +1 -0
- package/dist/modules/settings/managed-repository.js +60 -0
- package/dist/modules/settings/managed-repository.js.map +1 -0
- package/dist/modules/settings/repository-source.d.ts +128 -0
- package/dist/modules/settings/repository-source.d.ts.map +1 -0
- package/dist/modules/settings/repository-source.js +150 -0
- package/dist/modules/settings/repository-source.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +34 -4
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +198 -18
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
- package/dist/modules/skills/allowed-tools-check.js +8 -8
- package/dist/modules/skills/allowed-tools-check.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +3 -1
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +9 -6
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts +8 -9
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +26 -65
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +4 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +4 -4
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +4 -2
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +13 -11
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +15 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +47 -11
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +14 -6
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +40 -18
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.js +40 -5
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +45 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +99 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
- package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
- package/dist/modules/workflow/session-ontology.service.js +6 -2
- package/dist/modules/workflow/session-ontology.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +3 -1
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +42 -10
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +181 -71
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +3 -3
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +15 -13
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -7
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +183 -38
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +10 -6
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts +2 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +8 -7
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +18 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +49 -29
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +2 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +48 -20
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +3 -2
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +6 -5
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +39 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +55 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +62 -7
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js +30 -8
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/kb-context.d.ts +76 -0
- package/dist/shared/kb-context.d.ts.map +1 -0
- package/dist/shared/kb-context.js +108 -0
- package/dist/shared/kb-context.js.map +1 -0
- package/dist/shared/kb-layout.d.ts +3 -2
- package/dist/shared/kb-layout.d.ts.map +1 -1
- package/dist/shared/kb-layout.js +4 -3
- package/dist/shared/kb-layout.js.map +1 -1
- package/dist/shared/kb-layout.test.js +35 -27
- package/dist/shared/kb-layout.test.js.map +1 -1
- package/dist/shared/pending-proposals.d.ts +4 -1
- package/dist/shared/pending-proposals.d.ts.map +1 -1
- package/dist/shared/pending-proposals.js +3 -4
- package/dist/shared/pending-proposals.js.map +1 -1
- package/dist/shared/redact-secret.d.ts +5 -5
- package/dist/shared/redact-secret.js +5 -5
- package/dist/tenancy/index.d.ts +13 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +13 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/static-tenant-source.d.ts +98 -0
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
- package/dist/tenancy/static-tenant-source.js +220 -0
- package/dist/tenancy/static-tenant-source.js.map +1 -0
- package/dist/tenancy/tenant-host.d.ts +80 -0
- package/dist/tenancy/tenant-host.d.ts.map +1 -0
- package/dist/tenancy/tenant-host.js +217 -0
- package/dist/tenancy/tenant-host.js.map +1 -0
- package/dist/tenancy/tenant-runtime.d.ts +91 -0
- package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
- package/dist/tenancy/tenant-runtime.js +174 -0
- package/dist/tenancy/tenant-runtime.js.map +1 -0
- package/dist/tenancy/tenant-secrets.d.ts +24 -0
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
- package/dist/tenancy/tenant-secrets.js +30 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -0
- package/dist/tenancy/tenant-source.contract.d.ts +45 -0
- package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
- package/dist/tenancy/tenant-source.contract.js +21 -0
- package/dist/tenancy/tenant-source.contract.js.map +1 -0
- package/migrations/0000_core_init.sql +14 -14
- package/migrations/0003_deployment_settings.sql +1 -1
- package/migrations/0005_github_facade.sql +1 -1
- package/migrations/0012_agent_audit.sql +6 -6
- package/package.json +3 -3
- package/src/__tests__/branch-model.test.ts +7 -6
- package/src/__tests__/kb-context.ts +30 -0
- package/src/__tests__/kb-layout-config.test.ts +35 -30
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
- package/src/core/__tests__/lifecycle.test.ts +78 -1
- package/src/core/__tests__/public-config.test.ts +5 -1
- package/src/core/catalog-cache-invalidation.ts +16 -11
- package/src/core/core-ports.ts +19 -0
- package/src/core/create-core-server.ts +64 -107
- package/src/core/create-core-services.ts +238 -96
- package/src/core/lifecycle.ts +214 -29
- package/src/core/public-config.ts +8 -5
- package/src/core-config.ts +107 -8
- package/src/index.ts +25 -2
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
- package/src/modules/access/__tests__/access-requests.recut.test.ts +134 -0
- package/src/modules/access/__tests__/access-requests.routes.test.ts +610 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
- package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
- package/src/modules/access/__tests__/creator-access.test.ts +3 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
- package/src/modules/access/access-control.service.ts +20 -6
- package/src/modules/access/access-requests.contract.ts +93 -0
- package/src/modules/access/access-requests.routes.ts +286 -0
- package/src/modules/access/access-requests.service.ts +420 -0
- package/src/modules/access/access.routes.ts +10 -13
- package/src/modules/access/change-read-gate.ts +10 -4
- package/src/modules/access/creator-access.ts +7 -2
- package/src/modules/access-model/access-grammar.ts +22 -0
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
- package/src/modules/agent-instructions/read-preamble.ts +10 -12
- package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +98 -0
- package/src/modules/auth/account-admission.ts +44 -0
- package/src/modules/auth/account.routes.ts +4 -1
- package/src/modules/auth/auth.service.ts +61 -2
- package/src/modules/auth/oidc-auth-provider.ts +9 -0
- package/src/modules/connection-probe/connection-probe.service.ts +7 -1
- package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
- package/src/modules/database/__tests__/connection.test.ts +98 -0
- package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
- package/src/modules/database/advisory-lock.ts +28 -4
- package/src/modules/database/connection.ts +143 -13
- package/src/modules/database/migrate.ts +48 -14
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
- package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
- package/src/modules/github-app/__tests__/github-app.test.ts +848 -0
- package/src/modules/github-app/github-app.client.ts +268 -0
- package/src/modules/github-app/github-app.connection.ts +204 -0
- package/src/modules/github-app/github-app.routes.ts +359 -0
- package/src/modules/github-app/index.ts +19 -0
- package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
- package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
- package/src/modules/kb-fs/__tests__/remote-url.test.ts +38 -0
- package/src/modules/kb-fs/branch-name.ts +3 -3
- package/src/modules/kb-fs/clone-config.ts +15 -12
- package/src/modules/kb-fs/remote-url.ts +35 -0
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
- package/src/modules/mcp/mcp.service.ts +11 -4
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
- package/src/modules/plugins/__tests__/join-proposals.test.ts +100 -19
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
- package/src/modules/plugins/__tests__/join-requests.service.test.ts +28 -11
- package/src/modules/plugins/__tests__/join-requests.settlement.test.ts +371 -0
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +12 -3
- package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
- package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
- package/src/modules/plugins/discovery/native.source.ts +4 -1
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/join-proposals.ts +87 -19
- package/src/modules/plugins/join-request-jobs.service.ts +8 -7
- package/src/modules/plugins/join-requests.service.ts +203 -43
- package/src/modules/plugins/plugin-links.service.ts +192 -19
- package/src/modules/plugins/plugin-links.ts +147 -27
- package/src/modules/plugins/plugin-provision.service.ts +54 -27
- package/src/modules/plugins/plugin-rename.service.ts +10 -10
- package/src/modules/plugins/plugins.routes.ts +48 -17
- package/src/modules/plugins/plugins.service.ts +7 -11
- package/src/modules/plugins/teams.routes.ts +16 -8
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
- package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
- package/src/modules/secrets-vault/index.ts +2 -0
- package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
- package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
- package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
- package/src/modules/settings/__tests__/repository-source.test.ts +191 -0
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
- package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +353 -0
- package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +282 -0
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
- package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +233 -0
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
- package/src/modules/settings/deployment-settings.service.ts +130 -23
- package/src/modules/settings/managed-repository.ts +68 -0
- package/src/modules/settings/repository-source.ts +197 -0
- package/src/modules/settings/setup.routes.ts +233 -19
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
- package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +7 -2
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
- package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
- package/src/modules/skills/allowed-tools-check.ts +7 -6
- package/src/modules/skills/pending-skills.service.ts +9 -8
- package/src/modules/skills/skill-access-requests.routes.ts +29 -79
- package/src/modules/skills/skills.routes.ts +4 -3
- package/src/modules/skills/skills.service.ts +13 -9
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
- package/src/modules/tool-helpers/tool-context.ts +15 -0
- package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
- package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
- package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
- package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
- package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
- package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +11 -2
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +187 -35
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +148 -41
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +143 -2
- package/src/modules/workflow/agent-tools/workflow.tools.ts +60 -12
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
- package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
- package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
- package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
- package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +130 -8
- package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +145 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-delete.test.ts +166 -0
- package/src/modules/workflow/git/git.service.ts +49 -17
- package/src/modules/workflow/git/node-git-runner.ts +43 -4
- package/src/modules/workflow/git/pull-request.service.ts +119 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
- package/src/modules/workflow/session-ontology.service.ts +7 -2
- package/src/modules/workflow/workflow.routes.ts +3 -1
- package/src/modules/workflow/workflow.service.ts +201 -76
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
- package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +45 -1
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +237 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +44 -11
- package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
- package/src/modules/workspace/session-ontology.gate.ts +6 -4
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +240 -21
- package/src/modules/workspace/startup/kb-git.ts +15 -22
- package/src/modules/workspace/startup/kb-startup-runner.ts +198 -45
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
- package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
- package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
- package/src/modules/workspace/startup/steps/template-source.ts +8 -5
- package/src/modules/workspace/workspace.routes.ts +8 -7
- package/src/modules/workspace/workspace.service.ts +47 -28
- package/src/modules/workspace/workspace.tools.ts +56 -20
- package/src/modules/workspace/write-denial.ts +7 -5
- package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
- package/src/shared/domain-errors.ts +58 -0
- package/src/shared/git.contract.ts +80 -8
- package/src/shared/kb-context.ts +130 -0
- package/src/shared/kb-layout.test.ts +37 -27
- package/src/shared/kb-layout.ts +4 -3
- package/src/shared/pending-proposals.ts +7 -4
- package/src/shared/redact-secret.ts +5 -5
- package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
- package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
- package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
- package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
- package/src/tenancy/index.ts +35 -0
- package/src/tenancy/static-tenant-source.ts +296 -0
- package/src/tenancy/tenant-host.ts +261 -0
- package/src/tenancy/tenant-runtime.ts +208 -0
- package/src/tenancy/tenant-secrets.ts +41 -0
- package/src/tenancy/tenant-source.contract.ts +59 -0
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
import * as schema from './schema.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* One database, one schema per knowledge base.
|
|
4
|
+
*
|
|
5
|
+
* A single-tenant deployment keeps `public`, exactly as before this option
|
|
6
|
+
* existed: no `search_path` is set for it, so an operator's own default
|
|
7
|
+
* (`"$user", public`) is honoured, and the migration ledger stays where
|
|
8
|
+
* drizzle put it. A knowledge base hosted beside others gets a schema of its
|
|
9
|
+
* own: every connection of its pool starts with `search_path` pointing at it,
|
|
10
|
+
* so the unqualified table names the schema module and the migrations use
|
|
11
|
+
* resolve there and nowhere else. Isolation is then a Postgres object, and a
|
|
12
|
+
* tenant leaves as `pg_dump -n <schema>`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_DB_SCHEMA = "public";
|
|
15
|
+
/**
|
|
16
|
+
* A schema name this module will put into `search_path`: a plain lowercase
|
|
17
|
+
* identifier, at most Postgres's 63 characters. Validated rather than quoted,
|
|
18
|
+
* because the name also travels into `CREATE SCHEMA` and a `pg_dump`
|
|
19
|
+
* invocation, and a name that needs quoting in one of them is a name that
|
|
20
|
+
* will be spelled wrong in another.
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertSchemaName(name: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Prove that this handle's connections really search `schema` first, by
|
|
25
|
+
* asking the server. The schema is set as a startup parameter, and a
|
|
26
|
+
* transaction- or statement-mode pooler in front of the database (PgBouncer
|
|
27
|
+
* in those modes, RDS Proxy) either refuses that parameter or resets it
|
|
28
|
+
* between transactions; every unqualified table name would then resolve to
|
|
29
|
+
* `public`, and tenants would read each other's rows without a single
|
|
30
|
+
* error. So a graph refuses to come up on a handle that lost its schema,
|
|
31
|
+
* which is the failure an operator can see. Only session pooling is
|
|
32
|
+
* supported in front of a process that serves several knowledge bases.
|
|
33
|
+
*/
|
|
34
|
+
export declare function assertSearchPath(db: Pick<Database, 'execute'>, schema: string): Promise<void>;
|
|
35
|
+
export interface DbOptions {
|
|
36
|
+
/** The schema the pool's connections search first. Default {@link DEFAULT_DB_SCHEMA}. */
|
|
37
|
+
schema?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Connections the pool may hold. `pg`'s default (10) suits a process that
|
|
40
|
+
* serves one knowledge base; a process serving many keeps each pool small,
|
|
41
|
+
* since the database's `max_connections` is shared by all of them.
|
|
42
|
+
*/
|
|
43
|
+
max?: number;
|
|
44
|
+
/** How long an idle connection is kept before the pool closes it. Default: `pg`'s. */
|
|
45
|
+
idleTimeoutMillis?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A NEW pool on `databaseUrl`, searching `opts.schema` first. Not cached:
|
|
49
|
+
* the caller owns it and ends it with {@link closeDb}. The composition root
|
|
50
|
+
* of a process that serves one knowledge base goes through {@link getDb}
|
|
51
|
+
* instead, which caches.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createDb(databaseUrl: string, opts?: DbOptions): import("drizzle-orm/node-postgres").NodePgDatabase<typeof schema> & {
|
|
3
54
|
$client: import("pg").Pool;
|
|
4
55
|
};
|
|
5
|
-
export type Database = ReturnType<typeof
|
|
56
|
+
export type Database = ReturnType<typeof createDb>;
|
|
57
|
+
/** The schema a database handle searches first — for the callers that name it in DDL. */
|
|
58
|
+
export declare function dbSchemaOf(db: Pick<Database, '$client'>): string;
|
|
59
|
+
/**
|
|
60
|
+
* The process's pool on `databaseUrl` for `opts.schema`, created on first
|
|
61
|
+
* use and shared afterwards. One per (url, schema): two handles on the same
|
|
62
|
+
* schema would be two pools competing for the same connection budget.
|
|
63
|
+
*/
|
|
64
|
+
export declare function getDb(databaseUrl: string, opts?: DbOptions): Database;
|
|
65
|
+
/**
|
|
66
|
+
* End a handle's pool and forget it, so a later {@link getDb} for the same
|
|
67
|
+
* schema opens a fresh one rather than handing out a pool that was ended.
|
|
68
|
+
* The last step of stopping a knowledge base's graph.
|
|
69
|
+
*/
|
|
70
|
+
export declare function closeDb(db: Pick<Database, '$client'>): Promise<void>;
|
|
6
71
|
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/modules/database/connection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/modules/database/connection.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcrD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnG;AAED,MAAM,WAAW,SAAS;IACxB,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAcD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,SAAc;;EAgBjE;AAED,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEnD,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,MAAM,CAEhE;AAOD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,SAAc,GAAG,QAAQ,CASzE;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1E"}
|
|
@@ -1,20 +1,126 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
1
2
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
2
3
|
import pg from 'pg';
|
|
3
4
|
import * as schema from './schema.js';
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* One database, one schema per knowledge base.
|
|
7
|
+
*
|
|
8
|
+
* A single-tenant deployment keeps `public`, exactly as before this option
|
|
9
|
+
* existed: no `search_path` is set for it, so an operator's own default
|
|
10
|
+
* (`"$user", public`) is honoured, and the migration ledger stays where
|
|
11
|
+
* drizzle put it. A knowledge base hosted beside others gets a schema of its
|
|
12
|
+
* own: every connection of its pool starts with `search_path` pointing at it,
|
|
13
|
+
* so the unqualified table names the schema module and the migrations use
|
|
14
|
+
* resolve there and nowhere else. Isolation is then a Postgres object, and a
|
|
15
|
+
* tenant leaves as `pg_dump -n <schema>`.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_DB_SCHEMA = 'public';
|
|
18
|
+
/**
|
|
19
|
+
* A schema name this module will put into `search_path`: a plain lowercase
|
|
20
|
+
* identifier, at most Postgres's 63 characters. Validated rather than quoted,
|
|
21
|
+
* because the name also travels into `CREATE SCHEMA` and a `pg_dump`
|
|
22
|
+
* invocation, and a name that needs quoting in one of them is a name that
|
|
23
|
+
* will be spelled wrong in another.
|
|
24
|
+
*/
|
|
25
|
+
export function assertSchemaName(name) {
|
|
26
|
+
if (!/^[a-z][a-z0-9_]{0,62}$/.test(name)) {
|
|
27
|
+
throw new Error(`Database schema name must be a lowercase identifier ([a-z][a-z0-9_]*, at most 63 characters); got "${name}"`);
|
|
28
|
+
}
|
|
29
|
+
// Names Postgres or drizzle already own. `pg_*` would fail at CREATE
|
|
30
|
+
// SCHEMA anyway; `information_schema` would not, and `drizzle` is where a
|
|
31
|
+
// deployment on the default schema keeps its migration ledger, so a
|
|
32
|
+
// knowledge base placed there would share that ledger's home.
|
|
33
|
+
if (name.startsWith('pg_') || name === 'information_schema' || name === 'drizzle') {
|
|
34
|
+
throw new Error(`Database schema name "${name}" is reserved`);
|
|
35
|
+
}
|
|
36
|
+
return name;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Prove that this handle's connections really search `schema` first, by
|
|
40
|
+
* asking the server. The schema is set as a startup parameter, and a
|
|
41
|
+
* transaction- or statement-mode pooler in front of the database (PgBouncer
|
|
42
|
+
* in those modes, RDS Proxy) either refuses that parameter or resets it
|
|
43
|
+
* between transactions; every unqualified table name would then resolve to
|
|
44
|
+
* `public`, and tenants would read each other's rows without a single
|
|
45
|
+
* error. So a graph refuses to come up on a handle that lost its schema,
|
|
46
|
+
* which is the failure an operator can see. Only session pooling is
|
|
47
|
+
* supported in front of a process that serves several knowledge bases.
|
|
48
|
+
*/
|
|
49
|
+
export async function assertSearchPath(db, schema) {
|
|
50
|
+
const result = await db.execute(sql `select current_schema() as schema`);
|
|
51
|
+
const current = result.rows[0]?.schema ?? null;
|
|
52
|
+
if (current !== schema) {
|
|
53
|
+
throw new Error(`Database connections search "${current ?? '(none)'}" first, not the configured schema "${schema}". ` +
|
|
54
|
+
'A transaction-mode pooler in front of Postgres drops the search_path startup parameter; ' +
|
|
55
|
+
'use session pooling, or connect directly.');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A bounded handshake: `pg` waits forever by default for a NEW connection to
|
|
60
|
+
* come up, so a database that accepts the socket and never finishes the
|
|
61
|
+
* handshake would hold a boot (the migration lock is the first thing that
|
|
62
|
+
* asks) with nothing to say and nothing for the restart policy to see. Half
|
|
63
|
+
* a minute is generous for a handshake and short enough for a failed boot to
|
|
64
|
+
* be visible. It bounds only that: a checkout queued behind a saturated pool,
|
|
65
|
+
* or a query on a connection that stopped answering, is the caller's to
|
|
66
|
+
* bound — the advisory lock does.
|
|
67
|
+
*/
|
|
68
|
+
const CONNECT_TIMEOUT_MS = 30_000;
|
|
69
|
+
/**
|
|
70
|
+
* A NEW pool on `databaseUrl`, searching `opts.schema` first. Not cached:
|
|
71
|
+
* the caller owns it and ends it with {@link closeDb}. The composition root
|
|
72
|
+
* of a process that serves one knowledge base goes through {@link getDb}
|
|
73
|
+
* instead, which caches.
|
|
74
|
+
*/
|
|
75
|
+
export function createDb(databaseUrl, opts = {}) {
|
|
76
|
+
const dbSchema = assertSchemaName(opts.schema ?? DEFAULT_DB_SCHEMA);
|
|
77
|
+
const pool = new pg.Pool({
|
|
78
|
+
connectionString: databaseUrl,
|
|
79
|
+
connectionTimeoutMillis: CONNECT_TIMEOUT_MS,
|
|
80
|
+
max: opts.max,
|
|
81
|
+
idleTimeoutMillis: opts.idleTimeoutMillis,
|
|
82
|
+
// A startup parameter, applied by the server to every connection this
|
|
83
|
+
// pool opens — not a `SET` run after connecting, which a pooled
|
|
84
|
+
// connection could outlive. The default schema sets nothing, so an
|
|
85
|
+
// operator's own `search_path` stays in force there.
|
|
86
|
+
...(dbSchema === DEFAULT_DB_SCHEMA ? {} : { options: `-c search_path=${dbSchema}` }),
|
|
87
|
+
});
|
|
88
|
+
const db = drizzle(pool, { schema });
|
|
89
|
+
schemas.set(db, dbSchema);
|
|
90
|
+
return db;
|
|
91
|
+
}
|
|
92
|
+
/** The schema a database handle searches first — for the callers that name it in DDL. */
|
|
93
|
+
export function dbSchemaOf(db) {
|
|
94
|
+
return schemas.get(db) ?? DEFAULT_DB_SCHEMA;
|
|
95
|
+
}
|
|
96
|
+
const schemas = new WeakMap();
|
|
97
|
+
const cache = new Map();
|
|
98
|
+
const cacheKey = (databaseUrl, dbSchema) => `${dbSchema}\u0000${databaseUrl}`;
|
|
99
|
+
/**
|
|
100
|
+
* The process's pool on `databaseUrl` for `opts.schema`, created on first
|
|
101
|
+
* use and shared afterwards. One per (url, schema): two handles on the same
|
|
102
|
+
* schema would be two pools competing for the same connection budget.
|
|
103
|
+
*/
|
|
104
|
+
export function getDb(databaseUrl, opts = {}) {
|
|
105
|
+
const dbSchema = assertSchemaName(opts.schema ?? DEFAULT_DB_SCHEMA);
|
|
106
|
+
const key = cacheKey(databaseUrl, dbSchema);
|
|
107
|
+
let db = cache.get(key);
|
|
6
108
|
if (!db) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// the handshake would hold a boot (the migration lock is the first thing
|
|
10
|
-
// that asks) with nothing to say and nothing for the restart policy to
|
|
11
|
-
// see. Half a minute is generous for a handshake and short enough for a
|
|
12
|
-
// failed boot to be visible. It bounds only that: a checkout queued
|
|
13
|
-
// behind a saturated pool, or a query on a connection that stopped
|
|
14
|
-
// answering, is the caller's to bound — the advisory lock does.
|
|
15
|
-
const pool = new pg.Pool({ connectionString: databaseUrl, connectionTimeoutMillis: 30_000 });
|
|
16
|
-
db = drizzle(pool, { schema });
|
|
109
|
+
db = createDb(databaseUrl, opts);
|
|
110
|
+
cache.set(key, db);
|
|
17
111
|
}
|
|
18
112
|
return db;
|
|
19
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* End a handle's pool and forget it, so a later {@link getDb} for the same
|
|
116
|
+
* schema opens a fresh one rather than handing out a pool that was ended.
|
|
117
|
+
* The last step of stopping a knowledge base's graph.
|
|
118
|
+
*/
|
|
119
|
+
export async function closeDb(db) {
|
|
120
|
+
for (const [key, cached] of cache) {
|
|
121
|
+
if (cached === db)
|
|
122
|
+
cache.delete(key);
|
|
123
|
+
}
|
|
124
|
+
await db.$client.end();
|
|
125
|
+
}
|
|
20
126
|
//# sourceMappingURL=connection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/modules/database/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/modules/database/connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Database } from './connection.js';
|
|
2
2
|
/** Apply the CORE migration history from `folder`, tracked in `__drizzle_migrations_core`. */
|
|
3
3
|
export declare function runCoreMigrations(db: Database, folder: string): Promise<void>;
|
|
4
4
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAyD/E,8FAA8F;AAC9F,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYnF;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBzF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
2
2
|
import { logger } from '../../shared/logging.js';
|
|
3
3
|
const log = logger('database');
|
|
4
|
+
import { DEFAULT_DB_SCHEMA, dbSchemaOf } from './connection.js';
|
|
4
5
|
import { AdvisoryLock, withAdvisoryLock } from './advisory-lock.js';
|
|
5
6
|
/*
|
|
6
7
|
* ── Per-tier migration folders ──────────────────────────────────────────────
|
|
@@ -34,13 +35,34 @@ import { AdvisoryLock, withAdvisoryLock } from './advisory-lock.js';
|
|
|
34
35
|
* is not hypothetical here — it is every redeploy, for as long as the outgoing
|
|
35
36
|
* container takes to exit. See `advisory-lock.ts` for the mechanism.
|
|
36
37
|
*/
|
|
38
|
+
/**
|
|
39
|
+
* Where a handle's migration ledger lives, and which lock guards its runs.
|
|
40
|
+
*
|
|
41
|
+
* The default schema keeps drizzle's own `drizzle` schema for the ledger,
|
|
42
|
+
* where every existing deployment already has one: naming `public` here
|
|
43
|
+
* would make the next boot read an empty ledger and re-apply plain DDL that
|
|
44
|
+
* is already applied. A knowledge base on a schema of its own keeps its
|
|
45
|
+
* ledger IN that schema, so the schema is the whole of the tenant: what
|
|
46
|
+
* `pg_dump -n` carries out includes what has been applied to it, and the
|
|
47
|
+
* dedicated deployment it is restored into resumes from there rather than
|
|
48
|
+
* from nothing. The lock is keyed the same way, so two tenants of one
|
|
49
|
+
* database migrate side by side while two processes of one tenant still
|
|
50
|
+
* take turns.
|
|
51
|
+
*/
|
|
52
|
+
function ledgerOptions(db) {
|
|
53
|
+
const schema = dbSchemaOf(db);
|
|
54
|
+
return schema === DEFAULT_DB_SCHEMA
|
|
55
|
+
? { tenantKey: '' }
|
|
56
|
+
: { migrationsSchema: schema, tenantKey: schema };
|
|
57
|
+
}
|
|
37
58
|
/** Apply the CORE migration history from `folder`, tracked in `__drizzle_migrations_core`. */
|
|
38
59
|
export async function runCoreMigrations(db, folder) {
|
|
60
|
+
const { migrationsSchema, tenantKey } = ledgerOptions(db);
|
|
39
61
|
await withAdvisoryLock(db, AdvisoryLock.Migrations, async () => {
|
|
40
62
|
log.info('Running core database migrations...');
|
|
41
|
-
await migrate(db, { migrationsFolder: folder, migrationsTable: '__drizzle_migrations_core' });
|
|
63
|
+
await migrate(db, { migrationsFolder: folder, migrationsTable: '__drizzle_migrations_core', migrationsSchema });
|
|
42
64
|
log.info('Core migrations complete.');
|
|
43
|
-
});
|
|
65
|
+
}, { tenantKey });
|
|
44
66
|
}
|
|
45
67
|
/**
|
|
46
68
|
* Apply the ENTERPRISE migration history from `folder`, tracked in
|
|
@@ -48,13 +70,15 @@ export async function runCoreMigrations(db, folder) {
|
|
|
48
70
|
* enterprise tables FK into core tables.
|
|
49
71
|
*/
|
|
50
72
|
export async function runEnterpriseMigrations(db, folder) {
|
|
73
|
+
const { migrationsSchema, tenantKey } = ledgerOptions(db);
|
|
51
74
|
await withAdvisoryLock(db, AdvisoryLock.Migrations, async () => {
|
|
52
75
|
log.info('Running enterprise database migrations...');
|
|
53
76
|
await migrate(db, {
|
|
54
77
|
migrationsFolder: folder,
|
|
55
78
|
migrationsTable: '__drizzle_migrations_enterprise',
|
|
79
|
+
migrationsSchema,
|
|
56
80
|
});
|
|
57
81
|
log.info('Enterprise migrations complete.');
|
|
58
|
-
});
|
|
82
|
+
}, { tenantKey });
|
|
59
83
|
}
|
|
60
84
|
//# sourceMappingURL=migrate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;;;;;GAaG;AACH,SAAS,aAAa,CAAC,EAAY;IACjC,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAC9B,OAAO,MAAM,KAAK,iBAAiB;QACjC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;QACnB,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAY,EAAE,MAAc;IAClE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,gBAAgB,CACpB,EAAE,EACF,YAAY,CAAC,UAAU,EACvB,KAAK,IAAI,EAAE;QACT,GAAG,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QAChD,MAAM,OAAO,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAChH,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACxC,CAAC,EACD,EAAE,SAAS,EAAE,CACd,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAAY,EAAE,MAAc;IACxE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,gBAAgB,CACpB,EAAE,EACF,YAAY,CAAC,UAAU,EACvB,KAAK,IAAI,EAAE;QACT,GAAG,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QACtD,MAAM,OAAO,CAAC,EAAE,EAAE;YAChB,gBAAgB,EAAE,MAAM;YACxB,eAAe,EAAE,iCAAiC;YAClD,gBAAgB;SACjB,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,CAAC,EACD,EAAE,SAAS,EAAE,CACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** A GitHub App's identity and keys, as GitHub issued them. */
|
|
2
|
+
export interface GitHubAppCredentials {
|
|
3
|
+
appId: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
/** PEM. */
|
|
6
|
+
privateKey: string;
|
|
7
|
+
clientId: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
}
|
|
10
|
+
/** What GitHub hands back when an app is created from a manifest. */
|
|
11
|
+
export interface RegisteredApp extends GitHubAppCredentials {
|
|
12
|
+
/** The account that owns the app. */
|
|
13
|
+
owner: string;
|
|
14
|
+
htmlUrl: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Installation {
|
|
17
|
+
id: string;
|
|
18
|
+
/** The user or organisation it is installed on. */
|
|
19
|
+
account: string;
|
|
20
|
+
/** `all`, or `selected` when the admin chose repositories. */
|
|
21
|
+
repositorySelection: string;
|
|
22
|
+
}
|
|
23
|
+
export interface InstallationToken {
|
|
24
|
+
token: string;
|
|
25
|
+
/** Epoch milliseconds. */
|
|
26
|
+
expiresAt: number;
|
|
27
|
+
}
|
|
28
|
+
export interface InstallationRepository {
|
|
29
|
+
/** `owner/name`. */
|
|
30
|
+
fullName: string;
|
|
31
|
+
private: boolean;
|
|
32
|
+
defaultBranch: string;
|
|
33
|
+
/** Whether the installation may push to it. */
|
|
34
|
+
writable: boolean;
|
|
35
|
+
}
|
|
36
|
+
export type GitHubFailureKind = 'unreachable' | 'refused' | 'not-found' | 'unexpected';
|
|
37
|
+
/** A call to GitHub that did not give what was asked. The message never carries a credential. */
|
|
38
|
+
export declare class GitHubAppError extends Error {
|
|
39
|
+
readonly kind: GitHubFailureKind;
|
|
40
|
+
readonly status: number;
|
|
41
|
+
constructor(kind: GitHubFailureKind, message: string, status?: number);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A private key as an operator is likely to have supplied it: the PEM
|
|
45
|
+
* itself, the PEM with its line breaks written as `\n` (the only way most
|
|
46
|
+
* environment files can hold it), or the PEM in base64.
|
|
47
|
+
*/
|
|
48
|
+
export declare function normalizePrivateKey(raw: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* The JWT an app presents to GitHub as itself: RS256 over its id, good for
|
|
51
|
+
* a few minutes. Issued a minute in the past, as GitHub advises, so a clock
|
|
52
|
+
* that runs slightly ahead of theirs is not refused.
|
|
53
|
+
*/
|
|
54
|
+
export declare function appJwt(credentials: Pick<GitHubAppCredentials, 'appId' | 'privateKey'>, now?: number): string;
|
|
55
|
+
/**
|
|
56
|
+
* What the deployment asks of GitHub, as a GitHub App: every call it makes,
|
|
57
|
+
* and nothing that decides anything. Injected with `fetch` so suites answer
|
|
58
|
+
* for GitHub.
|
|
59
|
+
*/
|
|
60
|
+
export declare class GitHubAppClient {
|
|
61
|
+
private readonly fetchImpl;
|
|
62
|
+
private readonly now;
|
|
63
|
+
/** How long one request to GitHub may take. */
|
|
64
|
+
private readonly timeoutMs;
|
|
65
|
+
constructor(fetchImpl?: typeof fetch, now?: () => number,
|
|
66
|
+
/** How long one request to GitHub may take. */
|
|
67
|
+
timeoutMs?: number);
|
|
68
|
+
/** The app GitHub created from a manifest, for the code it sent the browser back with. Good once, for an hour. */
|
|
69
|
+
convertManifest(code: string): Promise<RegisteredApp>;
|
|
70
|
+
/**
|
|
71
|
+
* A token for the PERSON who has just come back from GitHub, in exchange
|
|
72
|
+
* for the code they came back with. Used for one question (see
|
|
73
|
+
* {@link installationsOf}) and then dropped.
|
|
74
|
+
*/
|
|
75
|
+
exchangeUserCode(credentials: Pick<GitHubAppCredentials, 'clientId' | 'clientSecret'>, code: string): Promise<string>;
|
|
76
|
+
/** The installations of this app that the person holding `userToken` can reach. */
|
|
77
|
+
installationsOf(userToken: string): Promise<Installation[]>;
|
|
78
|
+
/** One installation, asked for as the app. */
|
|
79
|
+
installation(credentials: GitHubAppCredentials, id: string): Promise<Installation>;
|
|
80
|
+
/** A token for the installation: what git presents. Good for an hour. */
|
|
81
|
+
installationToken(credentials: GitHubAppCredentials, id: string): Promise<InstallationToken>;
|
|
82
|
+
/** The repositories the installation reaches, and whether the list was cut short. */
|
|
83
|
+
repositories(installationToken: string): Promise<{
|
|
84
|
+
repositories: InstallationRepository[];
|
|
85
|
+
more: boolean;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* The repositories of an installation that THE PERSON holding `userToken`
|
|
89
|
+
* reaches, each with that person's own permissions: `writable` is whether
|
|
90
|
+
* they may push to it, which is another question from whether the
|
|
91
|
+
* installation may. An installation the person does not reach at all is
|
|
92
|
+
* GitHub's to refuse.
|
|
93
|
+
*/
|
|
94
|
+
repositoriesOf(userToken: string, installationId: string): Promise<{
|
|
95
|
+
repositories: InstallationRepository[];
|
|
96
|
+
more: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
private listRepositories;
|
|
99
|
+
private call;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=github-app.client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-app.client.d.ts","sourceRoot":"","sources":["../../../src/modules/github-app/github-app.client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createSign } from 'node:crypto';
|
|
2
|
+
/** A call to GitHub that did not give what was asked. The message never carries a credential. */
|
|
3
|
+
export class GitHubAppError extends Error {
|
|
4
|
+
kind;
|
|
5
|
+
status;
|
|
6
|
+
constructor(kind, message, status = 0) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.kind = kind;
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.name = 'GitHubAppError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const API = 'https://api.github.com';
|
|
14
|
+
const WEB = 'https://github.com';
|
|
15
|
+
const API_VERSION = '2022-11-28';
|
|
16
|
+
/** Generous for an API that answers in a fraction of a second, short for something git is waiting on. */
|
|
17
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
18
|
+
/** Repositories listed per installation before the list is said to be cut short. */
|
|
19
|
+
const MAX_REPOSITORIES = 500;
|
|
20
|
+
/**
|
|
21
|
+
* A private key as an operator is likely to have supplied it: the PEM
|
|
22
|
+
* itself, the PEM with its line breaks written as `\n` (the only way most
|
|
23
|
+
* environment files can hold it), or the PEM in base64.
|
|
24
|
+
*/
|
|
25
|
+
export function normalizePrivateKey(raw) {
|
|
26
|
+
const value = raw.trim();
|
|
27
|
+
if (value.includes('-----BEGIN'))
|
|
28
|
+
return value.replace(/\\n/g, '\n');
|
|
29
|
+
try {
|
|
30
|
+
const decoded = Buffer.from(value, 'base64').toString('utf8');
|
|
31
|
+
if (decoded.includes('-----BEGIN'))
|
|
32
|
+
return decoded.trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Not base64: handed on as it is, and the signing says what is wrong with it.
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The JWT an app presents to GitHub as itself: RS256 over its id, good for
|
|
41
|
+
* a few minutes. Issued a minute in the past, as GitHub advises, so a clock
|
|
42
|
+
* that runs slightly ahead of theirs is not refused.
|
|
43
|
+
*/
|
|
44
|
+
export function appJwt(credentials, now = Date.now()) {
|
|
45
|
+
const seconds = Math.floor(now / 1000);
|
|
46
|
+
const part = (value) => Buffer.from(JSON.stringify(value), 'utf8').toString('base64url');
|
|
47
|
+
const body = `${part({ alg: 'RS256', typ: 'JWT' })}.${part({ iat: seconds - 60, exp: seconds + 9 * 60, iss: credentials.appId })}`;
|
|
48
|
+
let signature;
|
|
49
|
+
try {
|
|
50
|
+
signature = createSign('RSA-SHA256').update(body).end().sign(normalizePrivateKey(credentials.privateKey), 'base64url');
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// What the key was is never quoted.
|
|
54
|
+
throw new GitHubAppError('refused', 'The GitHub App private key could not be read. It must be the PEM GitHub issued.');
|
|
55
|
+
}
|
|
56
|
+
return `${body}.${signature}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* What the deployment asks of GitHub, as a GitHub App: every call it makes,
|
|
60
|
+
* and nothing that decides anything. Injected with `fetch` so suites answer
|
|
61
|
+
* for GitHub.
|
|
62
|
+
*/
|
|
63
|
+
export class GitHubAppClient {
|
|
64
|
+
fetchImpl;
|
|
65
|
+
now;
|
|
66
|
+
timeoutMs;
|
|
67
|
+
constructor(fetchImpl = fetch, now = Date.now,
|
|
68
|
+
/** How long one request to GitHub may take. */
|
|
69
|
+
timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
70
|
+
this.fetchImpl = fetchImpl;
|
|
71
|
+
this.now = now;
|
|
72
|
+
this.timeoutMs = timeoutMs;
|
|
73
|
+
}
|
|
74
|
+
/** The app GitHub created from a manifest, for the code it sent the browser back with. Good once, for an hour. */
|
|
75
|
+
async convertManifest(code) {
|
|
76
|
+
const body = await this.call(`${API}/app-manifests/${encodeURIComponent(code)}/conversions`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
});
|
|
79
|
+
const owner = body.owner?.login;
|
|
80
|
+
const app = {
|
|
81
|
+
appId: String(body.id ?? ''),
|
|
82
|
+
slug: String(body.slug ?? ''),
|
|
83
|
+
privateKey: String(body.pem ?? ''),
|
|
84
|
+
clientId: String(body.client_id ?? ''),
|
|
85
|
+
clientSecret: String(body.client_secret ?? ''),
|
|
86
|
+
owner: typeof owner === 'string' ? owner : '',
|
|
87
|
+
htmlUrl: String(body.html_url ?? ''),
|
|
88
|
+
};
|
|
89
|
+
if (!app.appId || !app.slug || !app.privateKey || !app.clientId || !app.clientSecret) {
|
|
90
|
+
throw new GitHubAppError('unexpected', 'GitHub created the app but did not return its keys.');
|
|
91
|
+
}
|
|
92
|
+
return app;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A token for the PERSON who has just come back from GitHub, in exchange
|
|
96
|
+
* for the code they came back with. Used for one question (see
|
|
97
|
+
* {@link installationsOf}) and then dropped.
|
|
98
|
+
*/
|
|
99
|
+
async exchangeUserCode(credentials, code) {
|
|
100
|
+
const body = await this.call(`${WEB}/login/oauth/access_token`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
|
+
body: JSON.stringify({ client_id: credentials.clientId, client_secret: credentials.clientSecret, code }),
|
|
104
|
+
});
|
|
105
|
+
// GitHub answers a refused exchange with 200 and an `error` field.
|
|
106
|
+
if (typeof body.access_token !== 'string' || !body.access_token) {
|
|
107
|
+
throw new GitHubAppError('refused', 'GitHub did not accept the sign-in that came back with the installation.');
|
|
108
|
+
}
|
|
109
|
+
return body.access_token;
|
|
110
|
+
}
|
|
111
|
+
/** The installations of this app that the person holding `userToken` can reach. */
|
|
112
|
+
async installationsOf(userToken) {
|
|
113
|
+
const found = [];
|
|
114
|
+
for (let page = 1; page <= 10; page += 1) {
|
|
115
|
+
const body = await this.call(`${API}/user/installations?per_page=100&page=${page}`, {
|
|
116
|
+
headers: { Authorization: `Bearer ${userToken}` },
|
|
117
|
+
});
|
|
118
|
+
const batch = Array.isArray(body.installations) ? body.installations : [];
|
|
119
|
+
for (const item of batch)
|
|
120
|
+
found.push(installationOf(item));
|
|
121
|
+
if (batch.length < 100)
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
return found;
|
|
125
|
+
}
|
|
126
|
+
/** One installation, asked for as the app. */
|
|
127
|
+
async installation(credentials, id) {
|
|
128
|
+
const body = await this.call(`${API}/app/installations/${encodeURIComponent(id)}`, {
|
|
129
|
+
headers: { Authorization: `Bearer ${appJwt(credentials, this.now())}` },
|
|
130
|
+
});
|
|
131
|
+
return installationOf(body);
|
|
132
|
+
}
|
|
133
|
+
/** A token for the installation: what git presents. Good for an hour. */
|
|
134
|
+
async installationToken(credentials, id) {
|
|
135
|
+
const body = await this.call(`${API}/app/installations/${encodeURIComponent(id)}/access_tokens`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { Authorization: `Bearer ${appJwt(credentials, this.now())}` },
|
|
138
|
+
});
|
|
139
|
+
const expiresAt = Date.parse(String(body.expires_at ?? ''));
|
|
140
|
+
if (typeof body.token !== 'string' || !body.token || Number.isNaN(expiresAt)) {
|
|
141
|
+
throw new GitHubAppError('unexpected', 'GitHub did not return a token for the installation.');
|
|
142
|
+
}
|
|
143
|
+
return { token: body.token, expiresAt };
|
|
144
|
+
}
|
|
145
|
+
/** The repositories the installation reaches, and whether the list was cut short. */
|
|
146
|
+
repositories(installationToken) {
|
|
147
|
+
return this.listRepositories(`${API}/installation/repositories`, installationToken);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The repositories of an installation that THE PERSON holding `userToken`
|
|
151
|
+
* reaches, each with that person's own permissions: `writable` is whether
|
|
152
|
+
* they may push to it, which is another question from whether the
|
|
153
|
+
* installation may. An installation the person does not reach at all is
|
|
154
|
+
* GitHub's to refuse.
|
|
155
|
+
*/
|
|
156
|
+
repositoriesOf(userToken, installationId) {
|
|
157
|
+
return this.listRepositories(`${API}/user/installations/${encodeURIComponent(installationId)}/repositories`, userToken);
|
|
158
|
+
}
|
|
159
|
+
async listRepositories(url, token) {
|
|
160
|
+
const repositories = [];
|
|
161
|
+
let total = 0;
|
|
162
|
+
for (let page = 1; repositories.length < MAX_REPOSITORIES; page += 1) {
|
|
163
|
+
const body = await this.call(`${url}?per_page=100&page=${page}`, { headers: { Authorization: `Bearer ${token}` } });
|
|
164
|
+
total = typeof body.total_count === 'number' ? body.total_count : total;
|
|
165
|
+
const batch = Array.isArray(body.repositories) ? body.repositories : [];
|
|
166
|
+
for (const item of batch) {
|
|
167
|
+
const repo = item;
|
|
168
|
+
if (typeof repo.full_name !== 'string')
|
|
169
|
+
continue;
|
|
170
|
+
repositories.push({
|
|
171
|
+
fullName: repo.full_name,
|
|
172
|
+
private: repo.private === true,
|
|
173
|
+
defaultBranch: typeof repo.default_branch === 'string' ? repo.default_branch : '',
|
|
174
|
+
writable: repo.permissions?.push === true,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (batch.length < 100)
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
repositories.sort((a, b) => a.fullName.localeCompare(b.fullName));
|
|
181
|
+
return { repositories, more: total > repositories.length };
|
|
182
|
+
}
|
|
183
|
+
async call(url, init) {
|
|
184
|
+
let res;
|
|
185
|
+
try {
|
|
186
|
+
res = await this.fetchImpl(url, {
|
|
187
|
+
...init,
|
|
188
|
+
// A deadline of ours: left to the platform, a host that accepts
|
|
189
|
+
// the connection and says nothing is waited on for minutes, by
|
|
190
|
+
// whatever was waiting on this call.
|
|
191
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
192
|
+
headers: {
|
|
193
|
+
Accept: 'application/vnd.github+json',
|
|
194
|
+
'X-GitHub-Api-Version': API_VERSION,
|
|
195
|
+
'User-Agent': 'hexis',
|
|
196
|
+
...init.headers,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
throw new GitHubAppError('unreachable', `GitHub could not be reached: ${err instanceof Error ? err.message : String(err)}`);
|
|
202
|
+
}
|
|
203
|
+
if (!res.ok) {
|
|
204
|
+
// GitHub's own words name the cause (a permission, a suspended app) and carry no credential of ours.
|
|
205
|
+
const said = (await res.json().catch(() => ({}))).message;
|
|
206
|
+
const detail = typeof said === 'string' && said ? `: ${said.slice(0, 200)}` : '';
|
|
207
|
+
const kind = res.status === 404 ? 'not-found' : res.status === 401 || res.status === 403 ? 'refused' : 'unexpected';
|
|
208
|
+
throw new GitHubAppError(kind, `GitHub answered ${res.status}${detail}`, res.status);
|
|
209
|
+
}
|
|
210
|
+
return (await res.json().catch(() => ({})));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function installationOf(raw) {
|
|
214
|
+
const item = (raw ?? {});
|
|
215
|
+
const account = item.account?.login;
|
|
216
|
+
return {
|
|
217
|
+
id: String(item.id ?? ''),
|
|
218
|
+
account: typeof account === 'string' ? account : '',
|
|
219
|
+
repositorySelection: typeof item.repository_selection === 'string' ? item.repository_selection : '',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=github-app.client.js.map
|