@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +20 -2
- package/bootstrap.json +26 -0
- package/dist/admin/admin.controller.d.ts +139 -0
- package/dist/admin/admin.controller.js +238 -0
- package/dist/admin/extensions.controller.d.ts +100 -0
- package/dist/admin/extensions.controller.js +226 -0
- package/dist/admin/setup.controller.d.ts +36 -0
- package/dist/admin/setup.controller.js +106 -0
- package/dist/admin/setup.service.d.ts +47 -0
- package/dist/admin/setup.service.js +90 -0
- package/dist/agents/agents.controller.d.ts +205 -0
- package/dist/agents/agents.controller.js +144 -0
- package/dist/agents/agents.service.d.ts +177 -0
- package/dist/agents/agents.service.js +677 -0
- package/dist/agents/definition.d.ts +198 -0
- package/dist/agents/definition.js +152 -0
- package/dist/agents/models.controller.d.ts +13 -0
- package/dist/agents/models.controller.js +31 -0
- package/dist/agents/templates.controller.d.ts +15 -0
- package/dist/agents/templates.controller.js +37 -0
- package/dist/agents/templates.d.ts +83 -0
- package/dist/agents/templates.js +173 -0
- package/dist/catalog/admin-catalog.controller.d.ts +143 -0
- package/dist/catalog/admin-catalog.controller.js +245 -0
- package/dist/catalog/catalog.service.d.ts +430 -0
- package/dist/catalog/catalog.service.js +882 -0
- package/dist/catalog/claude/agents.d.ts +27 -0
- package/dist/catalog/claude/agents.js +270 -0
- package/dist/catalog/claude/commands.d.ts +50 -0
- package/dist/catalog/claude/commands.js +179 -0
- package/dist/catalog/claude/manifest.d.ts +69 -0
- package/dist/catalog/claude/manifest.js +134 -0
- package/dist/catalog/claude/marketplace.d.ts +35 -0
- package/dist/catalog/claude/marketplace.js +194 -0
- package/dist/catalog/claude/mcp.d.ts +33 -0
- package/dist/catalog/claude/mcp.js +226 -0
- package/dist/catalog/claude/report.d.ts +86 -0
- package/dist/catalog/claude/report.js +121 -0
- package/dist/catalog/claude/translate.d.ts +56 -0
- package/dist/catalog/claude/translate.js +857 -0
- package/dist/catalog/cli.d.ts +46 -0
- package/dist/catalog/cli.js +211 -0
- package/dist/catalog/git-source.d.ts +127 -0
- package/dist/catalog/git-source.js +520 -0
- package/dist/catalog/marketplace-fetch.d.ts +99 -0
- package/dist/catalog/marketplace-fetch.js +203 -0
- package/dist/catalog/marketplaces.controller.d.ts +97 -0
- package/dist/catalog/marketplaces.controller.js +197 -0
- package/dist/catalog/marketplaces.service.d.ts +340 -0
- package/dist/catalog/marketplaces.service.js +1217 -0
- package/dist/catalog/org-catalog.controller.d.ts +128 -0
- package/dist/catalog/org-catalog.controller.js +277 -0
- package/dist/catalog/org-catalog.service.d.ts +246 -0
- package/dist/catalog/org-catalog.service.js +625 -0
- package/dist/catalog/plugin-import.d.ts +436 -0
- package/dist/catalog/plugin-import.js +1069 -0
- package/dist/catalog/plugin-install.d.ts +447 -0
- package/dist/catalog/plugin-install.js +1333 -0
- package/dist/catalog/plugin-package.d.ts +143 -0
- package/dist/catalog/plugin-package.js +382 -0
- package/dist/catalog/plugin-upgrade.d.ts +222 -0
- package/dist/catalog/plugin-upgrade.js +1219 -0
- package/dist/catalog/requests.service.d.ts +162 -0
- package/dist/catalog/requests.service.js +504 -0
- package/dist/catalog/schema-path.d.ts +7 -0
- package/dist/catalog/schema-path.js +63 -0
- package/dist/catalog/upgrade-targets.d.ts +59 -0
- package/dist/catalog/upgrade-targets.js +90 -0
- package/dist/catalog/versions.d.ts +31 -0
- package/dist/catalog/versions.js +44 -0
- package/dist/channels/actions.d.ts +37 -0
- package/dist/channels/actions.js +121 -0
- package/dist/channels/cards.d.ts +44 -0
- package/dist/channels/cards.js +156 -0
- package/dist/channels/connections.controller.d.ts +59 -0
- package/dist/channels/connections.controller.js +115 -0
- package/dist/channels/connections.service.d.ts +187 -0
- package/dist/channels/connections.service.js +534 -0
- package/dist/channels/features.d.ts +12 -0
- package/dist/channels/features.js +22 -0
- package/dist/channels/inbound.d.ts +120 -0
- package/dist/channels/inbound.js +332 -0
- package/dist/channels/outbound.d.ts +140 -0
- package/dist/channels/outbound.js +1126 -0
- package/dist/channels/phrases.d.ts +100 -0
- package/dist/channels/phrases.js +81 -0
- package/dist/channels/supervisor.d.ts +182 -0
- package/dist/channels/supervisor.js +625 -0
- package/dist/channels/threads.d.ts +29 -0
- package/dist/channels/threads.js +104 -0
- package/dist/channels/webhook-url.d.ts +16 -0
- package/dist/channels/webhook-url.js +34 -0
- package/dist/channels/webhook.controller.d.ts +19 -0
- package/dist/channels/webhook.controller.js +72 -0
- package/dist/channels/webhook.d.ts +73 -0
- package/dist/channels/webhook.js +274 -0
- package/dist/config/docs.d.ts +9 -0
- package/dist/config/docs.js +85 -0
- package/dist/config/env.d.ts +6 -0
- package/dist/config/env.js +73 -0
- package/dist/config/fields.d.ts +42 -0
- package/dist/config/fields.js +214 -0
- package/dist/config/file-source.d.ts +3 -0
- package/dist/config/file-source.js +31 -0
- package/dist/config/load.d.ts +20 -0
- package/dist/config/load.js +98 -0
- package/dist/config/nacos-source.d.ts +31 -0
- package/dist/config/nacos-source.js +229 -0
- package/dist/config/schema.d.ts +237 -0
- package/dist/config/schema.js +1192 -0
- package/dist/config/sources.d.ts +18 -0
- package/dist/config/sources.js +59 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +7 -0
- package/dist/conversations/artifacts.d.ts +52 -0
- package/dist/conversations/artifacts.js +137 -0
- package/dist/conversations/attachments.controller.d.ts +28 -0
- package/dist/conversations/attachments.controller.js +96 -0
- package/dist/conversations/attachments.service.d.ts +180 -0
- package/dist/conversations/attachments.service.js +578 -0
- package/dist/conversations/conversations.controller.d.ts +288 -0
- package/dist/conversations/conversations.controller.js +607 -0
- package/dist/conversations/conversations.service.d.ts +321 -0
- package/dist/conversations/conversations.service.js +754 -0
- package/dist/conversations/event-log.d.ts +122 -0
- package/dist/conversations/event-log.js +259 -0
- package/dist/conversations/events.d.ts +856 -0
- package/dist/conversations/events.js +639 -0
- package/dist/conversations/files.d.ts +92 -0
- package/dist/conversations/files.js +213 -0
- package/dist/conversations/outputs-read.d.ts +34 -0
- package/dist/conversations/outputs-read.js +37 -0
- package/dist/conversations/queue.d.ts +169 -0
- package/dist/conversations/queue.js +527 -0
- package/dist/conversations/sandbox-status.d.ts +21 -0
- package/dist/conversations/sandbox-status.js +24 -0
- package/dist/conversations/selection.d.ts +46 -0
- package/dist/conversations/selection.js +75 -0
- package/dist/conversations/titles.d.ts +93 -0
- package/dist/conversations/titles.js +423 -0
- package/dist/ctx/bus.d.ts +16 -0
- package/dist/ctx/bus.js +101 -0
- package/dist/ctx/create-ctx.d.ts +109 -0
- package/dist/ctx/create-ctx.js +592 -0
- package/dist/ctx/kv.d.ts +4 -0
- package/dist/ctx/kv.js +31 -0
- package/dist/ctx/lock.d.ts +4 -0
- package/dist/ctx/lock.js +39 -0
- package/dist/ctx/namespace.d.ts +6 -0
- package/dist/ctx/namespace.js +12 -0
- package/dist/ctx/queue.d.ts +25 -0
- package/dist/ctx/queue.js +151 -0
- package/dist/ctx/secrets.d.ts +45 -0
- package/dist/ctx/secrets.js +175 -0
- package/dist/db/kernel-schema.d.ts +1122 -0
- package/dist/db/kernel-schema.js +5 -0
- package/dist/db/migrator.d.ts +28 -0
- package/dist/db/migrator.js +140 -0
- package/dist/db/pool.d.ts +21 -0
- package/dist/db/pool.js +28 -0
- package/dist/db/sql-statements.d.ts +34 -0
- package/dist/db/sql-statements.js +168 -0
- package/dist/errors.d.ts +211 -0
- package/dist/errors.js +213 -0
- package/dist/evals/budget.d.ts +61 -0
- package/dist/evals/budget.js +181 -0
- package/dist/evals/diff.d.ts +55 -0
- package/dist/evals/diff.js +133 -0
- package/dist/evals/judge.d.ts +53 -0
- package/dist/evals/judge.js +149 -0
- package/dist/evals/plan.d.ts +47 -0
- package/dist/evals/plan.js +77 -0
- package/dist/evals/reconstruct.d.ts +137 -0
- package/dist/evals/reconstruct.js +322 -0
- package/dist/evals/recorded-tools.d.ts +54 -0
- package/dist/evals/recorded-tools.js +167 -0
- package/dist/evals/run-replay.d.ts +86 -0
- package/dist/evals/run-replay.js +502 -0
- package/dist/evals/runs.controller.d.ts +100 -0
- package/dist/evals/runs.controller.js +199 -0
- package/dist/evals/runs.service.d.ts +275 -0
- package/dist/evals/runs.service.js +836 -0
- package/dist/evals/sets.controller.d.ts +61 -0
- package/dist/evals/sets.controller.js +183 -0
- package/dist/evals/sets.service.d.ts +128 -0
- package/dist/evals/sets.service.js +558 -0
- package/dist/evals/snapshot.d.ts +76 -0
- package/dist/evals/snapshot.js +207 -0
- package/dist/evals/step-replay.d.ts +113 -0
- package/dist/evals/step-replay.js +181 -0
- package/dist/evals/trajectory.controller.d.ts +41 -0
- package/dist/evals/trajectory.controller.js +88 -0
- package/dist/evals/trajectory.d.ts +144 -0
- package/dist/evals/trajectory.js +338 -0
- package/dist/evals/trajectory.service.d.ts +108 -0
- package/dist/evals/trajectory.service.js +323 -0
- package/dist/evals/worker.d.ts +101 -0
- package/dist/evals/worker.js +790 -0
- package/dist/extensions/admin-ops.d.ts +105 -0
- package/dist/extensions/admin-ops.js +353 -0
- package/dist/extensions/admin-view.d.ts +79 -0
- package/dist/extensions/admin-view.js +327 -0
- package/dist/extensions/approvals.d.ts +119 -0
- package/dist/extensions/approvals.js +205 -0
- package/dist/extensions/blobs.d.ts +45 -0
- package/dist/extensions/blobs.js +160 -0
- package/dist/extensions/bootstrap.d.ts +176 -0
- package/dist/extensions/bootstrap.js +535 -0
- package/dist/extensions/cli.d.ts +61 -0
- package/dist/extensions/cli.js +165 -0
- package/dist/extensions/config-json-schema.d.ts +9 -0
- package/dist/extensions/config-json-schema.js +73 -0
- package/dist/extensions/deployment-config.d.ts +138 -0
- package/dist/extensions/deployment-config.js +394 -0
- package/dist/extensions/enabled.d.ts +31 -0
- package/dist/extensions/enabled.js +55 -0
- package/dist/extensions/hooks.d.ts +161 -0
- package/dist/extensions/hooks.js +425 -0
- package/dist/extensions/host.d.ts +577 -0
- package/dist/extensions/host.js +2071 -0
- package/dist/extensions/inflight.d.ts +69 -0
- package/dist/extensions/inflight.js +277 -0
- package/dist/extensions/installs.d.ts +166 -0
- package/dist/extensions/installs.js +253 -0
- package/dist/extensions/instance.d.ts +167 -0
- package/dist/extensions/instance.js +329 -0
- package/dist/extensions/ledger.d.ts +30 -0
- package/dist/extensions/ledger.js +50 -0
- package/dist/extensions/lifecycle.d.ts +80 -0
- package/dist/extensions/lifecycle.js +152 -0
- package/dist/extensions/migrate-lock.d.ts +51 -0
- package/dist/extensions/migrate-lock.js +100 -0
- package/dist/extensions/org-config.controller.d.ts +24 -0
- package/dist/extensions/org-config.controller.js +59 -0
- package/dist/extensions/org-config.d.ts +169 -0
- package/dist/extensions/org-config.js +520 -0
- package/dist/extensions/package.d.ts +115 -0
- package/dist/extensions/package.js +246 -0
- package/dist/extensions/permission-set.d.ts +117 -0
- package/dist/extensions/permission-set.js +184 -0
- package/dist/extensions/permission-view.d.ts +194 -0
- package/dist/extensions/permission-view.js +284 -0
- package/dist/extensions/registry.d.ts +24 -0
- package/dist/extensions/registry.js +56 -0
- package/dist/extensions/resolve.d.ts +12 -0
- package/dist/extensions/resolve.js +71 -0
- package/dist/extensions/sources.d.ts +69 -0
- package/dist/extensions/sources.js +120 -0
- package/dist/extensions/sync.d.ts +40 -0
- package/dist/extensions/sync.js +242 -0
- package/dist/files/previewers.controller.d.ts +46 -0
- package/dist/files/previewers.controller.js +105 -0
- package/dist/files/previewers.d.ts +100 -0
- package/dist/files/previewers.js +250 -0
- package/dist/http/api.module.d.ts +114 -0
- package/dist/http/api.module.js +448 -0
- package/dist/http/app.d.ts +77 -0
- package/dist/http/app.js +220 -0
- package/dist/http/error.filter.d.ts +21 -0
- package/dist/http/error.filter.js +85 -0
- package/dist/http/gateway.module.d.ts +15 -0
- package/dist/http/gateway.module.js +13 -0
- package/dist/http/health.controller.d.ts +26 -0
- package/dist/http/health.controller.js +79 -0
- package/dist/http/nest-logger.d.ts +20 -0
- package/dist/http/nest-logger.js +28 -0
- package/dist/http/plugin-dispatch.d.ts +68 -0
- package/dist/http/plugin-dispatch.js +200 -0
- package/dist/http/tokens.d.ts +131 -0
- package/dist/http/tokens.js +131 -0
- package/dist/http/zod.pipe.d.ts +8 -0
- package/dist/http/zod.pipe.js +14 -0
- package/dist/identity/accounts.d.ts +93 -0
- package/dist/identity/accounts.js +367 -0
- package/dist/identity/api-tokens.d.ts +73 -0
- package/dist/identity/api-tokens.js +197 -0
- package/dist/identity/audit.d.ts +23 -0
- package/dist/identity/audit.js +41 -0
- package/dist/identity/auth.controller.d.ts +40 -0
- package/dist/identity/auth.controller.js +130 -0
- package/dist/identity/auth.guard.d.ts +41 -0
- package/dist/identity/auth.guard.js +162 -0
- package/dist/identity/binding.d.ts +47 -0
- package/dist/identity/binding.js +84 -0
- package/dist/identity/cookies.d.ts +16 -0
- package/dist/identity/cookies.js +32 -0
- package/dist/identity/credential-check.d.ts +17 -0
- package/dist/identity/credential-check.js +24 -0
- package/dist/identity/enterprise-admin.d.ts +14 -0
- package/dist/identity/enterprise-admin.js +27 -0
- package/dist/identity/external.d.ts +106 -0
- package/dist/identity/external.js +337 -0
- package/dist/identity/hash.d.ts +2 -0
- package/dist/identity/hash.js +3 -0
- package/dist/identity/login.d.ts +6 -0
- package/dist/identity/login.js +20 -0
- package/dist/identity/me.controller.d.ts +61 -0
- package/dist/identity/me.controller.js +159 -0
- package/dist/identity/passwords.d.ts +6 -0
- package/dist/identity/passwords.js +37 -0
- package/dist/identity/principal.d.ts +56 -0
- package/dist/identity/principal.js +38 -0
- package/dist/identity/rate-limit.d.ts +55 -0
- package/dist/identity/rate-limit.js +121 -0
- package/dist/identity/sessions.d.ts +84 -0
- package/dist/identity/sessions.js +306 -0
- package/dist/identity/settings.d.ts +121 -0
- package/dist/identity/settings.js +248 -0
- package/dist/identity/sso.controller.d.ts +59 -0
- package/dist/identity/sso.controller.js +192 -0
- package/dist/identity/sso.d.ts +83 -0
- package/dist/identity/sso.js +202 -0
- package/dist/inbox/inbox.service.d.ts +43 -0
- package/dist/inbox/inbox.service.js +57 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +67 -0
- package/dist/kernel.d.ts +259 -0
- package/dist/kernel.js +1326 -0
- package/dist/log-config.d.ts +9 -0
- package/dist/log-config.js +27 -0
- package/dist/log-context.d.ts +32 -0
- package/dist/log-context.js +40 -0
- package/dist/log-loki.d.ts +34 -0
- package/dist/log-loki.js +145 -0
- package/dist/log.d.ts +79 -0
- package/dist/log.js +303 -0
- package/dist/models/prices.d.ts +53 -0
- package/dist/models/prices.js +121 -0
- package/dist/models/purposes.controller.d.ts +19 -0
- package/dist/models/purposes.controller.js +56 -0
- package/dist/models/purposes.d.ts +140 -0
- package/dist/models/purposes.js +267 -0
- package/dist/net/proxy.d.ts +44 -0
- package/dist/net/proxy.js +162 -0
- package/dist/net/public-address.d.ts +60 -0
- package/dist/net/public-address.js +272 -0
- package/dist/net/safe-fetch.d.ts +38 -0
- package/dist/net/safe-fetch.js +140 -0
- package/dist/orgs/directory-sync.controller.d.ts +14 -0
- package/dist/orgs/directory-sync.controller.js +40 -0
- package/dist/orgs/directory-sync.d.ts +166 -0
- package/dist/orgs/directory-sync.js +558 -0
- package/dist/orgs/invitations.controller.d.ts +58 -0
- package/dist/orgs/invitations.controller.js +137 -0
- package/dist/orgs/invitations.service.d.ts +80 -0
- package/dist/orgs/invitations.service.js +217 -0
- package/dist/orgs/members.service.d.ts +63 -0
- package/dist/orgs/members.service.js +234 -0
- package/dist/orgs/offboarding.d.ts +141 -0
- package/dist/orgs/offboarding.js +398 -0
- package/dist/orgs/org-lock.d.ts +32 -0
- package/dist/orgs/org-lock.js +46 -0
- package/dist/orgs/org.guard.d.ts +35 -0
- package/dist/orgs/org.guard.js +95 -0
- package/dist/orgs/orgs.controller.d.ts +78 -0
- package/dist/orgs/orgs.controller.js +192 -0
- package/dist/orgs/orgs.service.d.ts +61 -0
- package/dist/orgs/orgs.service.js +209 -0
- package/dist/orgs/roles.d.ts +13 -0
- package/dist/orgs/roles.js +58 -0
- package/dist/orgs/settings.controller.d.ts +20 -0
- package/dist/orgs/settings.controller.js +53 -0
- package/dist/orgs/settings.service.d.ts +120 -0
- package/dist/orgs/settings.service.js +178 -0
- package/dist/packages/npm.d.ts +50 -0
- package/dist/packages/npm.js +218 -0
- package/dist/packages/provenance.d.ts +47 -0
- package/dist/packages/provenance.js +147 -0
- package/dist/packages/tgz.d.ts +76 -0
- package/dist/packages/tgz.js +225 -0
- package/dist/runtime/abort.d.ts +32 -0
- package/dist/runtime/abort.js +71 -0
- package/dist/runtime/checkpointer.d.ts +32 -0
- package/dist/runtime/checkpointer.js +243 -0
- package/dist/runtime/context/build.d.ts +254 -0
- package/dist/runtime/context/build.js +693 -0
- package/dist/runtime/context/claude-tools.d.ts +11 -0
- package/dist/runtime/context/claude-tools.js +24 -0
- package/dist/runtime/context/compaction.d.ts +26 -0
- package/dist/runtime/context/compaction.js +195 -0
- package/dist/runtime/context/pairing.d.ts +11 -0
- package/dist/runtime/context/pairing.js +82 -0
- package/dist/runtime/context/reminders.d.ts +5 -0
- package/dist/runtime/context/reminders.js +11 -0
- package/dist/runtime/context/skills.d.ts +105 -0
- package/dist/runtime/context/skills.js +283 -0
- package/dist/runtime/context/tokens.d.ts +19 -0
- package/dist/runtime/context/tokens.js +104 -0
- package/dist/runtime/conversation-lock.d.ts +40 -0
- package/dist/runtime/conversation-lock.js +97 -0
- package/dist/runtime/hook-calls.d.ts +84 -0
- package/dist/runtime/hook-calls.js +136 -0
- package/dist/runtime/langgraph-loop.d.ts +52 -0
- package/dist/runtime/langgraph-loop.js +247 -0
- package/dist/runtime/loop.d.ts +93 -0
- package/dist/runtime/loop.js +7 -0
- package/dist/runtime/maintenance.d.ts +80 -0
- package/dist/runtime/maintenance.js +148 -0
- package/dist/runtime/media-cache.d.ts +21 -0
- package/dist/runtime/media-cache.js +51 -0
- package/dist/runtime/model-call.d.ts +176 -0
- package/dist/runtime/model-call.js +1049 -0
- package/dist/runtime/providers.d.ts +86 -0
- package/dist/runtime/providers.js +224 -0
- package/dist/runtime/quota.d.ts +29 -0
- package/dist/runtime/quota.js +70 -0
- package/dist/runtime/run-finish.d.ts +45 -0
- package/dist/runtime/run-finish.js +69 -0
- package/dist/runtime/run-queue.d.ts +121 -0
- package/dist/runtime/run-queue.js +493 -0
- package/dist/runtime/run-worker.d.ts +138 -0
- package/dist/runtime/run-worker.js +806 -0
- package/dist/runtime/stream.controller.d.ts +34 -0
- package/dist/runtime/stream.controller.js +122 -0
- package/dist/runtime/stream.d.ts +63 -0
- package/dist/runtime/stream.js +262 -0
- package/dist/runtime/subagents/child.d.ts +80 -0
- package/dist/runtime/subagents/child.js +225 -0
- package/dist/runtime/subagents/definition.d.ts +103 -0
- package/dist/runtime/subagents/definition.js +392 -0
- package/dist/runtime/subagents/dispatch.d.ts +69 -0
- package/dist/runtime/subagents/dispatch.js +502 -0
- package/dist/runtime/subagents/limits.d.ts +23 -0
- package/dist/runtime/subagents/limits.js +34 -0
- package/dist/runtime/subagents/org-agents.d.ts +50 -0
- package/dist/runtime/subagents/org-agents.js +70 -0
- package/dist/runtime/subagents/preamble.d.ts +7 -0
- package/dist/runtime/subagents/preamble.js +11 -0
- package/dist/runtime/subagents/progress.d.ts +26 -0
- package/dist/runtime/subagents/progress.js +36 -0
- package/dist/runtime/subagents/roster.d.ts +55 -0
- package/dist/runtime/subagents/roster.js +111 -0
- package/dist/runtime/subagents/skill-fork.d.ts +123 -0
- package/dist/runtime/subagents/skill-fork.js +259 -0
- package/dist/runtime/usage-report.d.ts +163 -0
- package/dist/runtime/usage-report.js +551 -0
- package/dist/runtime/waits.d.ts +233 -0
- package/dist/runtime/waits.js +883 -0
- package/dist/sandbox/leases.d.ts +169 -0
- package/dist/sandbox/leases.js +515 -0
- package/dist/sandbox/lifecycle.d.ts +21 -0
- package/dist/sandbox/lifecycle.js +68 -0
- package/dist/sandbox/sandbox.service.d.ts +249 -0
- package/dist/sandbox/sandbox.service.js +908 -0
- package/dist/skills/catalog.d.ts +149 -0
- package/dist/skills/catalog.js +405 -0
- package/dist/skills/changes.controller.d.ts +56 -0
- package/dist/skills/changes.controller.js +136 -0
- package/dist/skills/changes.service.d.ts +175 -0
- package/dist/skills/changes.service.js +805 -0
- package/dist/skills/invocable.controller.d.ts +23 -0
- package/dist/skills/invocable.controller.js +50 -0
- package/dist/skills/invocation-keys.d.ts +23 -0
- package/dist/skills/invocation-keys.js +44 -0
- package/dist/skills/invoke.d.ts +135 -0
- package/dist/skills/invoke.js +286 -0
- package/dist/skills/package.d.ts +87 -0
- package/dist/skills/package.js +227 -0
- package/dist/skills/skills.controller.d.ts +40 -0
- package/dist/skills/skills.controller.js +110 -0
- package/dist/skills/skills.service.d.ts +192 -0
- package/dist/skills/skills.service.js +567 -0
- package/dist/storage/prefix.d.ts +36 -0
- package/dist/storage/prefix.js +104 -0
- package/dist/storage/purge.d.ts +27 -0
- package/dist/storage/purge.js +75 -0
- package/dist/storage/storage.service.d.ts +44 -0
- package/dist/storage/storage.service.js +145 -0
- package/dist/text.d.ts +13 -0
- package/dist/text.js +13 -0
- package/dist/tools/approvals.controller.d.ts +53 -0
- package/dist/tools/approvals.controller.js +128 -0
- package/dist/tools/approvals.service.d.ts +172 -0
- package/dist/tools/approvals.service.js +568 -0
- package/dist/tools/breaker.d.ts +28 -0
- package/dist/tools/breaker.js +72 -0
- package/dist/tools/builtins/agent.d.ts +81 -0
- package/dist/tools/builtins/agent.js +223 -0
- package/dist/tools/builtins/ask-user.d.ts +28 -0
- package/dist/tools/builtins/ask-user.js +139 -0
- package/dist/tools/builtins/read-tool-output.d.ts +18 -0
- package/dist/tools/builtins/read-tool-output.js +108 -0
- package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
- package/dist/tools/builtins/sandbox/bash.js +137 -0
- package/dist/tools/builtins/sandbox/common.d.ts +116 -0
- package/dist/tools/builtins/sandbox/common.js +306 -0
- package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
- package/dist/tools/builtins/sandbox/deliver.js +180 -0
- package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
- package/dist/tools/builtins/sandbox/edit.js +98 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
- package/dist/tools/builtins/sandbox/glob-match.js +240 -0
- package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
- package/dist/tools/builtins/sandbox/glob.js +104 -0
- package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
- package/dist/tools/builtins/sandbox/grep.js +133 -0
- package/dist/tools/builtins/sandbox/index.d.ts +12 -0
- package/dist/tools/builtins/sandbox/index.js +27 -0
- package/dist/tools/builtins/sandbox/names.d.ts +7 -0
- package/dist/tools/builtins/sandbox/names.js +20 -0
- package/dist/tools/builtins/sandbox/read.d.ts +8 -0
- package/dist/tools/builtins/sandbox/read.js +121 -0
- package/dist/tools/builtins/sandbox/write.d.ts +4 -0
- package/dist/tools/builtins/sandbox/write.js +88 -0
- package/dist/tools/builtins/skill-load.d.ts +53 -0
- package/dist/tools/builtins/skill-load.js +446 -0
- package/dist/tools/builtins/skill-write.d.ts +59 -0
- package/dist/tools/builtins/skill-write.js +244 -0
- package/dist/tools/builtins/tool-search.d.ts +31 -0
- package/dist/tools/builtins/tool-search.js +171 -0
- package/dist/tools/connector-content.controller.d.ts +34 -0
- package/dist/tools/connector-content.controller.js +78 -0
- package/dist/tools/connector-content.d.ts +104 -0
- package/dist/tools/connector-content.js +267 -0
- package/dist/tools/connectors.controller.d.ts +210 -0
- package/dist/tools/connectors.controller.js +234 -0
- package/dist/tools/connectors.service.d.ts +303 -0
- package/dist/tools/connectors.service.js +1102 -0
- package/dist/tools/credentials.d.ts +139 -0
- package/dist/tools/credentials.js +351 -0
- package/dist/tools/drift.d.ts +141 -0
- package/dist/tools/drift.js +539 -0
- package/dist/tools/elicitation.d.ts +81 -0
- package/dist/tools/elicitation.js +266 -0
- package/dist/tools/endpoint.d.ts +18 -0
- package/dist/tools/endpoint.js +115 -0
- package/dist/tools/info.d.ts +67 -0
- package/dist/tools/info.js +113 -0
- package/dist/tools/naming.d.ts +27 -0
- package/dist/tools/naming.js +47 -0
- package/dist/tools/oauth/discovery.d.ts +65 -0
- package/dist/tools/oauth/discovery.js +307 -0
- package/dist/tools/oauth/flow.d.ts +63 -0
- package/dist/tools/oauth/flow.js +237 -0
- package/dist/tools/oauth/oauth.controller.d.ts +31 -0
- package/dist/tools/oauth/oauth.controller.js +95 -0
- package/dist/tools/oauth/tokens.d.ts +111 -0
- package/dist/tools/oauth/tokens.js +258 -0
- package/dist/tools/outputs.d.ts +61 -0
- package/dist/tools/outputs.js +156 -0
- package/dist/tools/pipeline.d.ts +322 -0
- package/dist/tools/pipeline.js +1236 -0
- package/dist/tools/policy.d.ts +60 -0
- package/dist/tools/policy.js +236 -0
- package/dist/tools/questions.controller.d.ts +24 -0
- package/dist/tools/questions.controller.js +58 -0
- package/dist/tools/questions.service.d.ts +103 -0
- package/dist/tools/questions.service.js +295 -0
- package/dist/tools/redact.d.ts +20 -0
- package/dist/tools/redact.js +60 -0
- package/dist/tools/registry.d.ts +246 -0
- package/dist/tools/registry.js +481 -0
- package/dist/tools/resources.d.ts +16 -0
- package/dist/tools/resources.js +76 -0
- package/dist/tools/specs.d.ts +14 -0
- package/dist/tools/specs.js +31 -0
- package/dist/tools/validate.d.ts +20 -0
- package/dist/tools/validate.js +183 -0
- package/dist/tools/view.d.ts +43 -0
- package/dist/tools/view.js +225 -0
- package/dist/ui/embed-token.d.ts +31 -0
- package/dist/ui/embed-token.js +132 -0
- package/dist/ui/registry.d.ts +58 -0
- package/dist/ui/registry.js +90 -0
- package/dist/ui/ui-stream.d.ts +37 -0
- package/dist/ui/ui-stream.js +162 -0
- package/dist/ui/views.controller.d.ts +81 -0
- package/dist/ui/views.controller.js +261 -0
- package/dist/ui/views.d.ts +155 -0
- package/dist/ui/views.js +306 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +6 -0
- package/package.json +69 -3
- package/src/migrations/0001_init.sql +8 -0
- package/src/migrations/0002_secrets.sql +8 -0
- package/src/migrations/0003_identity.sql +117 -0
- package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
- package/src/migrations/0005_agents.sql +27 -0
- package/src/migrations/0006_conversations.sql +37 -0
- package/src/migrations/0007_checkpoints.sql +26 -0
- package/src/migrations/0008_runs_trigger_seq.sql +3 -0
- package/src/migrations/0009_runs_active_unique.sql +4 -0
- package/src/migrations/0010_tools.sql +125 -0
- package/src/migrations/0011_approvals_spec.sql +10 -0
- package/src/migrations/0012_run_waits.sql +24 -0
- package/src/migrations/0013_app_tools_source.sql +4 -0
- package/src/migrations/0014_tool_specs.sql +8 -0
- package/src/migrations/0015_tool_drift.sql +20 -0
- package/src/migrations/0016_plugin_permissions.sql +11 -0
- package/src/migrations/0017_identity_sources.sql +6 -0
- package/src/migrations/0018_channels.sql +74 -0
- package/src/migrations/0019_identity_trust.sql +17 -0
- package/src/migrations/0020_channel_card_lookup.sql +10 -0
- package/src/migrations/0021_org_storage_purge.sql +9 -0
- package/src/migrations/0022_attachments.sql +29 -0
- package/src/migrations/0023_sandboxes.sql +37 -0
- package/src/migrations/0024_skills.sql +46 -0
- package/src/migrations/0025_skills_catalog_idx.sql +6 -0
- package/src/migrations/0026_skill_changes.sql +34 -0
- package/src/migrations/0027_model_prices.sql +18 -0
- package/src/migrations/0028_evals.sql +105 -0
- package/src/migrations/0029_model_purposes.sql +18 -0
- package/src/migrations/0030_plugin_installs.sql +73 -0
- package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
- package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
- package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
- package/src/migrations/0034_directory.sql +49 -0
- package/src/migrations/0035_catalogs.sql +40 -0
- package/src/migrations/0036_app_import_staging.sql +17 -0
- package/src/migrations/0037_directory_installs.sql +92 -0
- package/src/migrations/0038_channel_inbound_mode.sql +6 -0
- package/src/migrations/0039_channel_card_pending.sql +8 -0
- package/src/migrations/0040_usage_report_sweep.sql +10 -0
- package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
- package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
- package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
- package/src/migrations/0044_catalog_one_kind.sql +90 -0
- package/src/migrations/0045_plugin_dependencies.sql +9 -0
- package/src/migrations/0046_git_sources.sql +25 -0
- package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
- package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
- package/src/migrations/0049_plugin_upgrades.sql +37 -0
- package/src/migrations/0050_bootstrap.sql +53 -0
- package/src/migrations/0051_claude_compat.sql +26 -0
- package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
- package/src/migrations/0053_subagents.sql +73 -0
- package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
- package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
- package/src/migrations/0056_approval_reason.sql +3 -0
- package/src/migrations/0057_conversation_titles.sql +11 -0
- package/src/migrations/0058_conversation_selection.sql +4 -0
- package/src/migrations/0059_conversation_queue.sql +22 -0
- package/src/migrations/0060_file_previewers.sql +10 -0
- package/src/migrations/0061_queue_selection.sql +5 -0
- package/src/migrations/0062_queued_skill.sql +8 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { LocalizedName } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { type Transaction } from "kysely";
|
|
3
|
+
import type { KernelDatabase, KernelDb } from "../db/kernel-schema.js";
|
|
4
|
+
import { ApiError } from "../errors.js";
|
|
5
|
+
type Trx = Transaction<KernelDatabase>;
|
|
6
|
+
export type CatalogRequestStage = "org" | "deployment";
|
|
7
|
+
export type CatalogRequestStatus = "pending" | "approved" | "rejected" | "cancelled";
|
|
8
|
+
export type CatalogDecision = "approve" | "reject";
|
|
9
|
+
/** A catalog request (the inbox's `catalog_request`, the enterprise admin request list). */
|
|
10
|
+
export interface CatalogRequestView {
|
|
11
|
+
id: string;
|
|
12
|
+
orgId: string;
|
|
13
|
+
orgName: string;
|
|
14
|
+
item: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
displayName: LocalizedName | null;
|
|
18
|
+
};
|
|
19
|
+
version: string | null;
|
|
20
|
+
stage: CatalogRequestStage;
|
|
21
|
+
status: CatalogRequestStatus;
|
|
22
|
+
note: string;
|
|
23
|
+
requestedBy: string | null;
|
|
24
|
+
/** 申请人的显示名(账号已删除为 null)。 */
|
|
25
|
+
requestedByName: string | null;
|
|
26
|
+
decidedBy: string | null;
|
|
27
|
+
decidedAt: string | null;
|
|
28
|
+
/** 组织管理员批准并升级到企业管理员时的批准人与时间(没有升级为 null)。 */
|
|
29
|
+
orgDecidedBy: string | null;
|
|
30
|
+
orgDecidedAt: string | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
}
|
|
33
|
+
/** 申请列表一次最多返回的条数。 */
|
|
34
|
+
export declare const CATALOG_REQUESTS_LIST_MAX = 200;
|
|
35
|
+
/**
|
|
36
|
+
* Before an org creates a component from the catalog (enabling an extension, creating a connector
|
|
37
|
+
* from a template, importing a skill), re-checks the item policy in the caller's transaction (C22):
|
|
38
|
+
* deleted or disabled -> `catalog.item_disabled`; needs_approval without an enterprise admin grant
|
|
39
|
+
* for this org -> `catalog.approval_required`; allow or granted -> passes. A dependency's
|
|
40
|
+
* components pass `approvedBy`, the item the org is installing (spec §10: approval follows the
|
|
41
|
+
* installed plugin only): the dependency's own item must still be live and not disabled, and the
|
|
42
|
+
* approval is judged by `approvedBy`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function assertItemInstallable(t: Trx, orgId: string, itemId: string, approvedBy?: string): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* The extensions among `plugins` whose own catalog item (the non-deleted item with the same name) is
|
|
47
|
+
* disabled (FOR SHARE: exclusive with policy changes). A disabled item is a master switch: no path
|
|
48
|
+
* (direct enabling, its item, another plugin) can newly enable its extension (Ruling M-5).
|
|
49
|
+
*/
|
|
50
|
+
export declare function disabledPluginItems(db: KernelDb | Trx, plugins: readonly string[]): Promise<string[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Throws `catalog.item_disabled` when a plugin's own catalog item is disabled (the message names
|
|
53
|
+
* the plugin).
|
|
54
|
+
*/
|
|
55
|
+
export declare function pluginItemDisabled(names: readonly string[]): ApiError;
|
|
56
|
+
/**
|
|
57
|
+
* When an org enables an extension directly (not by installing from an item, e.g.
|
|
58
|
+
* `PUT /orgs/:orgId/extensions/:extension`), it is judged by every catalog item that brought it into the
|
|
59
|
+
* deployment (`extension_catalog_sources`), and **the strictest wins**: any source disabled ->
|
|
60
|
+
* `catalog.item_disabled`; otherwise any source needs_approval without a grant of that item to the
|
|
61
|
+
* org -> `catalog.approval_required`; all allow / granted -> passes. Deleted items no longer count
|
|
62
|
+
* as sources (an enterprise admin deleting an item withdraws its constraint). No source (not
|
|
63
|
+
* installed through the catalog) -> not bound by catalog policy.
|
|
64
|
+
*/
|
|
65
|
+
export declare function assertPluginSourcesInstallable(t: Trx, orgId: string, plugin: string): Promise<void>;
|
|
66
|
+
/** 审计里带上 PAT(个人令牌发起时)。 */
|
|
67
|
+
export interface RequestActorOpts {
|
|
68
|
+
actorTokenId?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Cancels catalog requests still pending in the caller's transaction (when the item or the org is
|
|
72
|
+
* deleted), status `cancelled` (the decider is the actor). Each one audits
|
|
73
|
+
* `catalog.request_cancelled` (with the reason). Returns how many were cancelled.
|
|
74
|
+
*/
|
|
75
|
+
export declare function cancelPendingRequests(t: Trx, where: {
|
|
76
|
+
itemId: string;
|
|
77
|
+
} | {
|
|
78
|
+
orgId: string;
|
|
79
|
+
}, actor: string, reason: "item_removed" | "org_deleted", opts?: RequestActorOpts): Promise<number>;
|
|
80
|
+
/**
|
|
81
|
+
* Catalog requests and approvals (C22 / F-AF). Two levels:
|
|
82
|
+
* - a member request (stage `org`) goes to the org admins' inbox, an org admin (`catalog.decide`)
|
|
83
|
+
* approves or rejects it; when the item is needs_approval without a grant for this org, approving
|
|
84
|
+
* moves the request to stage `deployment` (still pending) for the enterprise admins to decide;
|
|
85
|
+
* - an org admin installing a needs_approval item without a grant -> creates a stage `deployment`
|
|
86
|
+
* request (or moves the existing pending one there);
|
|
87
|
+
* - an enterprise admin approving a stage `deployment` request -> writes a grant
|
|
88
|
+
* (`catalog_org_grants`, valid across versions), after which org admins can install.
|
|
89
|
+
* One pending request per org and item (partial unique index; org-side writes all run inside the
|
|
90
|
+
* org row lock, in order). No in-process state.
|
|
91
|
+
*/
|
|
92
|
+
export declare class CatalogRequestsService {
|
|
93
|
+
private readonly db;
|
|
94
|
+
constructor(db: KernelDb);
|
|
95
|
+
/**
|
|
96
|
+
* A member request (`catalog.request`, re-checked inside the org row lock). Item missing /
|
|
97
|
+
* deleted -> `catalog.item_not_found`; disabled -> org admins get `catalog.item_disabled`,
|
|
98
|
+
* members get `catalog.item_not_found` (members do not see disabled items). An existing pending
|
|
99
|
+
* request is returned as is (`created: false`), no new one. Audits `catalog.requested`.
|
|
100
|
+
*/
|
|
101
|
+
request(orgId: string, actor: string, itemId: string, input: {
|
|
102
|
+
note?: string | undefined;
|
|
103
|
+
version?: string | undefined;
|
|
104
|
+
}, opts?: RequestActorOpts): Promise<{
|
|
105
|
+
request: CatalogRequestView;
|
|
106
|
+
created: boolean;
|
|
107
|
+
}>;
|
|
108
|
+
private pendingRow;
|
|
109
|
+
/**
|
|
110
|
+
* An org admin installing a needs_approval item without a grant: in the caller's transaction (the
|
|
111
|
+
* caller has locked the org row and re-checked the role) creates a stage `deployment` request; an
|
|
112
|
+
* existing pending request is moved to deployment (a member request goes to the enterprise admins
|
|
113
|
+
* with it). Returns the request id. Audits `catalog.requested`.
|
|
114
|
+
*/
|
|
115
|
+
requestDeployment(t: Trx, orgId: string, actor: string, item: {
|
|
116
|
+
id: string;
|
|
117
|
+
name: string;
|
|
118
|
+
}, version: string | null, opts?: RequestActorOpts): Promise<string>;
|
|
119
|
+
/**
|
|
120
|
+
* 安装成功后:本组织该条目仍 pending 的申请(成员申请 stage org,以及之前因 needs_approval 建的 stage deployment
|
|
121
|
+
* 申请——条目之后改成 allow 再装的就不会一直挂着)标为 approved(安装者即决定人),收件箱与企业管理员列表随之清空。
|
|
122
|
+
* 在调用方事务里执行。
|
|
123
|
+
*/
|
|
124
|
+
resolveByInstall(t: Trx, orgId: string, itemId: string, actor: string, opts?: RequestActorOpts): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* An org admin decides a member request (`catalog.decide`, re-checked inside the org row lock;
|
|
127
|
+
* the request row FOR UPDATE). Not this org's request -> `catalog.request_not_found`; already
|
|
128
|
+
* decided or handed to the enterprise admins -> `catalog.request_decided`. On approval: item
|
|
129
|
+
* deleted or disabled -> `catalog.item_disabled`; needs_approval without a grant -> moved to stage
|
|
130
|
+
* deployment (still pending); otherwise approved. Audits `catalog.request_decided`.
|
|
131
|
+
*/
|
|
132
|
+
decideOrg(orgId: string, actor: string, requestId: string, decision: CatalogDecision, opts?: RequestActorOpts): Promise<CatalogRequestView>;
|
|
133
|
+
/**
|
|
134
|
+
* An enterprise admin decides a stage deployment request (re-checked inside the enterprise admin
|
|
135
|
+
* lock; the request row FOR UPDATE). Missing or still at the org stage ->
|
|
136
|
+
* `catalog.request_not_found`; already decided -> `catalog.request_decided`; on approval, item
|
|
137
|
+
* deleted or disabled -> `catalog.item_disabled`, the request's org deleted ->
|
|
138
|
+
* `catalog.request_not_found`. Approval writes a grant to `catalog_org_grants`. Audits
|
|
139
|
+
* `catalog.request_decided` (with orgId).
|
|
140
|
+
*/
|
|
141
|
+
decideDeployment(actor: string, requestId: string, decision: CatalogDecision, opts?: RequestActorOpts): Promise<CatalogRequestView>;
|
|
142
|
+
/** 企业管理员的申请列表(stage deployment;`status` 缺省 pending),新的在前。 */
|
|
143
|
+
listDeployment(q?: {
|
|
144
|
+
status?: CatalogRequestStatus;
|
|
145
|
+
}): Promise<CatalogRequestView[]>;
|
|
146
|
+
/** 待企业管理员处理的申请数(后台概览)。 */
|
|
147
|
+
countPendingDeployment(): Promise<number>;
|
|
148
|
+
/**
|
|
149
|
+
* 收件箱:当前用户是本组织管理员(实时读角色)时,返回待他处理的成员申请(stage org、pending),新的在前;
|
|
150
|
+
* 否则为空。
|
|
151
|
+
*/
|
|
152
|
+
listForOrgAdmin(orgId: string, accountId: string): Promise<CatalogRequestView[]>;
|
|
153
|
+
/** 本组织各条目最新的一条申请(组织目录列表用)。 */
|
|
154
|
+
latestByItem(orgId: string): Promise<Map<string, {
|
|
155
|
+
id: string;
|
|
156
|
+
stage: CatalogRequestStage;
|
|
157
|
+
status: string;
|
|
158
|
+
}>>;
|
|
159
|
+
view(db: KernelDb | Trx, id: string): Promise<CatalogRequestView>;
|
|
160
|
+
private baseQuery;
|
|
161
|
+
}
|
|
162
|
+
export {};
|
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
import { ApiError } from "../errors.js";
|
|
4
|
+
import { audit } from "../identity/audit.js";
|
|
5
|
+
import { lockEnterpriseAdminsAndAuthorize } from "../identity/enterprise-admin.js";
|
|
6
|
+
import { lockOrgAndAuthorize } from "../orgs/org-lock.js";
|
|
7
|
+
import { roleAtLeast } from "../orgs/roles.js";
|
|
8
|
+
/** 申请列表一次最多返回的条数。 */
|
|
9
|
+
export const CATALOG_REQUESTS_LIST_MAX = 200;
|
|
10
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11
|
+
const requestNotFound = () => new ApiError("catalog.request_not_found", "Catalog request not found");
|
|
12
|
+
const itemNotFound = () => new ApiError("catalog.item_not_found", "Catalog item not found");
|
|
13
|
+
const itemDisabled = () => new ApiError("catalog.item_disabled", "This catalog item is disabled by the enterprise admin and cannot be newly installed");
|
|
14
|
+
/** 在调用方事务里读条目的策略(FOR SHARE:与企业管理员改策略 / 删除互斥)。不存在或已删除 → undefined。 */
|
|
15
|
+
async function lockItem(t, itemId) {
|
|
16
|
+
if (!UUID_RE.test(itemId))
|
|
17
|
+
return undefined;
|
|
18
|
+
return t
|
|
19
|
+
.selectFrom("catalog_items")
|
|
20
|
+
.select(["id", "name", "policy", "deleted_at"])
|
|
21
|
+
.where("id", "=", itemId)
|
|
22
|
+
.forShare()
|
|
23
|
+
.executeTakeFirst();
|
|
24
|
+
}
|
|
25
|
+
async function hasGrant(db, orgId, itemId) {
|
|
26
|
+
const g = await db
|
|
27
|
+
.selectFrom("catalog_org_grants")
|
|
28
|
+
.select("item_id")
|
|
29
|
+
.where("item_id", "=", itemId)
|
|
30
|
+
.where("org_id", "=", orgId)
|
|
31
|
+
.executeTakeFirst();
|
|
32
|
+
return g !== undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Before an org creates a component from the catalog (enabling an extension, creating a connector
|
|
36
|
+
* from a template, importing a skill), re-checks the item policy in the caller's transaction (C22):
|
|
37
|
+
* deleted or disabled -> `catalog.item_disabled`; needs_approval without an enterprise admin grant
|
|
38
|
+
* for this org -> `catalog.approval_required`; allow or granted -> passes. A dependency's
|
|
39
|
+
* components pass `approvedBy`, the item the org is installing (spec §10: approval follows the
|
|
40
|
+
* installed plugin only): the dependency's own item must still be live and not disabled, and the
|
|
41
|
+
* approval is judged by `approvedBy`.
|
|
42
|
+
*/
|
|
43
|
+
export async function assertItemInstallable(t, orgId, itemId, approvedBy = itemId) {
|
|
44
|
+
if (approvedBy !== itemId) {
|
|
45
|
+
const own = await lockItem(t, itemId);
|
|
46
|
+
if (!own || own.deleted_at !== null || own.policy === "disabled")
|
|
47
|
+
throw itemDisabled();
|
|
48
|
+
}
|
|
49
|
+
const item = await lockItem(t, approvedBy);
|
|
50
|
+
if (!item || item.deleted_at !== null || item.policy === "disabled")
|
|
51
|
+
throw itemDisabled();
|
|
52
|
+
if (item.policy === "needs_approval" && !(await hasGrant(t, orgId, approvedBy))) {
|
|
53
|
+
throw new ApiError("catalog.approval_required", "This catalog item needs enterprise admin approval before this organization can install it");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The extensions among `plugins` whose own catalog item (the non-deleted item with the same name) is
|
|
58
|
+
* disabled (FOR SHARE: exclusive with policy changes). A disabled item is a master switch: no path
|
|
59
|
+
* (direct enabling, its item, another plugin) can newly enable its extension (Ruling M-5).
|
|
60
|
+
*/
|
|
61
|
+
export async function disabledPluginItems(db, plugins) {
|
|
62
|
+
if (plugins.length === 0)
|
|
63
|
+
return [];
|
|
64
|
+
const rows = await db
|
|
65
|
+
.selectFrom("catalog_items")
|
|
66
|
+
.select("name")
|
|
67
|
+
.where("name", "in", [...plugins])
|
|
68
|
+
.where("policy", "=", "disabled")
|
|
69
|
+
.where("deleted_at", "is", null)
|
|
70
|
+
.orderBy("name")
|
|
71
|
+
.forShare()
|
|
72
|
+
.execute();
|
|
73
|
+
return [...new Set(rows.map((r) => r.name))];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Throws `catalog.item_disabled` when a plugin's own catalog item is disabled (the message names
|
|
77
|
+
* the plugin).
|
|
78
|
+
*/
|
|
79
|
+
export function pluginItemDisabled(names) {
|
|
80
|
+
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`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* When an org enables an extension directly (not by installing from an item, e.g.
|
|
84
|
+
* `PUT /orgs/:orgId/extensions/:extension`), it is judged by every catalog item that brought it into the
|
|
85
|
+
* deployment (`extension_catalog_sources`), and **the strictest wins**: any source disabled ->
|
|
86
|
+
* `catalog.item_disabled`; otherwise any source needs_approval without a grant of that item to the
|
|
87
|
+
* org -> `catalog.approval_required`; all allow / granted -> passes. Deleted items no longer count
|
|
88
|
+
* as sources (an enterprise admin deleting an item withdraws its constraint). No source (not
|
|
89
|
+
* installed through the catalog) -> not bound by catalog policy.
|
|
90
|
+
*/
|
|
91
|
+
export async function assertPluginSourcesInstallable(t, orgId, plugin) {
|
|
92
|
+
const rows = await t
|
|
93
|
+
.selectFrom("extension_catalog_sources as s")
|
|
94
|
+
.innerJoin("catalog_items as i", "i.id", "s.item_id")
|
|
95
|
+
.select(["i.id", "i.policy"])
|
|
96
|
+
.where("s.plugin", "=", plugin)
|
|
97
|
+
.where("i.deleted_at", "is", null)
|
|
98
|
+
.orderBy("i.id")
|
|
99
|
+
.forShare("i")
|
|
100
|
+
.execute();
|
|
101
|
+
if (rows.some((r) => r.policy === "disabled"))
|
|
102
|
+
throw itemDisabled();
|
|
103
|
+
for (const r of rows) {
|
|
104
|
+
if (r.policy === "needs_approval" && !(await hasGrant(t, orgId, r.id))) {
|
|
105
|
+
throw new ApiError("catalog.approval_required", "A catalog item that brought this extension in needs enterprise admin approval before this organization can enable it");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Cancels catalog requests still pending in the caller's transaction (when the item or the org is
|
|
111
|
+
* deleted), status `cancelled` (the decider is the actor). Each one audits
|
|
112
|
+
* `catalog.request_cancelled` (with the reason). Returns how many were cancelled.
|
|
113
|
+
*/
|
|
114
|
+
export async function cancelPendingRequests(t, where, actor, reason, opts = {}) {
|
|
115
|
+
let q = t
|
|
116
|
+
.updateTable("catalog_requests")
|
|
117
|
+
.set({ status: "cancelled", decided_by: actor, decided_at: sql `now()` })
|
|
118
|
+
.where("status", "=", "pending");
|
|
119
|
+
q =
|
|
120
|
+
"itemId" in where ? q.where("item_id", "=", where.itemId) : q.where("org_id", "=", where.orgId);
|
|
121
|
+
const rows = await q.returning(["id", "org_id", "item_id", "stage"]).execute();
|
|
122
|
+
for (const r of rows) {
|
|
123
|
+
await audit(t, {
|
|
124
|
+
actorAccountId: actor,
|
|
125
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
126
|
+
orgId: r.org_id,
|
|
127
|
+
action: "catalog.request_cancelled",
|
|
128
|
+
target: r.id,
|
|
129
|
+
detail: { itemId: r.item_id, stage: r.stage, reason },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return rows.length;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Catalog requests and approvals (C22 / F-AF). Two levels:
|
|
136
|
+
* - a member request (stage `org`) goes to the org admins' inbox, an org admin (`catalog.decide`)
|
|
137
|
+
* approves or rejects it; when the item is needs_approval without a grant for this org, approving
|
|
138
|
+
* moves the request to stage `deployment` (still pending) for the enterprise admins to decide;
|
|
139
|
+
* - an org admin installing a needs_approval item without a grant -> creates a stage `deployment`
|
|
140
|
+
* request (or moves the existing pending one there);
|
|
141
|
+
* - an enterprise admin approving a stage `deployment` request -> writes a grant
|
|
142
|
+
* (`catalog_org_grants`, valid across versions), after which org admins can install.
|
|
143
|
+
* One pending request per org and item (partial unique index; org-side writes all run inside the
|
|
144
|
+
* org row lock, in order). No in-process state.
|
|
145
|
+
*/
|
|
146
|
+
export class CatalogRequestsService {
|
|
147
|
+
db;
|
|
148
|
+
constructor(db) {
|
|
149
|
+
this.db = db;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A member request (`catalog.request`, re-checked inside the org row lock). Item missing /
|
|
153
|
+
* deleted -> `catalog.item_not_found`; disabled -> org admins get `catalog.item_disabled`,
|
|
154
|
+
* members get `catalog.item_not_found` (members do not see disabled items). An existing pending
|
|
155
|
+
* request is returned as is (`created: false`), no new one. Audits `catalog.requested`.
|
|
156
|
+
*/
|
|
157
|
+
async request(orgId, actor, itemId, input, opts = {}) {
|
|
158
|
+
const r = await this.db.transaction().execute(async (t) => {
|
|
159
|
+
const { role } = await lockOrgAndAuthorize(t, orgId, actor, "catalog.request");
|
|
160
|
+
const item = await lockItem(t, itemId);
|
|
161
|
+
if (!item || item.deleted_at !== null)
|
|
162
|
+
throw itemNotFound();
|
|
163
|
+
// 成员看不到 disabled 的条目(列表、详情、图标一致):同样答 not found,不暴露条目存在
|
|
164
|
+
if (item.policy === "disabled") {
|
|
165
|
+
throw roleAtLeast(role, "admin") ? itemDisabled() : itemNotFound();
|
|
166
|
+
}
|
|
167
|
+
const existing = await this.pendingRow(t, orgId, itemId);
|
|
168
|
+
if (existing)
|
|
169
|
+
return { id: existing.id, created: false };
|
|
170
|
+
const id = randomUUID();
|
|
171
|
+
await t
|
|
172
|
+
.insertInto("catalog_requests")
|
|
173
|
+
.values({
|
|
174
|
+
id,
|
|
175
|
+
org_id: orgId,
|
|
176
|
+
item_id: itemId,
|
|
177
|
+
version: input.version ?? null,
|
|
178
|
+
stage: "org",
|
|
179
|
+
requested_by: actor,
|
|
180
|
+
note: input.note ?? "",
|
|
181
|
+
})
|
|
182
|
+
.execute();
|
|
183
|
+
await audit(t, {
|
|
184
|
+
actorAccountId: actor,
|
|
185
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
186
|
+
orgId,
|
|
187
|
+
action: "catalog.requested",
|
|
188
|
+
target: id,
|
|
189
|
+
detail: { itemId, name: item.name, stage: "org" },
|
|
190
|
+
});
|
|
191
|
+
return { id, created: true };
|
|
192
|
+
});
|
|
193
|
+
return { request: await this.view(this.db, r.id), created: r.created };
|
|
194
|
+
}
|
|
195
|
+
pendingRow(t, orgId, itemId) {
|
|
196
|
+
return t
|
|
197
|
+
.selectFrom("catalog_requests")
|
|
198
|
+
.select(["id", "stage"])
|
|
199
|
+
.where("org_id", "=", orgId)
|
|
200
|
+
.where("item_id", "=", itemId)
|
|
201
|
+
.where("status", "=", "pending")
|
|
202
|
+
.executeTakeFirst();
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* An org admin installing a needs_approval item without a grant: in the caller's transaction (the
|
|
206
|
+
* caller has locked the org row and re-checked the role) creates a stage `deployment` request; an
|
|
207
|
+
* existing pending request is moved to deployment (a member request goes to the enterprise admins
|
|
208
|
+
* with it). Returns the request id. Audits `catalog.requested`.
|
|
209
|
+
*/
|
|
210
|
+
async requestDeployment(t, orgId, actor, item, version, opts = {}) {
|
|
211
|
+
const existing = await this.pendingRow(t, orgId, item.id);
|
|
212
|
+
if (existing) {
|
|
213
|
+
if (existing.stage === "org") {
|
|
214
|
+
await t
|
|
215
|
+
.updateTable("catalog_requests")
|
|
216
|
+
.set({ stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` })
|
|
217
|
+
.where("id", "=", existing.id)
|
|
218
|
+
.execute();
|
|
219
|
+
await audit(t, {
|
|
220
|
+
actorAccountId: actor,
|
|
221
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
222
|
+
orgId,
|
|
223
|
+
action: "catalog.request_decided",
|
|
224
|
+
target: existing.id,
|
|
225
|
+
detail: { itemId: item.id, decision: "approve", stage: "org", escalated: true },
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return existing.id;
|
|
229
|
+
}
|
|
230
|
+
const id = randomUUID();
|
|
231
|
+
await t
|
|
232
|
+
.insertInto("catalog_requests")
|
|
233
|
+
.values({
|
|
234
|
+
id,
|
|
235
|
+
org_id: orgId,
|
|
236
|
+
item_id: item.id,
|
|
237
|
+
version,
|
|
238
|
+
stage: "deployment",
|
|
239
|
+
requested_by: actor,
|
|
240
|
+
})
|
|
241
|
+
.execute();
|
|
242
|
+
await audit(t, {
|
|
243
|
+
actorAccountId: actor,
|
|
244
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
245
|
+
orgId,
|
|
246
|
+
action: "catalog.requested",
|
|
247
|
+
target: id,
|
|
248
|
+
detail: { itemId: item.id, name: item.name, stage: "deployment" },
|
|
249
|
+
});
|
|
250
|
+
return id;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* 安装成功后:本组织该条目仍 pending 的申请(成员申请 stage org,以及之前因 needs_approval 建的 stage deployment
|
|
254
|
+
* 申请——条目之后改成 allow 再装的就不会一直挂着)标为 approved(安装者即决定人),收件箱与企业管理员列表随之清空。
|
|
255
|
+
* 在调用方事务里执行。
|
|
256
|
+
*/
|
|
257
|
+
async resolveByInstall(t, orgId, itemId, actor, opts = {}) {
|
|
258
|
+
const rows = await t
|
|
259
|
+
.updateTable("catalog_requests")
|
|
260
|
+
.set({ status: "approved", decided_by: actor, decided_at: sql `now()` })
|
|
261
|
+
.where("org_id", "=", orgId)
|
|
262
|
+
.where("item_id", "=", itemId)
|
|
263
|
+
.where("status", "=", "pending")
|
|
264
|
+
.returning(["id", "stage"])
|
|
265
|
+
.execute();
|
|
266
|
+
for (const r of rows) {
|
|
267
|
+
await audit(t, {
|
|
268
|
+
actorAccountId: actor,
|
|
269
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
270
|
+
orgId,
|
|
271
|
+
action: "catalog.request_decided",
|
|
272
|
+
target: r.id,
|
|
273
|
+
detail: { itemId, decision: "approve", stage: r.stage, installed: true },
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* An org admin decides a member request (`catalog.decide`, re-checked inside the org row lock;
|
|
279
|
+
* the request row FOR UPDATE). Not this org's request -> `catalog.request_not_found`; already
|
|
280
|
+
* decided or handed to the enterprise admins -> `catalog.request_decided`. On approval: item
|
|
281
|
+
* deleted or disabled -> `catalog.item_disabled`; needs_approval without a grant -> moved to stage
|
|
282
|
+
* deployment (still pending); otherwise approved. Audits `catalog.request_decided`.
|
|
283
|
+
*/
|
|
284
|
+
async decideOrg(orgId, actor, requestId, decision, opts = {}) {
|
|
285
|
+
if (!UUID_RE.test(requestId))
|
|
286
|
+
throw requestNotFound();
|
|
287
|
+
await this.db.transaction().execute(async (t) => {
|
|
288
|
+
await lockOrgAndAuthorize(t, orgId, actor, "catalog.decide");
|
|
289
|
+
const row = await t
|
|
290
|
+
.selectFrom("catalog_requests")
|
|
291
|
+
.select(["id", "item_id", "stage", "status"])
|
|
292
|
+
.where("id", "=", requestId)
|
|
293
|
+
.where("org_id", "=", orgId)
|
|
294
|
+
.forUpdate()
|
|
295
|
+
.executeTakeFirst();
|
|
296
|
+
if (!row)
|
|
297
|
+
throw requestNotFound();
|
|
298
|
+
if (row.status !== "pending" || row.stage !== "org") {
|
|
299
|
+
throw new ApiError("catalog.request_decided", row.status === "pending"
|
|
300
|
+
? "This request is waiting for the enterprise admin"
|
|
301
|
+
: "This request has already been decided");
|
|
302
|
+
}
|
|
303
|
+
let escalated = false;
|
|
304
|
+
if (decision === "approve") {
|
|
305
|
+
const item = await lockItem(t, row.item_id);
|
|
306
|
+
if (!item || item.deleted_at !== null || item.policy === "disabled")
|
|
307
|
+
throw itemDisabled();
|
|
308
|
+
escalated = item.policy === "needs_approval" && !(await hasGrant(t, orgId, row.item_id));
|
|
309
|
+
}
|
|
310
|
+
await t
|
|
311
|
+
.updateTable("catalog_requests")
|
|
312
|
+
.set(escalated
|
|
313
|
+
? { stage: "deployment", org_decided_by: actor, org_decided_at: sql `now()` }
|
|
314
|
+
: {
|
|
315
|
+
status: decision === "approve" ? "approved" : "rejected",
|
|
316
|
+
decided_by: actor,
|
|
317
|
+
decided_at: sql `now()`,
|
|
318
|
+
})
|
|
319
|
+
.where("id", "=", requestId)
|
|
320
|
+
.execute();
|
|
321
|
+
await audit(t, {
|
|
322
|
+
actorAccountId: actor,
|
|
323
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
324
|
+
orgId,
|
|
325
|
+
action: "catalog.request_decided",
|
|
326
|
+
target: requestId,
|
|
327
|
+
detail: { itemId: row.item_id, decision, stage: "org", escalated },
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
return this.view(this.db, requestId);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* An enterprise admin decides a stage deployment request (re-checked inside the enterprise admin
|
|
334
|
+
* lock; the request row FOR UPDATE). Missing or still at the org stage ->
|
|
335
|
+
* `catalog.request_not_found`; already decided -> `catalog.request_decided`; on approval, item
|
|
336
|
+
* deleted or disabled -> `catalog.item_disabled`, the request's org deleted ->
|
|
337
|
+
* `catalog.request_not_found`. Approval writes a grant to `catalog_org_grants`. Audits
|
|
338
|
+
* `catalog.request_decided` (with orgId).
|
|
339
|
+
*/
|
|
340
|
+
async decideDeployment(actor, requestId, decision, opts = {}) {
|
|
341
|
+
if (!UUID_RE.test(requestId))
|
|
342
|
+
throw requestNotFound();
|
|
343
|
+
await this.db.transaction().execute(async (t) => {
|
|
344
|
+
await lockEnterpriseAdminsAndAuthorize(t, actor);
|
|
345
|
+
const row = await t
|
|
346
|
+
.selectFrom("catalog_requests")
|
|
347
|
+
.select(["id", "org_id", "item_id", "stage", "status"])
|
|
348
|
+
.where("id", "=", requestId)
|
|
349
|
+
.forUpdate()
|
|
350
|
+
.executeTakeFirst();
|
|
351
|
+
if (row?.stage !== "deployment")
|
|
352
|
+
throw requestNotFound();
|
|
353
|
+
if (row.status !== "pending") {
|
|
354
|
+
throw new ApiError("catalog.request_decided", "This request has already been decided");
|
|
355
|
+
}
|
|
356
|
+
if (decision === "approve") {
|
|
357
|
+
const item = await lockItem(t, row.item_id);
|
|
358
|
+
if (!item || item.deleted_at !== null || item.policy === "disabled")
|
|
359
|
+
throw itemDisabled();
|
|
360
|
+
const org = await t
|
|
361
|
+
.selectFrom("orgs")
|
|
362
|
+
.select("deleted_at")
|
|
363
|
+
.where("id", "=", row.org_id)
|
|
364
|
+
.executeTakeFirst();
|
|
365
|
+
if (!org || org.deleted_at !== null)
|
|
366
|
+
throw requestNotFound();
|
|
367
|
+
await t
|
|
368
|
+
.insertInto("catalog_org_grants")
|
|
369
|
+
.values({ item_id: row.item_id, org_id: row.org_id, granted_by: actor })
|
|
370
|
+
.onConflict((oc) => oc.columns(["item_id", "org_id"]).doNothing())
|
|
371
|
+
.execute();
|
|
372
|
+
}
|
|
373
|
+
await t
|
|
374
|
+
.updateTable("catalog_requests")
|
|
375
|
+
.set({
|
|
376
|
+
status: decision === "approve" ? "approved" : "rejected",
|
|
377
|
+
decided_by: actor,
|
|
378
|
+
decided_at: sql `now()`,
|
|
379
|
+
})
|
|
380
|
+
.where("id", "=", requestId)
|
|
381
|
+
.execute();
|
|
382
|
+
await audit(t, {
|
|
383
|
+
actorAccountId: actor,
|
|
384
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
385
|
+
orgId: row.org_id,
|
|
386
|
+
action: "catalog.request_decided",
|
|
387
|
+
target: requestId,
|
|
388
|
+
detail: { itemId: row.item_id, decision, stage: "deployment" },
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
return this.view(this.db, requestId);
|
|
392
|
+
}
|
|
393
|
+
/** 企业管理员的申请列表(stage deployment;`status` 缺省 pending),新的在前。 */
|
|
394
|
+
async listDeployment(q = {}) {
|
|
395
|
+
const rows = await this.baseQuery(this.db)
|
|
396
|
+
.where("r.stage", "=", "deployment")
|
|
397
|
+
.where("r.status", "=", q.status ?? "pending")
|
|
398
|
+
.where("o.deleted_at", "is", null)
|
|
399
|
+
.orderBy("r.created_at", "desc")
|
|
400
|
+
.orderBy("r.id")
|
|
401
|
+
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
402
|
+
.execute();
|
|
403
|
+
return rows.map(toView);
|
|
404
|
+
}
|
|
405
|
+
/** 待企业管理员处理的申请数(后台概览)。 */
|
|
406
|
+
async countPendingDeployment() {
|
|
407
|
+
const r = await this.db
|
|
408
|
+
.selectFrom("catalog_requests as r")
|
|
409
|
+
.innerJoin("orgs as o", "o.id", "r.org_id")
|
|
410
|
+
.select(sql `count(*)`.as("n"))
|
|
411
|
+
.where("r.stage", "=", "deployment")
|
|
412
|
+
.where("r.status", "=", "pending")
|
|
413
|
+
.where("o.deleted_at", "is", null)
|
|
414
|
+
.executeTakeFirstOrThrow();
|
|
415
|
+
return Number(r.n);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* 收件箱:当前用户是本组织管理员(实时读角色)时,返回待他处理的成员申请(stage org、pending),新的在前;
|
|
419
|
+
* 否则为空。
|
|
420
|
+
*/
|
|
421
|
+
async listForOrgAdmin(orgId, accountId) {
|
|
422
|
+
const m = await this.db
|
|
423
|
+
.selectFrom("memberships")
|
|
424
|
+
.select("role")
|
|
425
|
+
.where("org_id", "=", orgId)
|
|
426
|
+
.where("account_id", "=", accountId)
|
|
427
|
+
.executeTakeFirst();
|
|
428
|
+
if (!m || !roleAtLeast(m.role, "admin"))
|
|
429
|
+
return [];
|
|
430
|
+
const rows = await this.baseQuery(this.db)
|
|
431
|
+
.where("r.org_id", "=", orgId)
|
|
432
|
+
.where("r.stage", "=", "org")
|
|
433
|
+
.where("r.status", "=", "pending")
|
|
434
|
+
.orderBy("r.created_at", "desc")
|
|
435
|
+
.orderBy("r.id")
|
|
436
|
+
.limit(CATALOG_REQUESTS_LIST_MAX)
|
|
437
|
+
.execute();
|
|
438
|
+
return rows.map(toView);
|
|
439
|
+
}
|
|
440
|
+
/** 本组织各条目最新的一条申请(组织目录列表用)。 */
|
|
441
|
+
async latestByItem(orgId) {
|
|
442
|
+
const rows = await this.db
|
|
443
|
+
.selectFrom("catalog_requests")
|
|
444
|
+
.select(["id", "item_id", "stage", "status", "created_at"])
|
|
445
|
+
.where("org_id", "=", orgId)
|
|
446
|
+
.orderBy("created_at", "asc")
|
|
447
|
+
.execute();
|
|
448
|
+
const out = new Map();
|
|
449
|
+
for (const r of rows)
|
|
450
|
+
out.set(r.item_id, { id: r.id, stage: r.stage, status: r.status });
|
|
451
|
+
return out;
|
|
452
|
+
}
|
|
453
|
+
async view(db, id) {
|
|
454
|
+
const row = await this.baseQuery(db).where("r.id", "=", id).executeTakeFirst();
|
|
455
|
+
if (!row)
|
|
456
|
+
throw requestNotFound();
|
|
457
|
+
return toView(row);
|
|
458
|
+
}
|
|
459
|
+
baseQuery(db) {
|
|
460
|
+
return db
|
|
461
|
+
.selectFrom("catalog_requests as r")
|
|
462
|
+
.innerJoin("catalog_items as i", "i.id", "r.item_id")
|
|
463
|
+
.innerJoin("orgs as o", "o.id", "r.org_id")
|
|
464
|
+
.leftJoin("accounts as a", "a.id", "r.requested_by")
|
|
465
|
+
.select([
|
|
466
|
+
"r.id",
|
|
467
|
+
"r.org_id",
|
|
468
|
+
"o.name as org_name",
|
|
469
|
+
"r.item_id",
|
|
470
|
+
"i.name",
|
|
471
|
+
"i.display_name",
|
|
472
|
+
"r.version",
|
|
473
|
+
"r.stage",
|
|
474
|
+
"r.status",
|
|
475
|
+
"r.note",
|
|
476
|
+
"r.requested_by",
|
|
477
|
+
"a.display_name as requested_by_name",
|
|
478
|
+
"r.decided_by",
|
|
479
|
+
"r.decided_at",
|
|
480
|
+
"r.org_decided_by",
|
|
481
|
+
"r.org_decided_at",
|
|
482
|
+
"r.created_at",
|
|
483
|
+
]);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function toView(r) {
|
|
487
|
+
return {
|
|
488
|
+
id: r.id,
|
|
489
|
+
orgId: r.org_id,
|
|
490
|
+
orgName: r.org_name,
|
|
491
|
+
item: { id: r.item_id, name: r.name, displayName: r.display_name },
|
|
492
|
+
version: r.version,
|
|
493
|
+
stage: r.stage,
|
|
494
|
+
status: r.status,
|
|
495
|
+
note: r.note,
|
|
496
|
+
requestedBy: r.requested_by,
|
|
497
|
+
requestedByName: r.requested_by_name,
|
|
498
|
+
decidedBy: r.decided_by,
|
|
499
|
+
decidedAt: r.decided_at?.toISOString() ?? null,
|
|
500
|
+
orgDecidedBy: r.org_decided_by,
|
|
501
|
+
orgDecidedAt: r.org_decided_at?.toISOString() ?? null,
|
|
502
|
+
createdAt: r.created_at.toISOString(),
|
|
503
|
+
};
|
|
504
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ZodTypeAny } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* zod schema(v4)里是否有点路径 `segs` 指向的字段(连接器模板的 `editableEndpoint` 用):对象按 shape(或非 never 的
|
|
4
|
+
* catchall)、记录类型的任意键、union / 交叉的任一分支;包装(optional、default、pipe 的输入端等)剥掉再看。
|
|
5
|
+
* 空路径即 schema 本身,恒为 true。叶子之下还有路径 → false。
|
|
6
|
+
*/
|
|
7
|
+
export declare function schemaHasPath(schema: ZodTypeAny, segs: string[], depth?: number): boolean;
|