@capybara-hq/kernel 0.1.0-rc.3 → 0.1.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bootstrap.json +61 -5
- package/dist/admin/admin.controller.d.ts +47 -16
- package/dist/admin/admin.controller.js +44 -19
- package/dist/admin/extensions.controller.d.ts +24 -3
- package/dist/admin/extensions.controller.js +48 -8
- package/dist/admin/setup-lock.d.ts +1 -1
- package/dist/admin/setup-lock.js +1 -1
- package/dist/admin/setup.controller.d.ts +1 -1
- package/dist/admin/setup.controller.js +1 -1
- package/dist/admin/setup.service.d.ts +4 -4
- package/dist/admin/setup.service.js +8 -8
- package/dist/agents/agent-lookup.d.ts +19 -0
- package/dist/agents/agent-lookup.js +21 -0
- package/dist/agents/agent-profile.service.d.ts +29 -0
- package/dist/agents/agent-profile.service.js +117 -0
- package/dist/agents/agents.controller.d.ts +168 -3
- package/dist/agents/agents.controller.js +201 -12
- package/dist/agents/agents.module.d.ts +4 -1
- package/dist/agents/agents.module.js +36 -6
- package/dist/agents/agents.service.d.ts +64 -27
- package/dist/agents/agents.service.js +199 -74
- package/dist/agents/definition.d.ts +53 -0
- package/dist/agents/definition.js +55 -0
- package/dist/agents/from-template.d.ts +106 -0
- package/dist/agents/from-template.js +649 -0
- package/dist/agents/from-template.service.d.ts +60 -0
- package/dist/agents/from-template.service.js +161 -0
- package/dist/agents/instruction-files.d.ts +60 -0
- package/dist/agents/instruction-files.js +111 -0
- package/dist/agents/models.controller.d.ts +9 -3
- package/dist/agents/models.controller.js +19 -4
- package/dist/agents/org-templates.d.ts +176 -0
- package/dist/agents/org-templates.js +827 -0
- package/dist/agents/pending-connector-requests.d.ts +77 -0
- package/dist/agents/pending-connector-requests.js +215 -0
- package/dist/agents/pending-connectors.controller.d.ts +39 -0
- package/dist/agents/pending-connectors.controller.js +91 -0
- package/dist/agents/pending-connectors.service.d.ts +62 -0
- package/dist/agents/pending-connectors.service.js +282 -0
- package/dist/agents/profile.d.ts +96 -0
- package/dist/agents/profile.js +51 -0
- package/dist/agents/readiness.controller.d.ts +26 -0
- package/dist/agents/readiness.controller.js +56 -0
- package/dist/agents/templates.controller.d.ts +86 -5
- package/dist/agents/templates.controller.js +171 -7
- package/dist/agents/templates.d.ts +127 -23
- package/dist/agents/templates.js +476 -53
- package/dist/background/background.controller.d.ts +38 -0
- package/dist/background/background.controller.js +87 -0
- package/dist/background/background.module.d.ts +10 -0
- package/dist/background/background.module.js +39 -0
- package/dist/background/finish.d.ts +44 -0
- package/dist/background/finish.js +94 -0
- package/dist/background/launch-lock.d.ts +15 -0
- package/dist/background/launch-lock.js +40 -0
- package/dist/background/launch.d.ts +36 -0
- package/dist/background/launch.js +70 -0
- package/dist/background/poll.job.d.ts +56 -0
- package/dist/background/poll.job.js +190 -0
- package/dist/background/render.d.ts +23 -0
- package/dist/background/render.js +48 -0
- package/dist/background/session.d.ts +48 -0
- package/dist/background/session.js +79 -0
- package/dist/background/status.d.ts +35 -0
- package/dist/background/status.js +57 -0
- package/dist/background/stop.d.ts +68 -0
- package/dist/background/stop.js +243 -0
- package/dist/background/store.d.ts +162 -0
- package/dist/background/store.js +357 -0
- package/dist/background/store.module.d.ts +6 -0
- package/dist/background/store.module.js +22 -0
- package/dist/background/tasks.service.d.ts +77 -0
- package/dist/background/tasks.service.js +211 -0
- package/dist/background/wake-rules.d.ts +66 -0
- package/dist/background/wake-rules.js +113 -0
- package/dist/background/wake.d.ts +30 -0
- package/dist/background/wake.js +63 -0
- package/dist/catalog/admin-catalog.controller.d.ts +129 -30
- package/dist/catalog/admin-catalog.controller.js +213 -42
- package/dist/catalog/catalog-content.d.ts +58 -32
- package/dist/catalog/catalog-content.js +34 -8
- package/dist/catalog/catalog-import.module.d.ts +7 -0
- package/dist/catalog/catalog-import.module.js +60 -0
- package/dist/catalog/catalog-items.d.ts +111 -7
- package/dist/catalog/catalog-items.js +279 -13
- package/dist/catalog/catalog-scope.service.d.ts +260 -0
- package/dist/catalog/catalog-scope.service.js +1116 -0
- package/dist/catalog/catalog.module.d.ts +7 -9
- package/dist/catalog/catalog.module.js +41 -31
- package/dist/catalog/catalog.service.d.ts +101 -29
- package/dist/catalog/catalog.service.js +104 -106
- package/dist/catalog/claude/agents.js +2 -0
- package/dist/catalog/cli.d.ts +11 -1
- package/dist/catalog/cli.js +26 -1
- package/dist/catalog/component-promotion.d.ts +96 -0
- package/dist/catalog/component-promotion.js +395 -0
- package/dist/catalog/component-scope.controller.d.ts +152 -0
- package/dist/catalog/component-scope.controller.js +287 -0
- package/dist/catalog/component-scope.service.d.ts +303 -0
- package/dist/catalog/component-scope.service.js +936 -0
- package/dist/catalog/component-state.d.ts +174 -0
- package/dist/catalog/component-state.js +437 -0
- package/dist/catalog/job-ids.d.ts +30 -0
- package/dist/catalog/job-ids.js +25 -0
- package/dist/catalog/marketplace-fetch.d.ts +1 -1
- package/dist/catalog/marketplaces.controller.d.ts +22 -5
- package/dist/catalog/marketplaces.controller.js +56 -7
- package/dist/catalog/marketplaces.service.d.ts +54 -14
- package/dist/catalog/marketplaces.service.js +71 -22
- package/dist/catalog/org-catalog.controller.d.ts +125 -34
- package/dist/catalog/org-catalog.controller.js +181 -65
- package/dist/catalog/org-catalog.service.d.ts +65 -33
- package/dist/catalog/org-catalog.service.js +324 -157
- package/dist/catalog/org-extension-switch.d.ts +41 -0
- package/dist/catalog/org-extension-switch.js +115 -0
- package/dist/catalog/org-extension.controller.d.ts +119 -0
- package/dist/catalog/org-extension.controller.js +266 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +98 -0
- package/dist/catalog/org-plugin-uploads.controller.js +213 -0
- package/dist/catalog/org-plugin-uploads.d.ts +63 -0
- package/dist/catalog/org-plugin-uploads.js +116 -0
- package/dist/catalog/owned-items.d.ts +184 -0
- package/dist/catalog/owned-items.js +789 -0
- package/dist/catalog/owned-plugin-cleanup.d.ts +56 -0
- package/dist/catalog/owned-plugin-cleanup.js +194 -0
- package/dist/catalog/ownership.d.ts +172 -0
- package/dist/catalog/ownership.js +326 -0
- package/dist/catalog/platform-components.d.ts +221 -0
- package/dist/catalog/platform-components.js +761 -0
- package/dist/catalog/platform-migration.d.ts +115 -0
- package/dist/catalog/platform-migration.js +582 -0
- package/dist/catalog/plugin-import.d.ts +178 -34
- package/dist/catalog/plugin-import.js +623 -83
- package/dist/catalog/plugin-install.d.ts +185 -41
- package/dist/catalog/plugin-install.js +758 -126
- package/dist/catalog/plugin-upgrade.d.ts +260 -225
- package/dist/catalog/plugin-upgrade.js +1148 -1137
- package/dist/catalog/request-rules.d.ts +65 -0
- package/dist/catalog/request-rules.js +217 -0
- package/dist/catalog/requests.service.d.ts +193 -118
- package/dist/catalog/requests.service.js +526 -343
- package/dist/catalog/reserved-names.d.ts +8 -0
- package/dist/catalog/reserved-names.js +42 -0
- package/dist/catalog/scope-orgs.d.ts +21 -0
- package/dist/catalog/scope-orgs.js +67 -0
- package/dist/catalog/scope-state.d.ts +35 -0
- package/dist/catalog/scope-state.js +87 -0
- package/dist/catalog/scope-sync-workers.d.ts +7 -0
- package/dist/catalog/scope-sync-workers.js +29 -0
- package/dist/catalog/scope-sync.d.ts +176 -0
- package/dist/catalog/scope-sync.js +576 -0
- package/dist/catalog/scope.d.ts +42 -0
- package/dist/catalog/scope.js +42 -0
- package/dist/catalog/unshare.d.ts +22 -0
- package/dist/catalog/unshare.js +118 -0
- package/dist/channels/actions.js +1 -0
- package/dist/channels/cards.js +21 -3
- package/dist/channels/channels.module.js +2 -0
- package/dist/channels/connections.service.d.ts +16 -1
- package/dist/channels/connections.service.js +38 -4
- package/dist/channels/inbound.d.ts +9 -1
- package/dist/channels/inbound.js +67 -5
- package/dist/channels/phrases.d.ts +35 -0
- package/dist/channels/phrases.js +29 -0
- package/dist/channels/threads.d.ts +5 -0
- package/dist/channels/threads.js +8 -0
- package/dist/config/docs.js +3 -1
- package/dist/config/schema.d.ts +24 -2
- package/dist/config/schema.js +145 -19
- package/dist/conversations/access.d.ts +6 -4
- package/dist/conversations/access.js +29 -5
- package/dist/conversations/agent-tree.d.ts +46 -0
- package/dist/conversations/agent-tree.js +92 -0
- package/dist/conversations/attachments.service.d.ts +30 -0
- package/dist/conversations/attachments.service.js +130 -5
- package/dist/conversations/conversations.controller.d.ts +79 -23
- package/dist/conversations/conversations.controller.js +141 -50
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +10 -7
- package/dist/conversations/conversations.service.d.ts +108 -9
- package/dist/conversations/conversations.service.js +237 -30
- package/dist/conversations/environment-status.d.ts +24 -0
- package/dist/conversations/environment-status.js +71 -0
- package/dist/conversations/event-log.d.ts +21 -6
- package/dist/conversations/event-log.js +70 -1
- package/dist/conversations/events.d.ts +140 -0
- package/dist/conversations/events.js +142 -13
- package/dist/conversations/queue.d.ts +3 -1
- package/dist/conversations/queue.js +13 -2
- package/dist/conversations/queue.service.d.ts +1 -1
- package/dist/conversations/queue.service.js +8 -1
- package/dist/conversations/titles.d.ts +12 -3
- package/dist/conversations/titles.js +36 -8
- package/dist/conversations/tree.d.ts +17 -0
- package/dist/conversations/tree.js +42 -0
- package/dist/ctx/create-ctx.d.ts +5 -0
- package/dist/ctx/create-ctx.js +15 -5
- package/dist/db/kernel-schema.d.ts +420 -20
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +3 -0
- package/dist/environments/access.d.ts +41 -0
- package/dist/environments/access.js +77 -0
- package/dist/environments/conversation-environments.d.ts +61 -0
- package/dist/environments/conversation-environments.js +170 -0
- package/dist/environments/dto.d.ts +25 -0
- package/dist/environments/dto.js +12 -0
- package/dist/environments/environments.controller.d.ts +33 -0
- package/dist/environments/environments.controller.js +110 -0
- package/dist/environments/environments.module.d.ts +8 -0
- package/dist/environments/environments.module.js +27 -0
- package/dist/environments/environments.service.d.ts +153 -0
- package/dist/environments/environments.service.js +541 -0
- package/dist/environments/legacy-cleanup.job.d.ts +34 -0
- package/dist/environments/legacy-cleanup.job.js +141 -0
- package/dist/errors.d.ts +90 -2
- package/dist/errors.js +90 -2
- package/dist/evals/reconstruct.d.ts +18 -9
- package/dist/evals/reconstruct.js +26 -7
- package/dist/evals/run-replay.d.ts +7 -2
- package/dist/evals/run-replay.js +42 -7
- package/dist/evals/step-replay.d.ts +2 -5
- package/dist/evals/step-replay.js +13 -7
- package/dist/evals/trajectory.js +1 -1
- package/dist/evals/trajectory.service.d.ts +8 -3
- package/dist/evals/trajectory.service.js +26 -14
- package/dist/evals/worker.d.ts +5 -5
- package/dist/evals/worker.js +9 -3
- package/dist/extensions/admin-ops.d.ts +36 -10
- package/dist/extensions/admin-ops.js +67 -42
- package/dist/extensions/admin-view.d.ts +39 -10
- package/dist/extensions/admin-view.js +111 -20
- package/dist/extensions/blobs.js +1 -0
- package/dist/extensions/bootstrap.d.ts +17 -4
- package/dist/extensions/bootstrap.js +70 -9
- package/dist/extensions/cli.d.ts +12 -0
- package/dist/extensions/cli.js +11 -2
- package/dist/extensions/config-issues.d.ts +13 -1
- package/dist/extensions/config-issues.js +22 -5
- package/dist/extensions/config-json-schema.d.ts +43 -7
- package/dist/extensions/config-json-schema.js +124 -58
- package/dist/extensions/deployment-config-store.d.ts +6 -0
- package/dist/extensions/deployment-config.d.ts +78 -8
- package/dist/extensions/deployment-config.js +172 -34
- package/dist/extensions/display-name.d.ts +22 -0
- package/dist/extensions/display-name.js +77 -0
- package/dist/extensions/effective-config.d.ts +127 -0
- package/dist/extensions/effective-config.js +368 -0
- package/dist/extensions/extensions.module.js +14 -2
- package/dist/extensions/hooks.d.ts +37 -4
- package/dist/extensions/hooks.js +82 -16
- package/dist/extensions/host.d.ts +45 -2
- package/dist/extensions/host.js +112 -16
- package/dist/extensions/installs.d.ts +20 -8
- package/dist/extensions/installs.js +37 -15
- package/dist/extensions/org-config.d.ts +81 -6
- package/dist/extensions/org-config.js +195 -44
- package/dist/extensions/org-levels.d.ts +37 -0
- package/dist/extensions/org-levels.js +71 -0
- package/dist/extensions/org-overrides.d.ts +151 -0
- package/dist/extensions/org-overrides.js +524 -0
- package/dist/extensions/package.d.ts +14 -1
- package/dist/extensions/package.js +51 -2
- package/dist/extensions/permission-view.d.ts +19 -4
- package/dist/extensions/permission-view.js +4 -4
- package/dist/extensions/plugin-items.d.ts +21 -0
- package/dist/extensions/plugin-items.js +42 -0
- package/dist/extensions/point-defaults.controller.d.ts +34 -0
- package/dist/extensions/point-defaults.controller.js +71 -0
- package/dist/extensions/point-defaults.d.ts +71 -0
- package/dist/extensions/point-defaults.js +234 -0
- package/dist/extensions/registry.d.ts +1 -1
- package/dist/extensions/registry.js +2 -0
- package/dist/extensions/resolve.d.ts +5 -1
- package/dist/extensions/resolve.js +15 -2
- package/dist/files/previewers.d.ts +8 -1
- package/dist/files/previewers.js +35 -6
- package/dist/http/api.module.js +31 -3
- package/dist/http/app.d.ts +11 -2
- package/dist/http/app.js +31 -5
- package/dist/http/nest-logger.d.ts +6 -5
- package/dist/http/nest-logger.js +24 -10
- package/dist/identity/accounts.d.ts +29 -29
- package/dist/identity/accounts.js +47 -47
- package/dist/identity/audit.d.ts +2 -1
- package/dist/identity/auth.controller.js +9 -5
- package/dist/identity/auth.guard.d.ts +13 -5
- package/dist/identity/auth.guard.js +26 -9
- package/dist/identity/cookies.d.ts +20 -5
- package/dist/identity/cookies.js +44 -6
- package/dist/identity/identity.module.d.ts +1 -1
- package/dist/identity/identity.module.js +4 -4
- package/dist/identity/me.controller.d.ts +5 -1
- package/dist/identity/me.controller.js +12 -3
- package/dist/identity/principal.d.ts +3 -3
- package/dist/identity/principal.js +3 -3
- package/dist/identity/sessions.d.ts +12 -0
- package/dist/identity/sessions.js +45 -0
- package/dist/identity/settings.d.ts +22 -11
- package/dist/identity/settings.js +53 -18
- package/dist/identity/{enterprise-admin.d.ts → super-admin.d.ts} +5 -5
- package/dist/identity/{enterprise-admin.js → super-admin.js} +24 -24
- package/dist/inbox/inbox.module.d.ts +4 -1
- package/dist/inbox/inbox.module.js +7 -3
- package/dist/inbox/inbox.service.d.ts +62 -3
- package/dist/inbox/inbox.service.js +74 -4
- package/dist/inbox/org-notices.d.ts +63 -0
- package/dist/inbox/org-notices.js +91 -0
- package/dist/inbox/platform-inbox.controller.d.ts +23 -0
- package/dist/inbox/platform-inbox.controller.js +58 -0
- package/dist/inbox/platform-inbox.service.d.ts +151 -0
- package/dist/inbox/platform-inbox.service.js +263 -0
- package/dist/inbox/platform-notices.d.ts +19 -0
- package/dist/inbox/platform-notices.js +9 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/infra/cli/kernel-cli.module.js +9 -1
- package/dist/infra/config/kernel-config.service.js +27 -1
- package/dist/infra/database/database.module.js +1 -0
- package/dist/infra/database/xact-lock.d.ts +1 -1
- package/dist/infra/database/xact-lock.js +1 -1
- package/dist/infra/events/kernel-events.d.ts +19 -2
- package/dist/infra/lifecycle/process-guards.js +4 -0
- package/dist/infra/logging/logging.module.d.ts +4 -2
- package/dist/infra/logging/logging.module.js +24 -6
- package/dist/infra/queue/add-job-once.d.ts +14 -0
- package/dist/infra/queue/add-job-once.js +16 -0
- package/dist/infra/queue/redis-connection.d.ts +6 -0
- package/dist/infra/queue/redis-connection.js +7 -0
- package/dist/infra/redis/redis.module.js +6 -2
- package/dist/infra/tokens.d.ts +6 -1
- package/dist/infra/tokens.js +6 -1
- package/dist/kernel.module.js +6 -0
- package/dist/lifecycle/kernel-lifecycle.d.ts +1 -1
- package/dist/lifecycle/kernel-lifecycle.js +4 -4
- package/dist/log.d.ts +13 -1
- package/dist/log.js +93 -17
- package/dist/models/prices.d.ts +5 -5
- package/dist/models/prices.js +4 -4
- package/dist/models/purposes.controller.d.ts +6 -4
- package/dist/models/purposes.controller.js +13 -7
- package/dist/models/purposes.d.ts +43 -9
- package/dist/models/purposes.js +48 -18
- package/dist/orgs/directory-sync.d.ts +14 -5
- package/dist/orgs/directory-sync.js +41 -17
- package/dist/orgs/offboarding.d.ts +12 -8
- package/dist/orgs/offboarding.js +54 -33
- package/dist/orgs/org-lock.d.ts +5 -0
- package/dist/orgs/org-lock.js +13 -0
- package/dist/orgs/org.guard.d.ts +10 -0
- package/dist/orgs/org.guard.js +43 -32
- package/dist/orgs/orgs.module.js +3 -0
- package/dist/orgs/orgs.service.d.ts +20 -7
- package/dist/orgs/orgs.service.js +32 -12
- package/dist/orgs/roles.d.ts +1 -1
- package/dist/orgs/roles.js +5 -1
- package/dist/orgs/settings.controller.d.ts +1 -1
- package/dist/orgs/settings.service.d.ts +20 -3
- package/dist/orgs/settings.service.js +19 -4
- package/dist/overrides.d.ts +3 -0
- package/dist/overrides.js +2 -0
- package/dist/platform/actor.d.ts +48 -0
- package/dist/platform/actor.js +100 -0
- package/dist/platform/agent-docs.d.ts +18 -0
- package/dist/platform/agent-docs.js +59 -0
- package/dist/platform/availability.d.ts +14 -0
- package/dist/platform/availability.js +43 -0
- package/dist/platform/errors.d.ts +11 -0
- package/dist/platform/errors.js +26 -0
- package/dist/platform/exclusions.d.ts +12 -0
- package/dist/platform/exclusions.js +1387 -0
- package/dist/platform/method.d.ts +6 -0
- package/dist/platform/method.js +15 -0
- package/dist/platform/operation.d.ts +92 -0
- package/dist/platform/operation.js +35 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +14 -0
- package/dist/platform/ops/agent-templates.ops.js +92 -0
- package/dist/platform/ops/agents.ops.d.ts +19 -0
- package/dist/platform/ops/agents.ops.js +294 -0
- package/dist/platform/ops/connectors.ops.d.ts +15 -0
- package/dist/platform/ops/connectors.ops.js +126 -0
- package/dist/platform/ops/errors.d.ts +11 -0
- package/dist/platform/ops/errors.js +22 -0
- package/dist/platform/ops/extensions.ops.d.ts +19 -0
- package/dist/platform/ops/extensions.ops.js +116 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +16 -0
- package/dist/platform/ops/marketplaces.ops.js +157 -0
- package/dist/platform/ops/paging.d.ts +14 -0
- package/dist/platform/ops/paging.js +20 -0
- package/dist/platform/ops/platform.ops.d.ts +23 -0
- package/dist/platform/ops/platform.ops.js +158 -0
- package/dist/platform/ops/plugins.ops.d.ts +33 -0
- package/dist/platform/ops/plugins.ops.js +377 -0
- package/dist/platform/ops/requests.ops.d.ts +14 -0
- package/dist/platform/ops/requests.ops.js +153 -0
- package/dist/platform/ops/role.d.ts +4 -0
- package/dist/platform/ops/role.js +10 -0
- package/dist/platform/ops/skills.ops.d.ts +13 -0
- package/dist/platform/ops/skills.ops.js +98 -0
- package/dist/platform/ops/summary.d.ts +10 -0
- package/dist/platform/ops/summary.js +18 -0
- package/dist/platform/platform-ops.module.d.ts +7 -0
- package/dist/platform/platform-ops.module.js +55 -0
- package/dist/platform/platform.module.d.ts +8 -0
- package/dist/platform/platform.module.js +25 -0
- package/dist/platform/redact-orgs.d.ts +7 -0
- package/dist/platform/redact-orgs.js +52 -0
- package/dist/platform/registry.d.ts +30 -0
- package/dist/platform/registry.js +111 -0
- package/dist/roles/worker-role.d.ts +6 -4
- package/dist/roles/worker-role.js +14 -7
- package/dist/roles/worker.module.d.ts +1 -1
- package/dist/roles/worker.module.js +15 -1
- package/dist/runtime/context/build.d.ts +11 -7
- package/dist/runtime/context/build.js +46 -19
- package/dist/runtime/context/claude-tools.d.ts +3 -1
- package/dist/runtime/context/claude-tools.js +8 -6
- package/dist/runtime/context/compaction.js +13 -0
- package/dist/runtime/context/reminders.d.ts +2 -0
- package/dist/runtime/context/reminders.js +2 -0
- package/dist/runtime/context/skills.js +9 -2
- package/dist/runtime/context/tool-changes.d.ts +27 -0
- package/dist/runtime/context/tool-changes.js +60 -0
- package/dist/runtime/hook-calls.js +2 -0
- package/dist/runtime/langgraph-loop.d.ts +3 -1
- package/dist/runtime/langgraph-loop.js +36 -17
- package/dist/runtime/loop.d.ts +34 -5
- package/dist/runtime/maintenance.d.ts +9 -4
- package/dist/runtime/maintenance.js +35 -8
- package/dist/runtime/model-call.d.ts +46 -8
- package/dist/runtime/model-call.js +72 -21
- package/dist/runtime/providers.d.ts +6 -0
- package/dist/runtime/providers.js +8 -0
- package/dist/runtime/run-control.d.ts +11 -1
- package/dist/runtime/run-control.js +12 -0
- package/dist/runtime/run-drafts.d.ts +85 -0
- package/dist/runtime/run-drafts.js +230 -0
- package/dist/runtime/run-jobs.d.ts +3 -5
- package/dist/runtime/run-jobs.js +3 -7
- package/dist/runtime/run-queue.d.ts +59 -2
- package/dist/runtime/run-queue.js +311 -38
- package/dist/runtime/run-worker.d.ts +11 -5
- package/dist/runtime/run-worker.js +69 -33
- package/dist/runtime/runtime.module.js +11 -3
- package/dist/runtime/step-log.d.ts +15 -4
- package/dist/runtime/step-log.js +24 -7
- package/dist/runtime/stream.controller.d.ts +23 -1
- package/dist/runtime/stream.controller.js +60 -3
- package/dist/runtime/stream.d.ts +4 -1
- package/dist/runtime/stream.js +27 -3
- package/dist/runtime/subagents/child.d.ts +55 -7
- package/dist/runtime/subagents/child.js +105 -7
- package/dist/runtime/subagents/definition.d.ts +12 -3
- package/dist/runtime/subagents/definition.js +44 -28
- package/dist/runtime/subagents/deliveries.d.ts +71 -0
- package/dist/runtime/subagents/deliveries.js +228 -0
- package/dist/runtime/subagents/dispatch.d.ts +115 -26
- package/dist/runtime/subagents/dispatch.js +212 -141
- package/dist/runtime/subagents/limits.d.ts +24 -5
- package/dist/runtime/subagents/limits.js +40 -6
- package/dist/runtime/subagents/messages.d.ts +95 -0
- package/dist/runtime/subagents/messages.js +328 -0
- package/dist/runtime/subagents/preamble.d.ts +4 -4
- package/dist/runtime/subagents/preamble.js +9 -7
- package/dist/runtime/subagents/progress.d.ts +8 -6
- package/dist/runtime/subagents/progress.js +11 -6
- package/dist/runtime/subagents/render.d.ts +30 -0
- package/dist/runtime/subagents/render.js +53 -0
- package/dist/runtime/subagents/roster.d.ts +24 -7
- package/dist/runtime/subagents/roster.js +47 -11
- package/dist/runtime/subagents/skill-fork.d.ts +3 -2
- package/dist/runtime/subagents/skill-fork.js +8 -4
- package/dist/runtime/subagents/status.d.ts +14 -0
- package/dist/runtime/subagents/status.js +23 -0
- package/dist/runtime/subagents/subagents.service.d.ts +7 -4
- package/dist/runtime/subagents/subagents.service.js +11 -6
- package/dist/runtime/usage-report.d.ts +2 -1
- package/dist/runtime/usage-report.js +19 -13
- package/dist/runtime/waits.d.ts +145 -36
- package/dist/runtime/waits.js +423 -109
- package/dist/sandbox/jobs.d.ts +40 -13
- package/dist/sandbox/jobs.js +57 -20
- package/dist/sandbox/leases.d.ts +37 -54
- package/dist/sandbox/leases.js +71 -115
- package/dist/sandbox/providers.d.ts +2 -2
- package/dist/sandbox/providers.js +1 -1
- package/dist/sandbox/sandbox.module.d.ts +3 -2
- package/dist/sandbox/sandbox.module.js +10 -4
- package/dist/sandbox/sandbox.service.d.ts +282 -129
- package/dist/sandbox/sandbox.service.js +736 -381
- package/dist/skills/catalog.d.ts +3 -2
- package/dist/skills/catalog.js +21 -43
- package/dist/skills/changes.controller.d.ts +7 -0
- package/dist/skills/changes.controller.js +19 -1
- package/dist/skills/invoke.js +8 -3
- package/dist/skills/package.d.ts +20 -1
- package/dist/skills/package.js +28 -1
- package/dist/skills/skills.controller.d.ts +39 -4
- package/dist/skills/skills.controller.js +88 -10
- package/dist/skills/skills.module.js +10 -1
- package/dist/skills/skills.service.d.ts +106 -26
- package/dist/skills/skills.service.js +421 -75
- package/dist/skills/usable.d.ts +81 -0
- package/dist/skills/usable.js +379 -0
- package/dist/tools/approvals.service.d.ts +20 -2
- package/dist/tools/approvals.service.js +25 -4
- package/dist/tools/builtin-names.d.ts +41 -7
- package/dist/tools/builtin-names.js +59 -7
- package/dist/tools/builtins/agent.d.ts +23 -21
- package/dist/tools/builtins/agent.js +62 -55
- package/dist/tools/builtins/builtin-tools.d.ts +19 -1
- package/dist/tools/builtins/builtin-tools.js +59 -2
- package/dist/tools/builtins/handback.d.ts +28 -0
- package/dist/tools/builtins/handback.js +53 -0
- package/dist/tools/builtins/platform.d.ts +34 -0
- package/dist/tools/builtins/platform.js +362 -0
- package/dist/tools/builtins/sandbox/bash.d.ts +1 -1
- package/dist/tools/builtins/sandbox/bash.js +241 -4
- package/dist/tools/builtins/sandbox/common.d.ts +69 -27
- package/dist/tools/builtins/sandbox/common.js +87 -48
- package/dist/tools/builtins/sandbox/deliver.js +1 -1
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/glob.js +2 -2
- package/dist/tools/builtins/sandbox/grep.js +2 -4
- package/dist/tools/builtins/sandbox/index.d.ts +3 -1
- package/dist/tools/builtins/sandbox/index.js +7 -1
- package/dist/tools/builtins/sandbox/read.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +74 -0
- package/dist/tools/builtins/sandbox/task-output.js +329 -0
- package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
- package/dist/tools/builtins/sandbox/task-stop.js +113 -0
- package/dist/tools/builtins/sandbox/write.js +2 -2
- package/dist/tools/builtins/send-message.d.ts +56 -0
- package/dist/tools/builtins/send-message.js +100 -0
- package/dist/tools/builtins/skill-load.d.ts +22 -14
- package/dist/tools/builtins/skill-load.js +86 -57
- package/dist/tools/builtins/skill-write.js +1 -1
- package/dist/tools/builtins/web/errors.d.ts +8 -0
- package/dist/tools/builtins/web/errors.js +53 -0
- package/dist/tools/builtins/web/extract.d.ts +62 -0
- package/dist/tools/builtins/web/extract.js +271 -0
- package/dist/tools/builtins/web/fetch.d.ts +55 -0
- package/dist/tools/builtins/web/fetch.js +175 -0
- package/dist/tools/builtins/web/index.d.ts +13 -0
- package/dist/tools/builtins/web/index.js +12 -0
- package/dist/tools/builtins/web/page-cache.d.ts +25 -0
- package/dist/tools/builtins/web/page-cache.js +77 -0
- package/dist/tools/builtins/web/search.d.ts +25 -0
- package/dist/tools/builtins/web/search.js +210 -0
- package/dist/tools/builtins/web/url.d.ts +17 -0
- package/dist/tools/builtins/web/url.js +43 -0
- package/dist/tools/connectors.controller.d.ts +10 -0
- package/dist/tools/connectors.controller.js +12 -0
- package/dist/tools/connectors.service.d.ts +46 -5
- package/dist/tools/connectors.service.js +94 -15
- package/dist/tools/extension-tools.controller.d.ts +14 -0
- package/dist/tools/extension-tools.controller.js +37 -0
- package/dist/tools/info.d.ts +42 -1
- package/dist/tools/info.js +64 -1
- package/dist/tools/oauth/flow-paths.d.ts +1 -1
- package/dist/tools/oauth/flow-paths.js +1 -1
- package/dist/tools/org-tool-switches.d.ts +74 -0
- package/dist/tools/org-tool-switches.js +184 -0
- package/dist/tools/pipeline.d.ts +46 -40
- package/dist/tools/pipeline.js +202 -364
- package/dist/tools/policy.d.ts +1 -1
- package/dist/tools/policy.js +36 -16
- package/dist/tools/registry.d.ts +120 -8
- package/dist/tools/registry.js +112 -19
- package/dist/tools/tools.module.js +24 -2
- package/dist/tools/validate.js +1 -1
- package/dist/ui/views.d.ts +2 -1
- package/dist/ui/views.js +17 -3
- package/package.json +3 -3
- package/src/migrations/0064_account_last_org.sql +7 -0
- package/src/migrations/0065_conversation_archive.sql +8 -0
- package/src/migrations/0066_extension_display_name.sql +4 -0
- package/src/migrations/0067_agent_profiles.sql +20 -0
- package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
- package/src/migrations/0069_attachments_agent_idx.sql +3 -0
- package/src/migrations/0070_background_tasks.sql +37 -0
- package/src/migrations/0071_background_tasks_reserve.sql +6 -0
- package/src/migrations/0072_background_tasks_stopping.sql +5 -0
- package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
- package/src/migrations/0074_subagent_tree.sql +50 -0
- package/src/migrations/0075_plugin_scope.sql +61 -0
- package/src/migrations/0076_skills_created_by_nullable.sql +6 -0
- package/src/migrations/0077_scope_requests.sql +52 -0
- package/src/migrations/0078_scope_grant_switches.sql +18 -0
- package/src/migrations/0079_scope_live_install_switches.sql +19 -0
- package/src/migrations/0080_rename_enterprise_admin.sql +18 -0
- package/src/migrations/0081_platform_components.sql +129 -0
- package/src/migrations/0082_platform_migration.sql +33 -0
- package/src/migrations/0083_plugin_scope_sync_failures.sql +15 -0
- package/src/migrations/0084_org_owned_items.sql +85 -0
- package/src/migrations/0085_agent_templates_phase4.sql +45 -0
- package/src/migrations/0086_org_layering.sql +30 -0
- package/src/migrations/0087_approval_summary.sql +6 -0
- package/src/migrations/0088_environments.sql +80 -0
- package/dist/catalog/upgrade-targets.d.ts +0 -56
- package/dist/catalog/upgrade-targets.js +0 -90
- package/dist/conversations/sandbox-status.d.ts +0 -24
- package/dist/conversations/sandbox-status.js +0 -52
- package/dist/extensions/org-config.controller.d.ts +0 -24
- package/dist/extensions/org-config.controller.js +0 -62
|
@@ -12,385 +12,428 @@ import { Inject, Injectable } from "@nestjs/common";
|
|
|
12
12
|
import { sql } from "kysely";
|
|
13
13
|
import { ApiError } from "../errors.js";
|
|
14
14
|
import { audit } from "../identity/audit.js";
|
|
15
|
-
import {
|
|
15
|
+
import { readOrgMarketplaceBrowse } from "../identity/settings.js";
|
|
16
|
+
import { SuperAdminLock } from "../identity/super-admin.js";
|
|
17
|
+
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
16
18
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
17
19
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
18
20
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
21
|
+
import { LockService } from "../infra/lock/lock.service.js";
|
|
22
|
+
import { WithLock } from "../infra/lock/with-lock.decorator.js";
|
|
19
23
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
20
24
|
import { roleAtLeast } from "../orgs/roles.js";
|
|
25
|
+
import { CatalogService } from "./catalog.service.js";
|
|
26
|
+
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
27
|
+
import { assertEntryNotDeprecated, loadMarketplaceEntry } from "./marketplaces.service.js";
|
|
28
|
+
import { OrgCatalogService } from "./org-catalog.service.js";
|
|
29
|
+
import { PluginImport } from "./plugin-import.js";
|
|
30
|
+
import { itemsSeenBy } from "./scope-state.js";
|
|
21
31
|
/** 申请列表一次最多返回的条数。 */
|
|
22
32
|
export const CATALOG_REQUESTS_LIST_MAX = 200;
|
|
23
33
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
24
34
|
const requestNotFound = () => new ApiError("catalog.request_not_found", "Catalog request not found");
|
|
25
35
|
const itemNotFound = () => new ApiError("catalog.item_not_found", "Catalog item not found");
|
|
26
|
-
const itemDisabled = () => new ApiError("catalog.item_disabled", "This catalog item is disabled by the
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.forShare()
|
|
36
|
-
.executeTakeFirst();
|
|
37
|
-
}
|
|
38
|
-
async function hasGrant(db, orgId, itemId) {
|
|
39
|
-
const g = await db
|
|
40
|
-
.selectFrom("catalog_org_grants")
|
|
41
|
-
.select("item_id")
|
|
42
|
-
.where("item_id", "=", itemId)
|
|
43
|
-
.where("org_id", "=", orgId)
|
|
44
|
-
.executeTakeFirst();
|
|
45
|
-
return g !== undefined;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Before an org creates a component from the catalog (enabling an extension, creating a connector
|
|
49
|
-
* from a template, importing a skill), re-checks the item policy in the caller's transaction (C22):
|
|
50
|
-
* deleted or disabled -> `catalog.item_disabled`; needs_approval without an enterprise admin grant
|
|
51
|
-
* for this org -> `catalog.approval_required`; allow or granted -> passes. A dependency's
|
|
52
|
-
* components pass `approvedBy`, the item the org is installing (spec §10: approval follows the
|
|
53
|
-
* installed plugin only): the dependency's own item must still be live and not disabled, and the
|
|
54
|
-
* approval is judged by `approvedBy`.
|
|
55
|
-
*/
|
|
56
|
-
export async function assertItemInstallable(t, orgId, itemId, approvedBy = itemId) {
|
|
57
|
-
if (approvedBy !== itemId) {
|
|
58
|
-
const own = await lockItem(t, itemId);
|
|
59
|
-
if (!own || own.deleted_at !== null || own.policy === "disabled")
|
|
60
|
-
throw itemDisabled();
|
|
61
|
-
}
|
|
62
|
-
const item = await lockItem(t, approvedBy);
|
|
63
|
-
if (!item || item.deleted_at !== null || item.policy === "disabled")
|
|
64
|
-
throw itemDisabled();
|
|
65
|
-
if (item.policy === "needs_approval" && !(await hasGrant(t, orgId, approvedBy))) {
|
|
66
|
-
throw new ApiError("catalog.approval_required", "This catalog item needs enterprise admin approval before this organization can install it");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* The extensions among `plugins` whose own catalog item (the non-deleted item with the same name) is
|
|
71
|
-
* disabled (FOR SHARE: exclusive with policy changes). A disabled item is a master switch: no path
|
|
72
|
-
* (direct enabling, its item, another plugin) can newly enable its extension (Ruling M-5).
|
|
73
|
-
*/
|
|
74
|
-
export async function disabledPluginItems(db, plugins) {
|
|
75
|
-
if (plugins.length === 0)
|
|
76
|
-
return [];
|
|
77
|
-
const rows = await db
|
|
78
|
-
.selectFrom("catalog_items")
|
|
79
|
-
.select("name")
|
|
80
|
-
.where("name", "in", [...plugins])
|
|
81
|
-
.where("policy", "=", "disabled")
|
|
82
|
-
.where("deleted_at", "is", null)
|
|
83
|
-
.orderBy("name")
|
|
84
|
-
.forShare()
|
|
85
|
-
.execute();
|
|
86
|
-
return [...new Set(rows.map((r) => r.name))];
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Throws `catalog.item_disabled` when a plugin's own catalog item is disabled (the message names
|
|
90
|
-
* the plugin).
|
|
91
|
-
*/
|
|
92
|
-
export function pluginItemDisabled(names) {
|
|
93
|
-
return new ApiError("catalog.item_disabled", `The enterprise admin disabled the catalog item of extension ${names.join(", ")}; it cannot be newly enabled, not even through a plugin that bundles it`);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* When an org enables an extension directly (not by installing from an item, e.g.
|
|
97
|
-
* `PUT /orgs/:orgId/extensions/:extension`), it is judged by every catalog item that brought it into the
|
|
98
|
-
* deployment (`extension_catalog_sources`), and **the strictest wins**: any source disabled ->
|
|
99
|
-
* `catalog.item_disabled`; otherwise any source needs_approval without a grant of that item to the
|
|
100
|
-
* org -> `catalog.approval_required`; all allow / granted -> passes. Deleted items no longer count
|
|
101
|
-
* as sources (an enterprise admin deleting an item withdraws its constraint). No source (not
|
|
102
|
-
* installed through the catalog) -> not bound by catalog policy.
|
|
103
|
-
*/
|
|
104
|
-
export async function assertPluginSourcesInstallable(t, orgId, plugin) {
|
|
105
|
-
const rows = await t
|
|
106
|
-
.selectFrom("extension_catalog_sources as s")
|
|
107
|
-
.innerJoin("catalog_items as i", "i.id", "s.item_id")
|
|
108
|
-
.select(["i.id", "i.policy"])
|
|
109
|
-
.where("s.plugin", "=", plugin)
|
|
110
|
-
.where("i.deleted_at", "is", null)
|
|
111
|
-
.orderBy("i.id")
|
|
112
|
-
.forShare("i")
|
|
113
|
-
.execute();
|
|
114
|
-
if (rows.some((r) => r.policy === "disabled"))
|
|
115
|
-
throw itemDisabled();
|
|
116
|
-
for (const r of rows) {
|
|
117
|
-
if (r.policy === "needs_approval" && !(await hasGrant(t, orgId, r.id))) {
|
|
118
|
-
throw new ApiError("catalog.approval_required", "A catalog item that brought this extension in needs enterprise admin approval before this organization can enable it");
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Cancels catalog requests still pending in the caller's transaction (`db` is its handle; when the
|
|
124
|
-
* item or the org is deleted), status `cancelled` (the decider is the actor). Each one audits
|
|
125
|
-
* `catalog.request_cancelled` (with the reason). Returns how many were cancelled.
|
|
126
|
-
*/
|
|
127
|
-
export async function cancelPendingRequests(db, where, actor, reason, opts = {}) {
|
|
128
|
-
let q = db
|
|
129
|
-
.updateTable("catalog_requests")
|
|
130
|
-
.set({ status: "cancelled", decided_by: actor, decided_at: sql `now()` })
|
|
131
|
-
.where("status", "=", "pending");
|
|
132
|
-
q =
|
|
133
|
-
"itemId" in where ? q.where("item_id", "=", where.itemId) : q.where("org_id", "=", where.orgId);
|
|
134
|
-
const rows = await q.returning(["id", "org_id", "item_id", "stage"]).execute();
|
|
135
|
-
for (const r of rows) {
|
|
136
|
-
await audit(db, {
|
|
137
|
-
actorAccountId: actor,
|
|
138
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
139
|
-
orgId: r.org_id,
|
|
140
|
-
action: "catalog.request_cancelled",
|
|
141
|
-
target: r.id,
|
|
142
|
-
detail: { itemId: r.item_id, stage: r.stage, reason },
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
return rows.length;
|
|
146
|
-
}
|
|
36
|
+
const itemDisabled = () => new ApiError("catalog.item_disabled", "This catalog item is disabled by the super admin and cannot be requested");
|
|
37
|
+
const alreadyDecided = () => new ApiError("catalog.request_decided", "This request has already been decided");
|
|
38
|
+
const pendingExists = () => new ApiError("catalog.request_pending", "This organization already has a pending request of this kind for it");
|
|
39
|
+
/** A unique violation (the partial index of pending requests). */
|
|
40
|
+
const isUniqueViolation = (e) => typeof e === "object" && e !== null && e.code === "23505";
|
|
41
|
+
/** The deployment-level kinds (decided by the super admin). */
|
|
42
|
+
const DEPLOYMENT_KINDS = ["access", "import"];
|
|
43
|
+
/** The org-level kinds (decided by the org admins). */
|
|
44
|
+
const ORG_KINDS = ["enable", "connector_setup"];
|
|
147
45
|
/**
|
|
148
|
-
* Catalog requests
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* - an org admin
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
46
|
+
* Catalog requests under plugin scope (spec §5.1). Three kinds, one pending request per (org,
|
|
47
|
+
* kind, item or entry) (partial unique indexes; org-side writes run inside the org row lock):
|
|
48
|
+
* - `enable`: a member asks the org admins to switch on an item that is off in the org (an
|
|
49
|
+
* `optional` item); an org admin approving it switches the item on, as that admin;
|
|
50
|
+
* - `access`: an org admin asks the super admin for a `named` item shown to orgs outside its
|
|
51
|
+
* list; approving adds the org to the list (`CatalogScopeService.addOrg`), the scope sync then
|
|
52
|
+
* installs it;
|
|
53
|
+
* - `import`: an org admin asks for a marketplace entry not in the catalog (deployment setting
|
|
54
|
+
* `orgMarketplaceBrowse`); approving prepares the import and returns its staging, the request
|
|
55
|
+
* resolves when the super admin confirms it (scope default `named` = the requesting org);
|
|
56
|
+
* - `connector_setup` (ruling P4-7): one per agent (`agent_id`, `pending_keys`), asking the org
|
|
57
|
+
* admins to set up an agent's pending connectors; written by the agents module
|
|
58
|
+
* (`PendingConnectorRequests`), closed by binding (`approved`) or the agent's deletion
|
|
59
|
+
* (`cancelled`); here it is listed and rejected.
|
|
60
|
+
* A rejection stores an optional reason. Decided requests show in the requester's inbox until
|
|
61
|
+
* dismissed. No in-process state.
|
|
158
62
|
*/
|
|
159
63
|
let CatalogRequestsService = class CatalogRequestsService {
|
|
160
64
|
kdb;
|
|
161
65
|
orgLock;
|
|
162
66
|
adminLock;
|
|
67
|
+
orgCatalog;
|
|
68
|
+
scope;
|
|
69
|
+
catalog;
|
|
70
|
+
config;
|
|
71
|
+
pluginImport;
|
|
163
72
|
txHost;
|
|
73
|
+
lockService;
|
|
164
74
|
constructor(kdb,
|
|
165
|
-
/** The org row and
|
|
166
|
-
orgLock, adminLock, txHost
|
|
75
|
+
/** The org row and super admin locks: both join the caller's transaction. */
|
|
76
|
+
orgLock, adminLock, orgCatalog, scope, catalog, config, pluginImport, txHost,
|
|
77
|
+
/** Serializes the approvals of one `import` request (`@WithLock`). */
|
|
78
|
+
lockService) {
|
|
167
79
|
this.kdb = kdb;
|
|
168
80
|
this.orgLock = orgLock;
|
|
169
81
|
this.adminLock = adminLock;
|
|
82
|
+
this.orgCatalog = orgCatalog;
|
|
83
|
+
this.scope = scope;
|
|
84
|
+
this.catalog = catalog;
|
|
85
|
+
this.config = config;
|
|
86
|
+
this.pluginImport = pluginImport;
|
|
170
87
|
this.txHost = txHost;
|
|
88
|
+
this.lockService = lockService;
|
|
171
89
|
}
|
|
172
90
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
173
91
|
get db() {
|
|
174
92
|
return this.kdb.db;
|
|
175
93
|
}
|
|
176
94
|
/**
|
|
177
|
-
* A
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
95
|
+
* A request for a catalog item (`POST /orgs/:orgId/catalog/:itemId/requests`): `enable`
|
|
96
|
+
* (`catalog.request`, members and up) or `access` (`catalog.decide`, org admins), checked first.
|
|
97
|
+
* The item as the org sees it: absent (missing, deleted, hidden, disabled for a member) ->
|
|
98
|
+
* `catalog.item_not_found`; disabled -> `catalog.item_disabled` for an org admin; `access` needs
|
|
99
|
+
* `not_offered`, `enable` needs `off` (else `catalog.request_invalid`); a pending request of the
|
|
100
|
+
* kind -> `catalog.request_pending`. Audits `catalog.requested`.
|
|
181
101
|
*/
|
|
182
|
-
async
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
const item = await lockItem(t, itemId);
|
|
190
|
-
if (!item || item.deleted_at !== null)
|
|
102
|
+
async requestItem(orgId, actor, itemId, input, opts = {}) {
|
|
103
|
+
const action = input.kind === "access" ? "catalog.decide" : "catalog.request";
|
|
104
|
+
await this.authorize(orgId, actor, action);
|
|
105
|
+
if (!UUID_RE.test(itemId))
|
|
106
|
+
throw itemNotFound();
|
|
107
|
+
const [item] = await this.orgCatalog.list(orgId, actor, itemId);
|
|
108
|
+
if (!item)
|
|
191
109
|
throw itemNotFound();
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
110
|
+
if (item.state === "unavailable")
|
|
111
|
+
throw itemDisabled();
|
|
112
|
+
const want = input.kind === "access" ? "not_offered" : "off";
|
|
113
|
+
if (item.state !== want) {
|
|
114
|
+
throw new ApiError("catalog.request_invalid", input.kind === "access"
|
|
115
|
+
? "This plugin is already offered to this organization"
|
|
116
|
+
: "This plugin is not off in this organization (or not one an org admin switches on)");
|
|
195
117
|
}
|
|
196
|
-
const
|
|
118
|
+
const id = await this.writeItemRequest(orgId, actor, item.name, itemId, input, opts);
|
|
119
|
+
return this.view(id);
|
|
120
|
+
}
|
|
121
|
+
/** The role check alone, before any item error (a member cannot probe items by error codes). */
|
|
122
|
+
async authorize(orgId, actor, action) {
|
|
123
|
+
await this.orgLock.lockAndAuthorize(orgId, actor, action);
|
|
124
|
+
}
|
|
125
|
+
async writeItemRequest(orgId, actor, name, itemId, input, opts) {
|
|
126
|
+
const t = this.db;
|
|
127
|
+
await this.orgLock.lockAndAuthorize(orgId, actor, input.kind === "access" ? "catalog.decide" : "catalog.request");
|
|
128
|
+
const existing = await t
|
|
129
|
+
.selectFrom("catalog_requests")
|
|
130
|
+
.select("id")
|
|
131
|
+
.where("org_id", "=", orgId)
|
|
132
|
+
.where("item_id", "=", itemId)
|
|
133
|
+
.where("kind", "=", input.kind)
|
|
134
|
+
.where("status", "=", "pending")
|
|
135
|
+
.executeTakeFirst();
|
|
197
136
|
if (existing)
|
|
198
|
-
|
|
137
|
+
throw pendingExists();
|
|
199
138
|
const id = randomUUID();
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
139
|
+
try {
|
|
140
|
+
await t
|
|
141
|
+
.insertInto("catalog_requests")
|
|
142
|
+
.values({
|
|
143
|
+
id,
|
|
144
|
+
org_id: orgId,
|
|
145
|
+
item_id: itemId,
|
|
146
|
+
kind: input.kind,
|
|
147
|
+
// still written for the old NOT NULL / CHECK, never read
|
|
148
|
+
stage: input.kind === "enable" ? "org" : "deployment",
|
|
149
|
+
requested_by: actor,
|
|
150
|
+
note: input.note ?? "",
|
|
151
|
+
})
|
|
152
|
+
.execute();
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
if (isUniqueViolation(e))
|
|
156
|
+
throw pendingExists();
|
|
157
|
+
throw e;
|
|
158
|
+
}
|
|
212
159
|
await audit(t, {
|
|
213
160
|
actorAccountId: actor,
|
|
214
161
|
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
215
162
|
orgId,
|
|
216
163
|
action: "catalog.requested",
|
|
217
164
|
target: id,
|
|
218
|
-
detail: { itemId, name:
|
|
165
|
+
detail: { itemId, name, kind: input.kind, ...opts.auditDetail },
|
|
219
166
|
});
|
|
220
|
-
return
|
|
221
|
-
}
|
|
222
|
-
pendingRow(orgId, itemId) {
|
|
223
|
-
return this.db
|
|
224
|
-
.selectFrom("catalog_requests")
|
|
225
|
-
.select(["id", "stage"])
|
|
226
|
-
.where("org_id", "=", orgId)
|
|
227
|
-
.where("item_id", "=", itemId)
|
|
228
|
-
.where("status", "=", "pending")
|
|
229
|
-
.executeTakeFirst();
|
|
167
|
+
return id;
|
|
230
168
|
}
|
|
231
169
|
/**
|
|
232
|
-
* An org admin
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
170
|
+
* An org admin asks for a marketplace entry to be imported (`POST /orgs/:orgId/
|
|
171
|
+
* marketplace-requests`, `catalog.decide`). The deployment setting `orgMarketplaceBrowse` off ->
|
|
172
|
+
* `catalog.marketplace_browse_disabled`; the marketplace or the entry / version missing ->
|
|
173
|
+
* `marketplace.not_found` / `marketplace.entry_not_found`; a deprecated version ->
|
|
174
|
+
* `marketplace.entry_deprecated`; a live item of that name ->
|
|
175
|
+
* `catalog.request_invalid` (ask for access instead) when the org can see or request that item
|
|
176
|
+
* (a hidden one is not revealed: the request is accepted); a pending request for the entry ->
|
|
177
|
+
* `catalog.request_pending`. Audits `catalog.requested`.
|
|
236
178
|
*/
|
|
237
|
-
async
|
|
179
|
+
async requestImport(orgId, actor, input, opts = {}) {
|
|
180
|
+
const id = await this.writeImportRequest(orgId, actor, input, opts);
|
|
181
|
+
return this.view(id);
|
|
182
|
+
}
|
|
183
|
+
async writeImportRequest(orgId, actor, input, opts) {
|
|
238
184
|
const t = this.db;
|
|
239
|
-
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
await t
|
|
243
|
-
.updateTable("catalog_requests")
|
|
244
|
-
.set({ stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` })
|
|
245
|
-
.where("id", "=", existing.id)
|
|
246
|
-
.execute();
|
|
247
|
-
await audit(t, {
|
|
248
|
-
actorAccountId: actor,
|
|
249
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
250
|
-
orgId,
|
|
251
|
-
action: "catalog.request_decided",
|
|
252
|
-
target: existing.id,
|
|
253
|
-
detail: { itemId: item.id, decision: "approve", stage: "org", escalated: true },
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
return existing.id;
|
|
185
|
+
await this.orgLock.lockAndAuthorize(orgId, actor, "catalog.decide");
|
|
186
|
+
if (!(await readOrgMarketplaceBrowse(t))) {
|
|
187
|
+
throw new ApiError("catalog.marketplace_browse_disabled", "Organizations cannot browse the marketplaces or request imports in this deployment");
|
|
257
188
|
}
|
|
189
|
+
const { entry } = await loadMarketplaceEntry(t, this.config.get(), input.marketplaceId, input.name, input.version);
|
|
190
|
+
assertEntryNotDeprecated(entry);
|
|
191
|
+
const live = await t
|
|
192
|
+
.selectFrom("catalog_items")
|
|
193
|
+
.select("id")
|
|
194
|
+
.where("name", "=", input.name)
|
|
195
|
+
.where("deleted_at", "is", null)
|
|
196
|
+
.executeTakeFirst();
|
|
197
|
+
// Only an item the org can see or request is named back to it; a hidden `named` item stays
|
|
198
|
+
// unknown and the request is accepted (approving it adds the org to that item's list)
|
|
199
|
+
if (live && (await itemsSeenBy(t, orgId, [live.id])).has(live.id)) {
|
|
200
|
+
throw new ApiError("catalog.request_invalid", `Plugin ${input.name} is already in the catalog; request access to it instead`);
|
|
201
|
+
}
|
|
202
|
+
const existing = await t
|
|
203
|
+
.selectFrom("catalog_requests")
|
|
204
|
+
.select("id")
|
|
205
|
+
.where("org_id", "=", orgId)
|
|
206
|
+
.where("kind", "=", "import")
|
|
207
|
+
.where("marketplace_id", "=", input.marketplaceId)
|
|
208
|
+
.where("entry_name", "=", input.name)
|
|
209
|
+
.where("status", "=", "pending")
|
|
210
|
+
.executeTakeFirst();
|
|
211
|
+
if (existing)
|
|
212
|
+
throw pendingExists();
|
|
258
213
|
const id = randomUUID();
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
214
|
+
try {
|
|
215
|
+
await t
|
|
216
|
+
.insertInto("catalog_requests")
|
|
217
|
+
.values({
|
|
218
|
+
id,
|
|
219
|
+
org_id: orgId,
|
|
220
|
+
item_id: null,
|
|
221
|
+
kind: "import",
|
|
222
|
+
stage: "deployment",
|
|
223
|
+
marketplace_id: input.marketplaceId,
|
|
224
|
+
entry_name: input.name,
|
|
225
|
+
entry_version: input.version,
|
|
226
|
+
requested_by: actor,
|
|
227
|
+
note: input.note ?? "",
|
|
228
|
+
})
|
|
229
|
+
.execute();
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
if (isUniqueViolation(e))
|
|
233
|
+
throw pendingExists();
|
|
234
|
+
throw e;
|
|
235
|
+
}
|
|
270
236
|
await audit(t, {
|
|
271
237
|
actorAccountId: actor,
|
|
272
238
|
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
273
239
|
orgId,
|
|
274
240
|
action: "catalog.requested",
|
|
275
241
|
target: id,
|
|
276
|
-
detail: {
|
|
242
|
+
detail: {
|
|
243
|
+
kind: "import",
|
|
244
|
+
marketplaceId: input.marketplaceId,
|
|
245
|
+
name: input.name,
|
|
246
|
+
version: input.version,
|
|
247
|
+
...opts.auditDetail,
|
|
248
|
+
},
|
|
277
249
|
});
|
|
278
250
|
return id;
|
|
279
251
|
}
|
|
280
252
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
.set({ status: "approved", decided_by: actor, decided_at: sql `now()` })
|
|
290
|
-
.where("org_id", "=", orgId)
|
|
291
|
-
.where("item_id", "=", itemId)
|
|
292
|
-
.where("status", "=", "pending")
|
|
293
|
-
.returning(["id", "stage"])
|
|
294
|
-
.execute();
|
|
295
|
-
for (const r of rows) {
|
|
296
|
-
await audit(t, {
|
|
297
|
-
actorAccountId: actor,
|
|
298
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
299
|
-
orgId,
|
|
300
|
-
action: "catalog.request_decided",
|
|
301
|
-
target: r.id,
|
|
302
|
-
detail: { itemId, decision: "approve", stage: r.stage, installed: true },
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* An org admin decides a member request (`catalog.decide`, re-checked inside the org row lock;
|
|
308
|
-
* the request row FOR UPDATE). Not this org's request -> `catalog.request_not_found`; already
|
|
309
|
-
* decided or handed to the enterprise admins -> `catalog.request_decided`. On approval: item
|
|
310
|
-
* deleted or disabled -> `catalog.item_disabled`; needs_approval without a grant -> moved to stage
|
|
311
|
-
* deployment (still pending); otherwise approved. Audits `catalog.request_decided`.
|
|
253
|
+
* An org admin decides a member's `enable` or `connector_setup` request (`catalog.decide`). Not
|
|
254
|
+
* this org's request of those kinds -> `catalog.request_not_found`; decided ->
|
|
255
|
+
* `catalog.request_decided`. Approving an `enable` request switches the item on in the org as the
|
|
256
|
+
* deciding admin ({@link OrgCatalogService.setSwitch}: its errors, e.g. inputs the install
|
|
257
|
+
* needs, leave the request pending); the install itself resolves the request. A
|
|
258
|
+
* `connector_setup` request is approved only by binding its connectors (ruling P4-T6-6):
|
|
259
|
+
* approving it -> `catalog.request_invalid`. Rejecting stores the reason. Audits
|
|
260
|
+
* `catalog.request_decided`.
|
|
312
261
|
*/
|
|
313
262
|
async decideOrg(orgId, actor, requestId, decision, opts = {}) {
|
|
314
263
|
if (!UUID_RE.test(requestId))
|
|
315
264
|
throw requestNotFound();
|
|
316
|
-
|
|
265
|
+
if (decision.approve) {
|
|
266
|
+
const itemId = await this.pendingOrgRequest(orgId, actor, requestId);
|
|
267
|
+
await this.orgCatalog.setSwitch(orgId, actor, itemId, { enabled: true }, opts.actorTokenId);
|
|
268
|
+
}
|
|
269
|
+
await this.writeDecision(requestId, actor, decision, opts, { orgId });
|
|
317
270
|
return this.view(requestId);
|
|
318
271
|
}
|
|
319
|
-
|
|
320
|
-
|
|
272
|
+
/** The item of a pending `enable` request of the org (the decider re-checked). */
|
|
273
|
+
async pendingOrgRequest(orgId, actor, requestId) {
|
|
321
274
|
await this.orgLock.lockAndAuthorize(orgId, actor, "catalog.decide");
|
|
322
|
-
const row = await
|
|
275
|
+
const row = await this.db
|
|
323
276
|
.selectFrom("catalog_requests")
|
|
324
|
-
.select(["
|
|
277
|
+
.select(["item_id", "status", "kind"])
|
|
325
278
|
.where("id", "=", requestId)
|
|
326
279
|
.where("org_id", "=", orgId)
|
|
327
|
-
.
|
|
280
|
+
.where("kind", "in", [...ORG_KINDS])
|
|
328
281
|
.executeTakeFirst();
|
|
329
282
|
if (!row)
|
|
330
283
|
throw requestNotFound();
|
|
331
|
-
if (row.status !== "pending"
|
|
332
|
-
throw
|
|
333
|
-
|
|
334
|
-
|
|
284
|
+
if (row.status !== "pending")
|
|
285
|
+
throw alreadyDecided();
|
|
286
|
+
if (row.kind === "connector_setup") {
|
|
287
|
+
throw new ApiError("catalog.request_invalid", "A connector setup request is resolved by binding the agent's connectors; reject it to refuse");
|
|
335
288
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
289
|
+
if (row.item_id === null)
|
|
290
|
+
throw requestNotFound();
|
|
291
|
+
return row.item_id;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* A super admin decides an `access` or `import` request (re-checked inside the super
|
|
295
|
+
* admin lock; the request row FOR UPDATE). Missing or an `enable` request ->
|
|
296
|
+
* `catalog.request_not_found`; decided -> `catalog.request_decided`. Approving `access`: the item
|
|
297
|
+
* deleted or disabled -> `catalog.item_disabled`, the org deleted -> not found; otherwise the org
|
|
298
|
+
* joins the item's `named` list. Approving `import` prepares the import of the entry and returns
|
|
299
|
+
* it; the request stays pending, linked to the staging, until that confirm commits (approving
|
|
300
|
+
* again prepares a new one). Audits `catalog.request_decided` (`catalog.request_import_prepared`
|
|
301
|
+
* for an import's approval).
|
|
302
|
+
*/
|
|
303
|
+
async decideDeployment(actor, requestId, decision, opts = {}) {
|
|
304
|
+
if (!UUID_RE.test(requestId))
|
|
305
|
+
throw requestNotFound();
|
|
306
|
+
const row = await this.pendingDeploymentRequest(actor, requestId);
|
|
307
|
+
if (decision.approve && row.kind === "import")
|
|
308
|
+
return this.approveImport(actor, requestId, opts);
|
|
309
|
+
await this.writeDecision(requestId, actor, decision, opts, { deployment: true });
|
|
310
|
+
return { request: await this.view(requestId) };
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Approves an `import` request, one approval of a request at a time (across replicas): an item
|
|
314
|
+
* of the entry's name that holds the requested version already (one hidden from the org, which
|
|
315
|
+
* is why the request was accepted) -> the org joins its `named` list at once, nothing imported;
|
|
316
|
+
* a staging linked by an earlier approval and not expired -> that staging again; otherwise the
|
|
317
|
+
* import is prepared and linked. The confirm of a staging adds the org to an item that exists by
|
|
318
|
+
* then (`PluginImport.commit`).
|
|
319
|
+
*/
|
|
320
|
+
async approveImport(actor, requestId, opts) {
|
|
321
|
+
const row = await this.pendingDeploymentRequest(actor, requestId);
|
|
322
|
+
if (row.marketplace_id === null || row.entry_name === null) {
|
|
323
|
+
throw new ApiError("catalog.request_invalid", "The marketplace of this request was deleted; reject it");
|
|
342
324
|
}
|
|
343
|
-
await
|
|
325
|
+
const existing = await this.db
|
|
326
|
+
.selectFrom("catalog_items as i")
|
|
327
|
+
.innerJoin("catalog_item_versions as v", "v.item_id", "i.id")
|
|
328
|
+
.select("i.id")
|
|
329
|
+
.where("i.name", "=", row.entry_name)
|
|
330
|
+
.where("i.deleted_at", "is", null)
|
|
331
|
+
.where("v.version", "=", row.entry_version ?? "")
|
|
332
|
+
.executeTakeFirst();
|
|
333
|
+
if (existing) {
|
|
334
|
+
await this.writeDecision(requestId, actor, { approve: true }, opts, {
|
|
335
|
+
deployment: true,
|
|
336
|
+
grantItem: existing.id,
|
|
337
|
+
});
|
|
338
|
+
return { request: await this.view(requestId) };
|
|
339
|
+
}
|
|
340
|
+
if (row.staging_id !== null) {
|
|
341
|
+
const staged = await this.pluginImport.staged(row.staging_id).catch(() => undefined);
|
|
342
|
+
if (staged) {
|
|
343
|
+
return {
|
|
344
|
+
request: await this.view(requestId),
|
|
345
|
+
import: {
|
|
346
|
+
stagingId: staged.stagingId,
|
|
347
|
+
review: staged.review,
|
|
348
|
+
permissionsMismatch: staged.permissionsMismatch ?? null,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const prepared = await this.catalog.importFromMarketplace(actor, {
|
|
354
|
+
marketplaceId: row.marketplace_id,
|
|
355
|
+
name: row.entry_name,
|
|
356
|
+
...(row.entry_version !== null && { version: row.entry_version }),
|
|
357
|
+
}, opts);
|
|
358
|
+
await this.linkStaging(actor, requestId, prepared.stagingId, opts);
|
|
359
|
+
return { request: await this.view(requestId), import: prepared };
|
|
360
|
+
}
|
|
361
|
+
/** A pending `access` / `import` request (the row locked; the super admin re-checked). */
|
|
362
|
+
async pendingDeploymentRequest(actor, requestId) {
|
|
363
|
+
await this.adminLock.lockAndAuthorize(actor);
|
|
364
|
+
const row = await this.db
|
|
365
|
+
.selectFrom("catalog_requests")
|
|
366
|
+
.select(["kind", "status", "marketplace_id", "entry_name", "entry_version", "staging_id"])
|
|
367
|
+
.where("id", "=", requestId)
|
|
368
|
+
.where("kind", "in", [...DEPLOYMENT_KINDS])
|
|
369
|
+
.forUpdate()
|
|
370
|
+
.executeTakeFirst();
|
|
371
|
+
if (!row)
|
|
372
|
+
throw requestNotFound();
|
|
373
|
+
if (row.status !== "pending")
|
|
374
|
+
throw alreadyDecided();
|
|
375
|
+
return row;
|
|
376
|
+
}
|
|
377
|
+
/** Links a still pending `import` request to its prepared staging. */
|
|
378
|
+
async linkStaging(actor, requestId, stagingId, opts) {
|
|
379
|
+
await this.adminLock.lockAndAuthorize(actor);
|
|
380
|
+
const row = await this.db
|
|
381
|
+
.selectFrom("catalog_requests")
|
|
382
|
+
.select(["org_id", "status", "entry_name"])
|
|
383
|
+
.where("id", "=", requestId)
|
|
384
|
+
.forUpdate()
|
|
385
|
+
.executeTakeFirstOrThrow();
|
|
386
|
+
if (row.status !== "pending")
|
|
387
|
+
throw alreadyDecided();
|
|
388
|
+
await this.db
|
|
344
389
|
.updateTable("catalog_requests")
|
|
345
|
-
.set(
|
|
346
|
-
? { stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` }
|
|
347
|
-
: {
|
|
348
|
-
status: decision === "approve" ? "approved" : "rejected",
|
|
349
|
-
decided_by: actor,
|
|
350
|
-
decided_at: sql `now()`,
|
|
351
|
-
})
|
|
390
|
+
.set({ staging_id: stagingId })
|
|
352
391
|
.where("id", "=", requestId)
|
|
353
392
|
.execute();
|
|
354
|
-
await audit(
|
|
393
|
+
await audit(this.db, {
|
|
355
394
|
actorAccountId: actor,
|
|
356
395
|
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
357
|
-
orgId,
|
|
358
|
-
action: "catalog.
|
|
396
|
+
orgId: row.org_id,
|
|
397
|
+
action: "catalog.request_import_prepared",
|
|
359
398
|
target: requestId,
|
|
360
|
-
detail: {
|
|
399
|
+
detail: { name: row.entry_name, stagingId },
|
|
361
400
|
});
|
|
362
401
|
}
|
|
363
402
|
/**
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* `
|
|
367
|
-
* deleted or disabled -> `catalog.item_disabled`, the request's org deleted ->
|
|
368
|
-
* `catalog.request_not_found`. Approval writes a grant to `catalog_org_grants`. Audits
|
|
369
|
-
* `catalog.request_decided` (with orgId).
|
|
403
|
+
* Writes a decision (the request row FOR UPDATE): org side (`orgId`: the org admin re-checked,
|
|
404
|
+
* `enable` only) or deployment side (the super admin re-checked, `access` / `import`). An
|
|
405
|
+
* approval of an `enable` request may find it approved already by the install it triggered.
|
|
370
406
|
*/
|
|
371
|
-
async
|
|
372
|
-
if (!UUID_RE.test(requestId))
|
|
373
|
-
throw requestNotFound();
|
|
374
|
-
await this.writeDecideDeployment(actor, requestId, decision, opts);
|
|
375
|
-
return this.view(requestId);
|
|
376
|
-
}
|
|
377
|
-
async writeDecideDeployment(actor, requestId, decision, opts) {
|
|
407
|
+
async writeDecision(requestId, actor, decision, opts, side) {
|
|
378
408
|
const t = this.db;
|
|
379
|
-
|
|
380
|
-
|
|
409
|
+
if ("orgId" in side)
|
|
410
|
+
await this.orgLock.lockAndAuthorize(side.orgId, actor, "catalog.decide");
|
|
411
|
+
else
|
|
412
|
+
await this.adminLock.lockAndAuthorize(actor);
|
|
413
|
+
let q = t
|
|
381
414
|
.selectFrom("catalog_requests")
|
|
382
|
-
.select(["id", "org_id", "item_id", "
|
|
383
|
-
.where("id", "=", requestId)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
415
|
+
.select(["id", "org_id", "item_id", "kind", "status", "decided_by"])
|
|
416
|
+
.where("id", "=", requestId);
|
|
417
|
+
q =
|
|
418
|
+
"orgId" in side
|
|
419
|
+
? q.where("org_id", "=", side.orgId).where("kind", "in", [...ORG_KINDS])
|
|
420
|
+
: q.where("kind", "in", [...DEPLOYMENT_KINDS]);
|
|
421
|
+
const row = await q.forUpdate().executeTakeFirst();
|
|
422
|
+
if (!row)
|
|
387
423
|
throw requestNotFound();
|
|
388
424
|
if (row.status !== "pending") {
|
|
389
|
-
|
|
425
|
+
// The switch-on of this approval already resolved it (the install approves pending requests)
|
|
426
|
+
if (decision.approve && row.kind === "enable" && row.status === "approved")
|
|
427
|
+
return;
|
|
428
|
+
throw alreadyDecided();
|
|
390
429
|
}
|
|
391
|
-
if (decision === "
|
|
392
|
-
const item = await
|
|
393
|
-
|
|
430
|
+
if (decision.approve && row.kind === "access" && row.item_id !== null) {
|
|
431
|
+
const item = await t
|
|
432
|
+
.selectFrom("catalog_items")
|
|
433
|
+
.select(["deleted_at", "disabled"])
|
|
434
|
+
.where("id", "=", row.item_id)
|
|
435
|
+
.executeTakeFirst();
|
|
436
|
+
if (!item || item.deleted_at !== null || item.disabled)
|
|
394
437
|
throw itemDisabled();
|
|
395
438
|
const org = await t
|
|
396
439
|
.selectFrom("orgs")
|
|
@@ -399,16 +442,19 @@ let CatalogRequestsService = class CatalogRequestsService {
|
|
|
399
442
|
.executeTakeFirst();
|
|
400
443
|
if (!org || org.deleted_at !== null)
|
|
401
444
|
throw requestNotFound();
|
|
402
|
-
await
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
445
|
+
await this.scope.addOrg(actor, row.item_id, row.org_id, { ...opts, requestId });
|
|
446
|
+
}
|
|
447
|
+
// An `import` request whose entry is in the catalog already: the org joins that item's list
|
|
448
|
+
const grantItem = "grantItem" in side ? side.grantItem : undefined;
|
|
449
|
+
if (decision.approve && row.kind === "import" && grantItem !== undefined) {
|
|
450
|
+
await this.scope.addOrg(actor, grantItem, row.org_id, { ...opts, requestId });
|
|
407
451
|
}
|
|
408
452
|
await t
|
|
409
453
|
.updateTable("catalog_requests")
|
|
410
454
|
.set({
|
|
411
|
-
status: decision
|
|
455
|
+
status: decision.approve ? "approved" : "rejected",
|
|
456
|
+
reason: decision.approve ? null : (decision.reason ?? null),
|
|
457
|
+
...(grantItem !== undefined && { item_id: grantItem }),
|
|
412
458
|
decided_by: actor,
|
|
413
459
|
decided_at: sql `now()`,
|
|
414
460
|
})
|
|
@@ -420,36 +466,62 @@ let CatalogRequestsService = class CatalogRequestsService {
|
|
|
420
466
|
orgId: row.org_id,
|
|
421
467
|
action: "catalog.request_decided",
|
|
422
468
|
target: requestId,
|
|
423
|
-
detail: {
|
|
469
|
+
detail: {
|
|
470
|
+
itemId: row.item_id,
|
|
471
|
+
kind: row.kind,
|
|
472
|
+
decision: decision.approve ? "approve" : "reject",
|
|
473
|
+
...(!decision.approve && decision.reason !== undefined && { reason: decision.reason }),
|
|
474
|
+
},
|
|
424
475
|
});
|
|
425
476
|
}
|
|
426
|
-
/**
|
|
477
|
+
/**
|
|
478
|
+
* The requester dismisses a decided request from the inbox (`POST /orgs/:orgId/
|
|
479
|
+
* catalog-requests/:id/dismiss`). Not the requester's decided request in this org ->
|
|
480
|
+
* `catalog.request_not_found`.
|
|
481
|
+
*/
|
|
482
|
+
async dismiss(orgId, accountId, requestId) {
|
|
483
|
+
if (!UUID_RE.test(requestId))
|
|
484
|
+
throw requestNotFound();
|
|
485
|
+
const r = await this.db
|
|
486
|
+
.updateTable("catalog_requests")
|
|
487
|
+
.set({ dismissed_at: sql `now()` })
|
|
488
|
+
.where("id", "=", requestId)
|
|
489
|
+
.where("org_id", "=", orgId)
|
|
490
|
+
.where("requested_by", "=", accountId)
|
|
491
|
+
.where("status", "in", ["approved", "rejected"])
|
|
492
|
+
.where("dismissed_at", "is", null)
|
|
493
|
+
.executeTakeFirst();
|
|
494
|
+
if (r.numUpdatedRows === 0n)
|
|
495
|
+
throw requestNotFound();
|
|
496
|
+
}
|
|
497
|
+
/** 超级管理员的申请列表(`access` / `import`;`status` 缺省 pending),新的在前。 */
|
|
427
498
|
async listDeployment(q = {}) {
|
|
428
499
|
const rows = await this.baseQuery()
|
|
429
|
-
.where("r.
|
|
500
|
+
.where("r.kind", "in", [...DEPLOYMENT_KINDS])
|
|
430
501
|
.where("r.status", "=", q.status ?? "pending")
|
|
431
502
|
.where("o.deleted_at", "is", null)
|
|
432
503
|
.orderBy("r.created_at", "desc")
|
|
433
504
|
.orderBy("r.id")
|
|
434
505
|
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
435
506
|
.execute();
|
|
436
|
-
return
|
|
507
|
+
return this.toViews(rows);
|
|
437
508
|
}
|
|
438
|
-
/**
|
|
509
|
+
/** 待超级管理员处理的申请数(后台概览)。 */
|
|
439
510
|
async countPendingDeployment() {
|
|
440
511
|
const r = await this.db
|
|
441
512
|
.selectFrom("catalog_requests as r")
|
|
442
513
|
.innerJoin("orgs as o", "o.id", "r.org_id")
|
|
443
514
|
.select(sql `count(*)`.as("n"))
|
|
444
|
-
.where("r.
|
|
515
|
+
.where("r.kind", "in", [...DEPLOYMENT_KINDS])
|
|
445
516
|
.where("r.status", "=", "pending")
|
|
446
517
|
.where("o.deleted_at", "is", null)
|
|
447
518
|
.executeTakeFirstOrThrow();
|
|
448
519
|
return Number(r.n);
|
|
449
520
|
}
|
|
450
521
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
522
|
+
* The inbox: when the account is an org admin of the org (the role read live), the members'
|
|
523
|
+
* pending `enable` requests and the pending `connector_setup` requests, newest first; otherwise
|
|
524
|
+
* none.
|
|
453
525
|
*/
|
|
454
526
|
async listForOrgAdmin(orgId, accountId) {
|
|
455
527
|
const m = await this.db
|
|
@@ -462,99 +534,210 @@ let CatalogRequestsService = class CatalogRequestsService {
|
|
|
462
534
|
return [];
|
|
463
535
|
const rows = await this.baseQuery()
|
|
464
536
|
.where("r.org_id", "=", orgId)
|
|
465
|
-
.where("r.
|
|
537
|
+
.where("r.kind", "in", [...ORG_KINDS])
|
|
466
538
|
.where("r.status", "=", "pending")
|
|
467
539
|
.orderBy("r.created_at", "desc")
|
|
468
540
|
.orderBy("r.id")
|
|
469
541
|
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
470
542
|
.execute();
|
|
471
|
-
|
|
543
|
+
// A request on an item the org can no longer see (its scope hid it since) is left out, so
|
|
544
|
+
// nothing reveals the item's name to the org; a setup request of a deleted agent too
|
|
545
|
+
const ids = [...new Set(rows.flatMap((r) => (r.item_id !== null ? [r.item_id] : [])))];
|
|
546
|
+
const seen = await itemsSeenBy(this.db, orgId, ids);
|
|
547
|
+
return this.toViews(rows.filter((r) => r.kind === "connector_setup"
|
|
548
|
+
? r.agent_id !== null && r.agent_deleted_at === null
|
|
549
|
+
: r.item_id !== null && seen.has(r.item_id)));
|
|
472
550
|
}
|
|
473
|
-
/**
|
|
474
|
-
async
|
|
475
|
-
const rows = await this.
|
|
476
|
-
.
|
|
477
|
-
.
|
|
478
|
-
.where("
|
|
479
|
-
.
|
|
551
|
+
/** The inbox: the account's decided requests in the org it has not dismissed, newest first. */
|
|
552
|
+
async listDecidedForRequester(orgId, accountId) {
|
|
553
|
+
const rows = await this.baseQuery()
|
|
554
|
+
.where("r.org_id", "=", orgId)
|
|
555
|
+
.where("r.requested_by", "=", accountId)
|
|
556
|
+
.where("r.status", "in", ["approved", "rejected"])
|
|
557
|
+
.where("r.dismissed_at", "is", null)
|
|
558
|
+
.orderBy("r.decided_at", "desc")
|
|
559
|
+
.orderBy("r.id")
|
|
560
|
+
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
480
561
|
.execute();
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
562
|
+
return this.toViews(rows);
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* The account's own requests in the org, pending and decided (dismissed ones too), newest first;
|
|
566
|
+
* cancelled ones are left out (the Platform tool's `requests.list-mine`).
|
|
567
|
+
*/
|
|
568
|
+
async listForRequester(orgId, accountId) {
|
|
569
|
+
const rows = await this.baseQuery()
|
|
570
|
+
.where("r.org_id", "=", orgId)
|
|
571
|
+
.where("r.requested_by", "=", accountId)
|
|
572
|
+
.where("r.status", "in", ["pending", "approved", "rejected"])
|
|
573
|
+
.orderBy("r.created_at", "desc")
|
|
574
|
+
.orderBy("r.id")
|
|
575
|
+
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
576
|
+
.execute();
|
|
577
|
+
return this.toViews(rows);
|
|
485
578
|
}
|
|
486
579
|
async view(id) {
|
|
487
580
|
const row = await this.baseQuery().where("r.id", "=", id).executeTakeFirst();
|
|
488
581
|
if (!row)
|
|
489
582
|
throw requestNotFound();
|
|
490
|
-
return
|
|
583
|
+
return (await this.toViews([row]))[0];
|
|
584
|
+
}
|
|
585
|
+
/** The views of `rows`, with the display names of the connector templates setup requests name. */
|
|
586
|
+
async toViews(rows) {
|
|
587
|
+
const ids = new Set();
|
|
588
|
+
for (const r of rows) {
|
|
589
|
+
if (r.kind !== "connector_setup")
|
|
590
|
+
continue;
|
|
591
|
+
const def = r.agent_definition;
|
|
592
|
+
for (const c of def?.pendingConnectors ?? []) {
|
|
593
|
+
if ("template" in c.source && UUID_RE.test(c.source.template))
|
|
594
|
+
ids.add(c.source.template);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const names = new Map();
|
|
598
|
+
if (ids.size > 0) {
|
|
599
|
+
const found = await this.db
|
|
600
|
+
.selectFrom("platform_connector_templates")
|
|
601
|
+
.select(["id", "file"])
|
|
602
|
+
.where("id", "in", [...ids])
|
|
603
|
+
.execute();
|
|
604
|
+
for (const t of found) {
|
|
605
|
+
const dn = t.file?.displayName;
|
|
606
|
+
names.set(t.id, dn ?? null);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return rows.map((r) => toView(r, names));
|
|
491
610
|
}
|
|
492
611
|
baseQuery() {
|
|
493
|
-
return this.db
|
|
612
|
+
return (this.db
|
|
494
613
|
.selectFrom("catalog_requests as r")
|
|
495
|
-
.
|
|
614
|
+
.leftJoin("catalog_items as i", "i.id", "r.item_id")
|
|
496
615
|
.innerJoin("orgs as o", "o.id", "r.org_id")
|
|
497
616
|
.leftJoin("accounts as a", "a.id", "r.requested_by")
|
|
617
|
+
// a connector_setup request's agent and its current version (name, pending connectors)
|
|
618
|
+
.leftJoin("agents as ag", "ag.id", "r.agent_id")
|
|
619
|
+
.leftJoin("agent_versions as av", (j) => j.onRef("av.agent_id", "=", "ag.id").onRef("av.version", "=", "ag.current_version"))
|
|
498
620
|
.select([
|
|
621
|
+
"r.agent_id",
|
|
622
|
+
"r.pending_keys",
|
|
623
|
+
"ag.deleted_at as agent_deleted_at",
|
|
624
|
+
"av.definition as agent_definition",
|
|
499
625
|
"r.id",
|
|
500
626
|
"r.org_id",
|
|
501
627
|
"o.name as org_name",
|
|
628
|
+
"r.kind",
|
|
502
629
|
"r.item_id",
|
|
503
630
|
"i.name",
|
|
504
631
|
"i.display_name",
|
|
505
|
-
"r.
|
|
506
|
-
"r.
|
|
632
|
+
"r.marketplace_id",
|
|
633
|
+
"r.entry_name",
|
|
634
|
+
"r.entry_version",
|
|
507
635
|
"r.status",
|
|
508
636
|
"r.note",
|
|
637
|
+
"r.reason",
|
|
509
638
|
"r.requested_by",
|
|
510
639
|
"a.display_name as requested_by_name",
|
|
511
640
|
"r.decided_by",
|
|
512
641
|
"r.decided_at",
|
|
513
|
-
"r.
|
|
514
|
-
"r.org_decided_at",
|
|
642
|
+
"r.staging_id",
|
|
515
643
|
"r.created_at",
|
|
516
|
-
]);
|
|
644
|
+
]));
|
|
517
645
|
}
|
|
518
646
|
};
|
|
519
647
|
__decorate([
|
|
520
648
|
Transactional()
|
|
521
|
-
], CatalogRequestsService.prototype, "
|
|
649
|
+
], CatalogRequestsService.prototype, "authorize", null);
|
|
650
|
+
__decorate([
|
|
651
|
+
Transactional()
|
|
652
|
+
], CatalogRequestsService.prototype, "writeItemRequest", null);
|
|
653
|
+
__decorate([
|
|
654
|
+
Transactional()
|
|
655
|
+
], CatalogRequestsService.prototype, "writeImportRequest", null);
|
|
522
656
|
__decorate([
|
|
523
|
-
Transactional(
|
|
524
|
-
], CatalogRequestsService.prototype, "
|
|
657
|
+
Transactional()
|
|
658
|
+
], CatalogRequestsService.prototype, "pendingOrgRequest", null);
|
|
659
|
+
__decorate([
|
|
660
|
+
WithLock({ key: "catalog-request-#{1}", ttl: 60_000, waitTimeout: 180_000 })
|
|
661
|
+
], CatalogRequestsService.prototype, "approveImport", null);
|
|
525
662
|
__decorate([
|
|
526
|
-
Transactional(
|
|
527
|
-
], CatalogRequestsService.prototype, "
|
|
663
|
+
Transactional()
|
|
664
|
+
], CatalogRequestsService.prototype, "pendingDeploymentRequest", null);
|
|
528
665
|
__decorate([
|
|
529
666
|
Transactional()
|
|
530
|
-
], CatalogRequestsService.prototype, "
|
|
667
|
+
], CatalogRequestsService.prototype, "linkStaging", null);
|
|
531
668
|
__decorate([
|
|
532
669
|
Transactional()
|
|
533
|
-
], CatalogRequestsService.prototype, "
|
|
670
|
+
], CatalogRequestsService.prototype, "writeDecision", null);
|
|
534
671
|
CatalogRequestsService = __decorate([
|
|
535
672
|
Injectable(),
|
|
536
673
|
__param(0, Inject(KernelDb)),
|
|
537
674
|
__param(1, Inject(OrgLock)),
|
|
538
|
-
__param(2, Inject(
|
|
539
|
-
__param(3, Inject(
|
|
675
|
+
__param(2, Inject(SuperAdminLock)),
|
|
676
|
+
__param(3, Inject(OrgCatalogService)),
|
|
677
|
+
__param(4, Inject(CatalogScopeService)),
|
|
678
|
+
__param(5, Inject(CatalogService)),
|
|
679
|
+
__param(6, Inject(KernelConfigService)),
|
|
680
|
+
__param(7, Inject(PluginImport)),
|
|
681
|
+
__param(8, Inject(TransactionHost)),
|
|
682
|
+
__param(9, Inject(LockService))
|
|
540
683
|
], CatalogRequestsService);
|
|
541
684
|
export { CatalogRequestsService };
|
|
542
|
-
|
|
685
|
+
/** The view fields of a `connector_setup` request (ruling P4-T6-5); null for other kinds. */
|
|
686
|
+
function setupFields(r, templateNames) {
|
|
687
|
+
if (r.kind !== "connector_setup" || r.agent_id === null)
|
|
688
|
+
return { agent: null, connectors: null };
|
|
689
|
+
const def = (r.agent_definition ?? null);
|
|
690
|
+
const pending = new Map((def?.pendingConnectors ?? []).map((c) => [c.key, c]));
|
|
691
|
+
const connectors = [];
|
|
692
|
+
for (const key of r.pending_keys ?? []) {
|
|
693
|
+
const c = pending.get(key);
|
|
694
|
+
if (c === undefined)
|
|
695
|
+
continue;
|
|
696
|
+
const src = c.source;
|
|
697
|
+
connectors.push({
|
|
698
|
+
key,
|
|
699
|
+
label: c.label,
|
|
700
|
+
kind: "template" in src ? "template" : "needs",
|
|
701
|
+
source: "template" in src
|
|
702
|
+
? { template: { id: src.template, displayName: templateNames.get(src.template) ?? null } }
|
|
703
|
+
: {
|
|
704
|
+
needs: {
|
|
705
|
+
protocol: src.needs.protocol,
|
|
706
|
+
endpoint: src.needs.endpoint,
|
|
707
|
+
tools: [...src.needs.tools],
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
tools: c.tools !== undefined && c.tools.length > 0 ? [...c.tools] : null,
|
|
711
|
+
// jsonb keeps no key order: sorted
|
|
712
|
+
policies: Object.keys(c.policies ?? {}).sort(),
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
agent: { id: r.agent_id, name: def?.name ?? "", deleted: r.agent_deleted_at !== null },
|
|
717
|
+
connectors,
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function toView(r, templateNames) {
|
|
543
721
|
return {
|
|
544
722
|
id: r.id,
|
|
545
723
|
orgId: r.org_id,
|
|
546
724
|
orgName: r.org_name,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
725
|
+
kind: r.kind,
|
|
726
|
+
item: r.item_id !== null && r.name !== null
|
|
727
|
+
? { id: r.item_id, name: r.name, displayName: r.display_name }
|
|
728
|
+
: null,
|
|
729
|
+
entry: r.entry_name !== null
|
|
730
|
+
? { marketplaceId: r.marketplace_id, name: r.entry_name, version: r.entry_version }
|
|
731
|
+
: null,
|
|
732
|
+
...setupFields(r, templateNames),
|
|
550
733
|
status: r.status,
|
|
551
734
|
note: r.note,
|
|
735
|
+
reason: r.reason,
|
|
552
736
|
requestedBy: r.requested_by,
|
|
553
737
|
requestedByName: r.requested_by_name,
|
|
554
738
|
decidedBy: r.decided_by,
|
|
555
739
|
decidedAt: r.decided_at?.toISOString() ?? null,
|
|
556
|
-
|
|
557
|
-
orgDecidedAt: r.org_decided_at?.toISOString() ?? null,
|
|
740
|
+
stagingId: r.status === "pending" ? r.staging_id : null,
|
|
558
741
|
createdAt: r.created_at.toISOString(),
|
|
559
742
|
};
|
|
560
743
|
}
|