@capybara-hq/kernel 0.1.0-rc.5 → 0.1.0-rc.7
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 +27 -3
- package/dist/admin/admin.controller.d.ts +21 -74
- package/dist/admin/admin.controller.js +50 -50
- package/dist/admin/admin.schemas.d.ts +57 -0
- package/dist/admin/admin.schemas.js +50 -0
- package/dist/admin/extensions.controller.d.ts +10 -0
- package/dist/admin/extensions.controller.js +18 -0
- package/dist/admin/extensions.schemas.d.ts +7 -0
- package/dist/admin/extensions.schemas.js +10 -0
- package/dist/admin/limit-defaults.d.ts +20 -0
- package/dist/admin/limit-defaults.js +10 -0
- package/dist/agents/agent-profile.service.d.ts +7 -5
- package/dist/agents/agent-profile.service.js +14 -9
- package/dist/agents/agents.controller.d.ts +7 -287
- package/dist/agents/agents.controller.js +7 -67
- package/dist/agents/agents.schemas.d.ts +389 -0
- package/dist/agents/agents.schemas.js +126 -0
- package/dist/agents/agents.service.d.ts +16 -6
- package/dist/agents/agents.service.js +75 -19
- package/dist/agents/definition.d.ts +47 -19
- package/dist/agents/definition.js +119 -38
- package/dist/agents/from-template.d.ts +2 -2
- package/dist/agents/from-template.js +76 -45
- package/dist/agents/from-template.service.d.ts +12 -0
- package/dist/agents/from-template.service.js +23 -6
- package/dist/agents/models.controller.d.ts +33 -5
- package/dist/agents/models.controller.js +50 -6
- package/dist/agents/org-templates.d.ts +13 -3
- package/dist/agents/org-templates.js +69 -28
- package/dist/agents/pending-connector-requests.d.ts +2 -0
- package/dist/agents/pending-connector-requests.js +1 -1
- package/dist/agents/pending-connectors.controller.d.ts +1 -1
- package/dist/agents/pending-connectors.controller.js +2 -2
- package/dist/agents/pending-connectors.service.d.ts +2 -2
- package/dist/agents/pending-connectors.service.js +19 -19
- package/dist/agents/profile.d.ts +18 -0
- package/dist/agents/profile.js +5 -1
- package/dist/agents/readiness.controller.d.ts +5 -5
- package/dist/agents/readiness.controller.js +6 -6
- package/dist/agents/templates.controller.d.ts +8 -17
- package/dist/agents/templates.controller.js +13 -31
- package/dist/agents/templates.schemas.d.ts +20 -0
- package/dist/agents/templates.schemas.js +45 -0
- package/dist/background/background.controller.js +3 -2
- package/dist/background/background.schemas.d.ts +10 -0
- package/dist/background/background.schemas.js +16 -0
- package/dist/background/tasks.service.d.ts +1 -1
- package/dist/background/tasks.service.js +7 -2
- package/dist/catalog/admin-catalog.controller.d.ts +4 -57
- package/dist/catalog/admin-catalog.controller.js +8 -45
- package/dist/catalog/admin-catalog.schemas.d.ts +72 -0
- package/dist/catalog/admin-catalog.schemas.js +92 -0
- package/dist/catalog/catalog-content.d.ts +12 -2
- package/dist/catalog/catalog-scope.service.js +8 -2
- package/dist/catalog/catalog.service.d.ts +2 -0
- package/dist/catalog/catalog.service.js +3 -0
- package/dist/catalog/component-scope.controller.d.ts +3 -65
- package/dist/catalog/component-scope.controller.js +3 -56
- package/dist/catalog/component-scope.schemas.d.ts +114 -0
- package/dist/catalog/component-scope.schemas.js +97 -0
- package/dist/catalog/component-scope.service.d.ts +28 -4
- package/dist/catalog/component-scope.service.js +55 -3
- package/dist/catalog/component-state.d.ts +9 -2
- package/dist/catalog/component-state.js +22 -13
- package/dist/catalog/marketplaces.controller.d.ts +5 -35
- package/dist/catalog/marketplaces.controller.js +6 -34
- package/dist/catalog/marketplaces.schemas.d.ts +48 -0
- package/dist/catalog/marketplaces.schemas.js +53 -0
- package/dist/catalog/marketplaces.service.d.ts +15 -1
- package/dist/catalog/marketplaces.service.js +22 -1
- package/dist/catalog/org-catalog.controller.d.ts +6 -62
- package/dist/catalog/org-catalog.controller.js +12 -66
- package/dist/catalog/org-catalog.schemas.d.ts +79 -0
- package/dist/catalog/org-catalog.schemas.js +82 -0
- package/dist/catalog/org-catalog.service.d.ts +9 -2
- package/dist/catalog/org-catalog.service.js +38 -5
- package/dist/catalog/org-extension.controller.d.ts +1 -12
- package/dist/catalog/org-extension.controller.js +1 -10
- package/dist/catalog/org-extension.schemas.d.ts +15 -0
- package/dist/catalog/org-extension.schemas.js +22 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +2 -19
- package/dist/catalog/org-plugin-uploads.controller.js +15 -28
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +20 -0
- package/dist/catalog/org-plugin-uploads.schemas.js +32 -0
- package/dist/catalog/owned-items.d.ts +6 -2
- package/dist/catalog/owned-items.js +16 -4
- package/dist/catalog/platform-components.d.ts +2 -0
- package/dist/catalog/platform-components.js +2 -0
- package/dist/catalog/plugin-import.js +1 -0
- package/dist/catalog/plugin-install.js +1 -1
- package/dist/catalog/requests.service.d.ts +2 -1
- package/dist/catalog/requests.service.js +6 -2
- package/dist/channels/channels.schemas.d.ts +33 -0
- package/dist/channels/channels.schemas.js +34 -0
- package/dist/channels/connections.controller.d.ts +2 -29
- package/dist/channels/connections.controller.js +1 -23
- package/dist/channels/connections.service.d.ts +8 -2
- package/dist/channels/connections.service.js +23 -5
- package/dist/channels/inbound.js +4 -0
- package/dist/config/schema.d.ts +4 -0
- package/dist/config/schema.js +24 -0
- package/dist/conversations/conversations.controller.d.ts +16 -37
- package/dist/conversations/conversations.controller.js +16 -56
- package/dist/conversations/conversations.schemas.d.ts +52 -0
- package/dist/conversations/conversations.schemas.js +79 -0
- package/dist/conversations/conversations.service.d.ts +13 -4
- package/dist/conversations/conversations.service.js +32 -26
- package/dist/conversations/events.d.ts +80 -6
- package/dist/conversations/events.js +60 -5
- package/dist/conversations/message-context.d.ts +28 -0
- package/dist/conversations/message-context.js +56 -0
- package/dist/conversations/queue.d.ts +2 -1
- package/dist/conversations/queue.js +11 -2
- package/dist/ctx/create-ctx.d.ts +15 -1
- package/dist/ctx/create-ctx.js +23 -2
- package/dist/db/kernel-schema.d.ts +44 -0
- package/dist/environments/environments.schemas.d.ts +3 -0
- package/dist/environments/environments.schemas.js +14 -0
- package/dist/environments/environments.service.d.ts +16 -4
- package/dist/environments/environments.service.js +58 -13
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/evals/evals.schemas.d.ts +110 -0
- package/dist/evals/evals.schemas.js +107 -0
- package/dist/evals/reconstruct.js +18 -11
- package/dist/evals/recorded-tools.d.ts +2 -1
- package/dist/evals/recorded-tools.js +11 -3
- package/dist/evals/run-replay.d.ts +8 -1
- package/dist/evals/run-replay.js +17 -2
- package/dist/evals/runs.controller.d.ts +2 -57
- package/dist/evals/runs.controller.js +1 -42
- package/dist/evals/runs.service.d.ts +8 -7
- package/dist/evals/runs.service.js +45 -30
- package/dist/evals/sets.controller.d.ts +2 -28
- package/dist/evals/sets.controller.js +1 -31
- package/dist/evals/sets.service.d.ts +7 -7
- package/dist/evals/sets.service.js +23 -17
- package/dist/evals/snapshot.d.ts +3 -2
- package/dist/evals/snapshot.js +17 -4
- package/dist/evals/step-replay.d.ts +2 -1
- package/dist/evals/step-replay.js +3 -2
- package/dist/extensions/admin-ops.d.ts +5 -3
- package/dist/extensions/admin-ops.js +17 -12
- package/dist/extensions/config-hash.d.ts +10 -0
- package/dist/extensions/config-hash.js +38 -0
- package/dist/extensions/deployment-config.d.ts +16 -1
- package/dist/extensions/deployment-config.js +83 -0
- package/dist/extensions/extensions.module.js +9 -12
- package/dist/extensions/host.d.ts +39 -12
- package/dist/extensions/host.js +129 -51
- package/dist/extensions/installs.d.ts +5 -0
- package/dist/extensions/installs.js +12 -0
- package/dist/extensions/org-config.d.ts +17 -2
- package/dist/extensions/org-config.js +23 -4
- package/dist/extensions/point-defaults.controller.d.ts +2 -8
- package/dist/extensions/point-defaults.controller.js +1 -3
- package/dist/extensions/point-defaults.d.ts +3 -1
- package/dist/extensions/point-defaults.js +4 -2
- package/dist/extensions/point-defaults.schemas.d.ts +9 -0
- package/dist/extensions/point-defaults.schemas.js +14 -0
- package/dist/extensions/state.module.d.ts +9 -0
- package/dist/extensions/state.module.js +38 -0
- package/dist/extensions/unavailable.d.ts +49 -0
- package/dist/extensions/unavailable.js +113 -0
- package/dist/files/previewers.controller.js +2 -3
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +4 -4
- package/dist/files/previewers.schemas.d.ts +10 -0
- package/dist/files/previewers.schemas.js +9 -0
- package/dist/http/api.module.js +4 -0
- package/dist/http/plugin-dispatch.d.ts +4 -1
- package/dist/http/plugin-dispatch.js +14 -2
- package/dist/identity/accounts.d.ts +43 -4
- package/dist/identity/accounts.js +74 -6
- package/dist/identity/auth.guard.js +10 -1
- package/dist/identity/cookies.d.ts +6 -0
- package/dist/identity/cookies.js +14 -0
- package/dist/identity/identity.module.js +3 -0
- package/dist/identity/initial-passwords.controller.d.ts +22 -0
- package/dist/identity/initial-passwords.controller.js +49 -0
- package/dist/identity/initial-passwords.d.ts +61 -0
- package/dist/identity/initial-passwords.job.d.ts +16 -0
- package/dist/identity/initial-passwords.job.js +46 -0
- package/dist/identity/initial-passwords.js +159 -0
- package/dist/identity/me.controller.d.ts +14 -0
- package/dist/identity/me.controller.js +39 -1
- package/dist/identity/principal.d.ts +8 -0
- package/dist/identity/principal.js +8 -0
- package/dist/identity/settings.d.ts +3 -1
- package/dist/identity/settings.js +6 -4
- package/dist/inbox/inbox.schemas.d.ts +8 -0
- package/dist/inbox/inbox.schemas.js +11 -0
- package/dist/inbox/platform-inbox.controller.d.ts +1 -1
- package/dist/inbox/platform-inbox.controller.js +2 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -0
- package/dist/infra/config/kernel-config.service.js +3 -0
- package/dist/infra/events/kernel-events.d.ts +8 -0
- package/dist/lifecycle/kernel-lifecycle.js +4 -0
- package/dist/models/embeddings.d.ts +82 -0
- package/dist/models/embeddings.js +326 -0
- package/dist/models/enablement.controller.d.ts +40 -0
- package/dist/models/enablement.controller.js +74 -0
- package/dist/models/enablement.d.ts +101 -0
- package/dist/models/enablement.js +264 -0
- package/dist/models/models.module.d.ts +5 -1
- package/dist/models/models.module.js +16 -4
- package/dist/models/org-models.schemas.d.ts +8 -0
- package/dist/models/org-models.schemas.js +22 -0
- package/dist/models/prices.d.ts +3 -1
- package/dist/models/prices.js +7 -5
- package/dist/models/purposes.d.ts +30 -6
- package/dist/models/purposes.js +68 -17
- package/dist/orgs/orgs.controller.d.ts +2 -5
- package/dist/orgs/orgs.controller.js +3 -6
- package/dist/orgs/orgs.schemas.d.ts +8 -0
- package/dist/orgs/orgs.schemas.js +16 -0
- package/dist/orgs/orgs.service.d.ts +3 -1
- package/dist/orgs/orgs.service.js +6 -4
- package/dist/orgs/settings.service.d.ts +9 -1
- package/dist/orgs/settings.service.js +20 -5
- package/dist/overrides.d.ts +4 -0
- package/dist/overrides.js +2 -0
- package/dist/platform/errors.d.ts +21 -4
- package/dist/platform/errors.js +45 -6
- package/dist/platform/exclusions.d.ts +2 -3
- package/dist/platform/exclusions.js +68 -831
- package/dist/platform/method.js +1 -1
- package/dist/platform/operation.d.ts +82 -5
- package/dist/platform/operation.js +62 -7
- package/dist/platform/ops/accounts.ops.d.ts +32 -0
- package/dist/platform/ops/accounts.ops.js +291 -0
- package/dist/platform/ops/admin.ops.d.ts +36 -0
- package/dist/platform/ops/admin.ops.js +389 -0
- package/dist/platform/ops/agent-skills.ops.d.ts +24 -0
- package/dist/platform/ops/agent-skills.ops.js +226 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +4 -1
- package/dist/platform/ops/agent-templates.ops.js +194 -14
- package/dist/platform/ops/agents.ops.d.ts +19 -1
- package/dist/platform/ops/agents.ops.js +481 -58
- package/dist/platform/ops/approvals.ops.d.ts +30 -0
- package/dist/platform/ops/approvals.ops.js +116 -0
- package/dist/platform/ops/background.ops.d.ts +14 -0
- package/dist/platform/ops/background.ops.js +134 -0
- package/dist/platform/ops/catalog-admin.ops.d.ts +74 -0
- package/dist/platform/ops/catalog-admin.ops.js +587 -0
- package/dist/platform/ops/channels.ops.d.ts +16 -0
- package/dist/platform/ops/channels.ops.js +195 -0
- package/dist/platform/ops/components.ops.d.ts +46 -0
- package/dist/platform/ops/components.ops.js +853 -0
- package/dist/platform/ops/connectors.ops.d.ts +4 -2
- package/dist/platform/ops/connectors.ops.js +68 -6
- package/dist/platform/ops/conversations.ops.d.ts +30 -0
- package/dist/platform/ops/conversations.ops.js +470 -0
- package/dist/platform/ops/environments.ops.d.ts +26 -0
- package/dist/platform/ops/environments.ops.js +289 -0
- package/dist/platform/ops/errors.d.ts +10 -5
- package/dist/platform/ops/errors.js +19 -11
- package/dist/platform/ops/evals.ops.d.ts +28 -0
- package/dist/platform/ops/evals.ops.js +783 -0
- package/dist/platform/ops/extensions-admin.ops.d.ts +25 -0
- package/dist/platform/ops/extensions-admin.ops.js +344 -0
- package/dist/platform/ops/extensions.ops.d.ts +7 -1
- package/dist/platform/ops/extensions.ops.js +248 -17
- package/dist/platform/ops/inbox.ops.d.ts +25 -0
- package/dist/platform/ops/inbox.ops.js +378 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +7 -1
- package/dist/platform/ops/marketplaces.ops.js +326 -17
- package/dist/platform/ops/models.ops.d.ts +25 -0
- package/dist/platform/ops/models.ops.js +232 -0
- package/dist/platform/ops/org-plugins.ops.d.ts +29 -0
- package/dist/platform/ops/org-plugins.ops.js +329 -0
- package/dist/platform/ops/org-settings.ops.d.ts +16 -0
- package/dist/platform/ops/org-settings.ops.js +102 -0
- package/dist/platform/ops/orgs.ops.d.ts +28 -0
- package/dist/platform/ops/orgs.ops.js +295 -0
- package/dist/platform/ops/other-orgs.d.ts +20 -0
- package/dist/platform/ops/other-orgs.js +72 -0
- package/dist/platform/ops/platform.ops.d.ts +4 -4
- package/dist/platform/ops/platform.ops.js +23 -24
- package/dist/platform/ops/plugins.ops.d.ts +10 -8
- package/dist/platform/ops/plugins.ops.js +176 -77
- package/dist/platform/ops/previewers.ops.d.ts +14 -0
- package/dist/platform/ops/previewers.ops.js +109 -0
- package/dist/platform/ops/requests.ops.js +57 -19
- package/dist/platform/ops/skills.ops.d.ts +5 -1
- package/dist/platform/ops/skills.ops.js +129 -11
- package/dist/platform/ops/unavailable.d.ts +23 -0
- package/dist/platform/ops/unavailable.js +111 -0
- package/dist/platform/parity.d.ts +33 -0
- package/dist/platform/parity.js +272 -0
- package/dist/platform/platform-ops.module.d.ts +32 -0
- package/dist/platform/platform-ops.module.js +78 -11
- package/dist/platform/route-schemas.d.ts +18 -0
- package/dist/platform/route-schemas.js +60 -0
- package/dist/roles/worker.module.js +2 -0
- package/dist/runtime/context/build.d.ts +2 -0
- package/dist/runtime/context/build.js +28 -2
- package/dist/runtime/context/compaction.js +10 -1
- package/dist/runtime/context/run-context.d.ts +65 -0
- package/dist/runtime/context/run-context.js +215 -0
- package/dist/runtime/hook-calls.d.ts +8 -1
- package/dist/runtime/hook-calls.js +40 -9
- package/dist/runtime/model-call.d.ts +8 -3
- package/dist/runtime/model-call.js +30 -6
- package/dist/runtime/providers.d.ts +146 -32
- package/dist/runtime/providers.js +328 -67
- package/dist/runtime/run-context.service.d.ts +65 -0
- package/dist/runtime/run-context.service.js +220 -0
- package/dist/runtime/run-worker.d.ts +6 -1
- package/dist/runtime/run-worker.js +35 -10
- package/dist/runtime/runtime.module.js +2 -0
- package/dist/runtime/subagents/definition.d.ts +15 -15
- package/dist/runtime/subagents/definition.js +49 -118
- package/dist/runtime/usage-report-jobs.d.ts +88 -0
- package/dist/runtime/usage-report-jobs.js +158 -0
- package/dist/runtime/usage-report.d.ts +33 -38
- package/dist/runtime/usage-report.js +152 -84
- package/dist/skills/changes.controller.js +2 -1
- package/dist/skills/changes.service.d.ts +1 -1
- package/dist/skills/changes.service.js +4 -4
- package/dist/skills/invocable.controller.d.ts +1 -1
- package/dist/skills/invocable.controller.js +2 -2
- package/dist/skills/invoke.d.ts +2 -2
- package/dist/skills/invoke.js +8 -1
- package/dist/skills/skills.controller.d.ts +4 -13
- package/dist/skills/skills.controller.js +8 -24
- package/dist/skills/skills.schemas.d.ts +48 -0
- package/dist/skills/skills.schemas.js +61 -0
- package/dist/skills/skills.service.d.ts +11 -1
- package/dist/skills/skills.service.js +37 -14
- package/dist/time-zone.d.ts +5 -0
- package/dist/time-zone.js +19 -0
- package/dist/tools/approvals.controller.js +2 -3
- package/dist/tools/approvals.schemas.d.ts +21 -0
- package/dist/tools/approvals.schemas.js +15 -0
- package/dist/tools/builtin-names.d.ts +10 -8
- package/dist/tools/builtin-names.js +16 -11
- package/dist/tools/builtins/builtin-tools.d.ts +3 -1
- package/dist/tools/builtins/builtin-tools.js +15 -3
- package/dist/tools/builtins/current-time.d.ts +26 -0
- package/dist/tools/builtins/current-time.js +99 -0
- package/dist/tools/builtins/platform.d.ts +19 -2
- package/dist/tools/builtins/platform.js +105 -16
- package/dist/tools/connectors.controller.d.ts +1 -2
- package/dist/tools/connectors.controller.js +1 -4
- package/dist/tools/connectors.schemas.d.ts +12 -0
- package/dist/tools/connectors.schemas.js +19 -0
- package/dist/tools/connectors.service.d.ts +5 -2
- package/dist/tools/connectors.service.js +7 -5
- package/dist/tools/org-tool-switches.d.ts +16 -2
- package/dist/tools/org-tool-switches.js +26 -9
- package/dist/tools/pipeline.js +9 -1
- package/dist/tools/registry.d.ts +48 -51
- package/dist/tools/registry.js +222 -233
- package/package.json +3 -3
- package/src/migrations/0089_model_kinds_usage.sql +38 -0
- package/src/migrations/0090_initial_passwords.sql +27 -0
- package/src/migrations/0091_account_time_zone.sql +4 -0
- package/src/migrations/0092_tools_default_on.sql +27 -0
- package/dist/platform/redact-orgs.d.ts +0 -7
- package/dist/platform/redact-orgs.js +0 -52
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Module } from "@nestjs/common";
|
|
8
|
+
import { SuperAdminLockModule } from "../identity/super-admin.js";
|
|
9
|
+
import { OrgLockModule } from "../orgs/org-lock.js";
|
|
10
|
+
import { StorageModule } from "../storage/storage.module.js";
|
|
11
|
+
import { ExtensionApprovals } from "./approvals.js";
|
|
12
|
+
import { ExtensionBlobs } from "./blobs.js";
|
|
13
|
+
import { EffectiveConfigs } from "./effective-config.js";
|
|
14
|
+
import { ExtensionInstalls } from "./installs.js";
|
|
15
|
+
import { ExtensionRegistryModule } from "./registry.js";
|
|
16
|
+
/**
|
|
17
|
+
* The extension state the model domain reads below the host: the install records with their
|
|
18
|
+
* packages and approvals, and each extension's effective config per org. Apart from
|
|
19
|
+
* `ExtensionsModule` so the model provider registry (and the `ctx.models` broker the host injects)
|
|
20
|
+
* can depend on it without a module cycle (writing-kernel-api: a cycle is cut by moving the shared
|
|
21
|
+
* part into its own provider both sides inject). `ExtensionsModule` re-exports it.
|
|
22
|
+
*/
|
|
23
|
+
let ExtensionStateModule = class ExtensionStateModule {
|
|
24
|
+
};
|
|
25
|
+
ExtensionStateModule = __decorate([
|
|
26
|
+
Module({
|
|
27
|
+
imports: [ExtensionRegistryModule, SuperAdminLockModule, OrgLockModule, StorageModule],
|
|
28
|
+
providers: [ExtensionApprovals, ExtensionBlobs, ExtensionInstalls, EffectiveConfigs],
|
|
29
|
+
exports: [
|
|
30
|
+
ExtensionRegistryModule,
|
|
31
|
+
ExtensionApprovals,
|
|
32
|
+
ExtensionBlobs,
|
|
33
|
+
ExtensionInstalls,
|
|
34
|
+
EffectiveConfigs,
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
], ExtensionStateModule);
|
|
38
|
+
export { ExtensionStateModule };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
2
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
3
|
+
import { type DeploymentExtensionStatus } from "./permission-view.js";
|
|
4
|
+
import { ExtensionRegistry } from "./registry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Why an extension cannot be used right now (Platform tool spec §14.2 problem 1, §14.5 item 4):
|
|
7
|
+
* - `not_deployed`: no install record on the platform (a catalog plugin whose extension was never
|
|
8
|
+
* installed);
|
|
9
|
+
* - `needs_deployment_config`: installed, its deployment config is missing or invalid;
|
|
10
|
+
* - `pending_approval`: its permissions wait for the super admin's approval;
|
|
11
|
+
* - `pending_migration` / `loading`: the platform is still bringing it up;
|
|
12
|
+
* - `dependency`: an extension point it requires has no loaded provider;
|
|
13
|
+
* - `failed`: it failed to load (or its package cannot be read);
|
|
14
|
+
* - `deployment_disabled`: the super admin disabled it on the platform.
|
|
15
|
+
* State only: never a config value or field name.
|
|
16
|
+
*/
|
|
17
|
+
export type ExtensionUnavailableReason = "not_deployed" | "needs_deployment_config" | "pending_approval" | "pending_migration" | "loading" | "dependency" | "failed" | "deployment_disabled";
|
|
18
|
+
/** The deployment status of an extension that is not loaded, and the reason it shows for it. */
|
|
19
|
+
export interface ExtensionUnavailability {
|
|
20
|
+
/** Null when it has no install record (`not_deployed`). */
|
|
21
|
+
status: DeploymentExtensionStatus | null;
|
|
22
|
+
reason: ExtensionUnavailableReason;
|
|
23
|
+
}
|
|
24
|
+
/** The reason an org or the Platform tool shows for a deployment status of a not-loaded extension. */
|
|
25
|
+
export declare function unavailableReason(status: DeploymentExtensionStatus): ExtensionUnavailableReason;
|
|
26
|
+
/**
|
|
27
|
+
* The state of extensions that are not loaded on this replica, derived like the admin console's
|
|
28
|
+
* status ({@link deriveExtensionStatus}) from the install record and the replicas' recent reports,
|
|
29
|
+
* without reading packages: a pending approval and a pending config come from the replicas' rows
|
|
30
|
+
* (`pending` with reason `approval` / `config`). Reads PG on every call (no in-process state).
|
|
31
|
+
*
|
|
32
|
+
* Its inputs differ slightly from the admin view's (`ExtensionAdmin`): there `pendingApproval`
|
|
33
|
+
* compares the package's permission set with the snapshot and `configValid` checks the deployment
|
|
34
|
+
* config, while here both come from what the replicas last reported. They agree once a replica
|
|
35
|
+
* has tried the current package; until then this view says `loading` where the admin view may
|
|
36
|
+
* already say `pending_approval` or `pending_config`.
|
|
37
|
+
*
|
|
38
|
+
* Which extensions count as loaded is this replica's registry: replica-local and transient. During
|
|
39
|
+
* a rollout, or right after an enable or upgrade, one replica may answer `loading` while another
|
|
40
|
+
* has it loaded; the next call (or the next reconcile) converges.
|
|
41
|
+
*/
|
|
42
|
+
export declare class ExtensionAvailability {
|
|
43
|
+
private readonly kdb;
|
|
44
|
+
private readonly config;
|
|
45
|
+
private readonly registry;
|
|
46
|
+
constructor(kdb: KernelDb, config: KernelConfigService, registry: ExtensionRegistry);
|
|
47
|
+
/** For each of `names` not loaded on this replica: its status and reason (loaded ones absent). */
|
|
48
|
+
unavailable(names: readonly string[]): Promise<Map<string, ExtensionUnavailability>>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
11
|
+
import { sql } from "kysely";
|
|
12
|
+
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
13
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
14
|
+
import { STALE_RECONCILE_PERIODS } from "./lifecycle-topics.js";
|
|
15
|
+
import { deriveExtensionStatus } from "./permission-view.js";
|
|
16
|
+
import { ExtensionRegistry } from "./registry.js";
|
|
17
|
+
/** The reason an org or the Platform tool shows for a deployment status of a not-loaded extension. */
|
|
18
|
+
export function unavailableReason(status) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case "pending_config":
|
|
21
|
+
return "needs_deployment_config";
|
|
22
|
+
case "pending_approval":
|
|
23
|
+
return "pending_approval";
|
|
24
|
+
case "pending_migration":
|
|
25
|
+
return "pending_migration";
|
|
26
|
+
case "dependency":
|
|
27
|
+
return "dependency";
|
|
28
|
+
case "failed":
|
|
29
|
+
case "legacy_format":
|
|
30
|
+
return "failed";
|
|
31
|
+
case "disabled":
|
|
32
|
+
return "deployment_disabled";
|
|
33
|
+
// loaded on another replica, or not yet on this one
|
|
34
|
+
case "converging":
|
|
35
|
+
case "enabled":
|
|
36
|
+
return "loading";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The state of extensions that are not loaded on this replica, derived like the admin console's
|
|
41
|
+
* status ({@link deriveExtensionStatus}) from the install record and the replicas' recent reports,
|
|
42
|
+
* without reading packages: a pending approval and a pending config come from the replicas' rows
|
|
43
|
+
* (`pending` with reason `approval` / `config`). Reads PG on every call (no in-process state).
|
|
44
|
+
*
|
|
45
|
+
* Its inputs differ slightly from the admin view's (`ExtensionAdmin`): there `pendingApproval`
|
|
46
|
+
* compares the package's permission set with the snapshot and `configValid` checks the deployment
|
|
47
|
+
* config, while here both come from what the replicas last reported. They agree once a replica
|
|
48
|
+
* has tried the current package; until then this view says `loading` where the admin view may
|
|
49
|
+
* already say `pending_approval` or `pending_config`.
|
|
50
|
+
*
|
|
51
|
+
* Which extensions count as loaded is this replica's registry: replica-local and transient. During
|
|
52
|
+
* a rollout, or right after an enable or upgrade, one replica may answer `loading` while another
|
|
53
|
+
* has it loaded; the next call (or the next reconcile) converges.
|
|
54
|
+
*/
|
|
55
|
+
let ExtensionAvailability = class ExtensionAvailability {
|
|
56
|
+
kdb;
|
|
57
|
+
config;
|
|
58
|
+
registry;
|
|
59
|
+
constructor(kdb, config, registry) {
|
|
60
|
+
this.kdb = kdb;
|
|
61
|
+
this.config = config;
|
|
62
|
+
this.registry = registry;
|
|
63
|
+
}
|
|
64
|
+
/** For each of `names` not loaded on this replica: its status and reason (loaded ones absent). */
|
|
65
|
+
async unavailable(names) {
|
|
66
|
+
const loaded = new Set(this.registry.manifests().map((m) => m.name));
|
|
67
|
+
const wanted = [...new Set(names)].filter((n) => !loaded.has(n));
|
|
68
|
+
const out = new Map();
|
|
69
|
+
if (wanted.length === 0)
|
|
70
|
+
return out;
|
|
71
|
+
const db = this.kdb.db;
|
|
72
|
+
const staleSeconds = STALE_RECONCILE_PERIODS * this.config.get().extensionHost.reconcileIntervalSeconds;
|
|
73
|
+
const [installs, replicas] = await Promise.all([
|
|
74
|
+
db
|
|
75
|
+
.selectFrom("extension_installs")
|
|
76
|
+
.select(["name", "sha256", "desired_state", "migrated_sha"])
|
|
77
|
+
.where("name", "in", wanted)
|
|
78
|
+
.execute(),
|
|
79
|
+
db
|
|
80
|
+
.selectFrom("extension_replica_status")
|
|
81
|
+
.select(["plugin", "state", "reason", "sha256"])
|
|
82
|
+
.where("plugin", "in", wanted)
|
|
83
|
+
.where("heartbeat_at", ">", sql `now() - make_interval(secs => ${staleSeconds})`)
|
|
84
|
+
.execute(),
|
|
85
|
+
]);
|
|
86
|
+
for (const name of wanted) {
|
|
87
|
+
const install = installs.find((i) => i.name === name);
|
|
88
|
+
if (install === undefined) {
|
|
89
|
+
out.set(name, { status: null, reason: "not_deployed" });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const rows = replicas.filter((r) => r.plugin === name);
|
|
93
|
+
const target = rows.filter((r) => r.sha256 === install.sha256);
|
|
94
|
+
const status = deriveExtensionStatus({
|
|
95
|
+
source: "install",
|
|
96
|
+
desired: { sha256: install.sha256, state: install.desired_state },
|
|
97
|
+
pendingApproval: target.some((r) => r.state === "pending" && r.reason === "approval"),
|
|
98
|
+
configValid: !target.some((r) => r.state === "pending" && r.reason === "config"),
|
|
99
|
+
migratedSha: install.migrated_sha,
|
|
100
|
+
replicas: rows,
|
|
101
|
+
});
|
|
102
|
+
out.set(name, { status, reason: unavailableReason(status) });
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
ExtensionAvailability = __decorate([
|
|
108
|
+
Injectable(),
|
|
109
|
+
__param(0, Inject(KernelDb)),
|
|
110
|
+
__param(1, Inject(KernelConfigService)),
|
|
111
|
+
__param(2, Inject(ExtensionRegistry))
|
|
112
|
+
], ExtensionAvailability);
|
|
113
|
+
export { ExtensionAvailability };
|
|
@@ -14,11 +14,10 @@ import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
|
14
14
|
import { ZBody, ZParam, ZQuery } from "../infra/validation/zod-params.js";
|
|
15
15
|
import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
|
|
16
16
|
import { PreviewerRegistry } from "./previewers.js";
|
|
17
|
+
import { FilePreviewersOrderBody } from "./previewers.schemas.js";
|
|
17
18
|
const Id = z.string().min(1).max(100);
|
|
18
19
|
const PreviewQuery = z.object({ locale: z.enum(["zh", "en"]).default("en") });
|
|
19
|
-
const OrderBody =
|
|
20
|
-
items: z.array(z.object({ plugin: Id, id: Id, disabled: z.boolean().default(false) })).max(500),
|
|
21
|
-
});
|
|
20
|
+
const OrderBody = FilePreviewersOrderBody;
|
|
22
21
|
/** The previewer named in a preview path (the other path parameters are read as they are). */
|
|
23
22
|
const PreviewParams = z.object({ plugin: Id, previewerId: Id });
|
|
24
23
|
class FilePreviewQueryDto extends createZodDto(PreviewQuery, "FilePreviewQuery") {
|
|
@@ -61,7 +61,7 @@ export declare class PreviewerRegistry {
|
|
|
61
61
|
}[], actor?: {
|
|
62
62
|
accountId?: string;
|
|
63
63
|
tokenId?: string;
|
|
64
|
-
}): Promise<OrgPreviewerItem[]>;
|
|
64
|
+
}, auditDetail?: Record<string, unknown>): Promise<OrgPreviewerItem[]>;
|
|
65
65
|
/** Replaces the org's rows of the previewers this replica knows, in one transaction. */
|
|
66
66
|
private putIn;
|
|
67
67
|
/** Previewers that take this file (viewer must read the conversation), in the org's order. */
|
package/dist/files/previewers.js
CHANGED
|
@@ -141,7 +141,7 @@ let PreviewerRegistry = class PreviewerRegistry {
|
|
|
141
141
|
* extension that is disabled now (or not loaded here yet) keep their order and `disabled`.
|
|
142
142
|
* Audited as `org.file_previewers.updated`.
|
|
143
143
|
*/
|
|
144
|
-
async put(orgId, items, actor = {}) {
|
|
144
|
+
async put(orgId, items, actor = {}, auditDetail) {
|
|
145
145
|
const known = new Set((await this.ordered(orgId)).map((l) => `${l.plugin}/${l.previewer.id}`));
|
|
146
146
|
const seen = new Set();
|
|
147
147
|
for (const i of items) {
|
|
@@ -151,11 +151,11 @@ let PreviewerRegistry = class PreviewerRegistry {
|
|
|
151
151
|
}
|
|
152
152
|
seen.add(k);
|
|
153
153
|
}
|
|
154
|
-
await this.putIn(orgId, items, known, actor);
|
|
154
|
+
await this.putIn(orgId, items, known, actor, auditDetail);
|
|
155
155
|
return this.list(orgId);
|
|
156
156
|
}
|
|
157
157
|
/** Replaces the org's rows of the previewers this replica knows, in one transaction. */
|
|
158
|
-
async putIn(orgId, items, known, actor) {
|
|
158
|
+
async putIn(orgId, items, known, actor, auditDetail) {
|
|
159
159
|
if (known.size > 0) {
|
|
160
160
|
await this.d.db
|
|
161
161
|
.deleteFrom("file_previewers")
|
|
@@ -180,7 +180,7 @@ let PreviewerRegistry = class PreviewerRegistry {
|
|
|
180
180
|
...(actor.tokenId !== undefined && { actorTokenId: actor.tokenId }),
|
|
181
181
|
orgId,
|
|
182
182
|
action: "org.file_previewers.updated",
|
|
183
|
-
detail: { items },
|
|
183
|
+
detail: { items, ...auditDetail },
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
/** Previewers that take this file (viewer must read the conversation), in the org's order. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { RouteSchemas } from "../platform/route-schemas.js";
|
|
3
|
+
export declare const FilePreviewersOrderBody: z.ZodObject<{
|
|
4
|
+
items: z.ZodArray<z.ZodObject<{
|
|
5
|
+
plugin: z.ZodString;
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
disabled: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
}, z.core.$strip>>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export declare const FILE_PREVIEWER_ROUTES: readonly RouteSchemas[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const Id = z.string().min(1).max(100);
|
|
3
|
+
export const FilePreviewersOrderBody = z.object({
|
|
4
|
+
items: z.array(z.object({ plugin: Id, id: Id, disabled: z.boolean().default(false) })).max(500),
|
|
5
|
+
});
|
|
6
|
+
export const FILE_PREVIEWER_ROUTES = [
|
|
7
|
+
{ route: "GET /api/v1/orgs/:orgId/file-previewers" },
|
|
8
|
+
{ route: "PUT /api/v1/orgs/:orgId/file-previewers", body: FilePreviewersOrderBody },
|
|
9
|
+
];
|
package/dist/http/api.module.js
CHANGED
|
@@ -43,10 +43,12 @@ import { FilePreviewersController } from "../files/previewers.controller.js";
|
|
|
43
43
|
import { AuthController } from "../identity/auth.controller.js";
|
|
44
44
|
import { AuthGuard } from "../identity/auth.guard.js";
|
|
45
45
|
import { IdentityModule } from "../identity/identity.module.js";
|
|
46
|
+
import { InitialPasswordsController } from "../identity/initial-passwords.controller.js";
|
|
46
47
|
import { MeController } from "../identity/me.controller.js";
|
|
47
48
|
import { BindController, MeIdentitiesController, SsoController, } from "../identity/sso.controller.js";
|
|
48
49
|
import { InboxModule } from "../inbox/inbox.module.js";
|
|
49
50
|
import { PlatformInboxController } from "../inbox/platform-inbox.controller.js";
|
|
51
|
+
import { ModelEnablementController } from "../models/enablement.controller.js";
|
|
50
52
|
import { ModelsModule } from "../models/models.module.js";
|
|
51
53
|
import { ModelPurposesController } from "../models/purposes.controller.js";
|
|
52
54
|
import { DirectorySyncController } from "../orgs/directory-sync.controller.js";
|
|
@@ -74,6 +76,7 @@ import { UiController } from "../ui/views.controller.js";
|
|
|
74
76
|
const CONTROLLERS = [
|
|
75
77
|
AuthController,
|
|
76
78
|
MeController,
|
|
79
|
+
InitialPasswordsController,
|
|
77
80
|
OrgsController,
|
|
78
81
|
OrgSettingsController,
|
|
79
82
|
InvitationsController,
|
|
@@ -92,6 +95,7 @@ const CONTROLLERS = [
|
|
|
92
95
|
AgentSaveAsTemplateController,
|
|
93
96
|
PendingConnectorsController,
|
|
94
97
|
ModelsController,
|
|
98
|
+
ModelEnablementController,
|
|
95
99
|
ReadinessController,
|
|
96
100
|
ConversationsController,
|
|
97
101
|
BackgroundController,
|
|
@@ -45,7 +45,10 @@ export declare function createPluginRouter(routes: Route[]): PluginRouter;
|
|
|
45
45
|
* - `req.signal` aborts only when the client disconnects before the response is written (not on
|
|
46
46
|
* normal completion); long-lived handlers use it to unsubscribe;
|
|
47
47
|
* - a throwing handler is logged (path redacted with `redactPath`) and returns 500 `internal` (the
|
|
48
|
-
* error message is not echoed).
|
|
48
|
+
* error message is not echoed), except a `model.hook_denied` `ApiError` that escaped from
|
|
49
|
+
* `ctx.models.embed` (an organization policy hook denied the call, spec B §5.4): a deliberate
|
|
50
|
+
* outcome, not a failure, so it answers 403 `model.hook_denied` with a generic message (the
|
|
51
|
+
* routes are unauthenticated: the policy extension's name and reason are not echoed).
|
|
49
52
|
* - Fastify's own errors (a body over 1 MiB and so on) are mapped to the error envelope by the
|
|
50
53
|
* scope's error handler: 4xx by the common error code table (413 `payload_too_large`, 415
|
|
51
54
|
* `unsupported_media_type` and so on), 5xx are logged and return `internal`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Readable } from "node:stream";
|
|
2
2
|
import FindMyWay from "find-my-way";
|
|
3
|
-
import { errorBody } from "../errors.js";
|
|
3
|
+
import { ApiError, ERROR_CODES, errorBody } from "../errors.js";
|
|
4
4
|
import { ACCESS_COOKIE, REFRESH_COOKIE } from "../identity/cookies.js";
|
|
5
5
|
import { codeForStatus, redactPath } from "./error.filter.js";
|
|
6
6
|
/** 插件路由都在此前缀下(ctx.http.route 已加 `/plugins/<name>` 前缀)。 */
|
|
@@ -47,7 +47,10 @@ export function createPluginRouter(routes) {
|
|
|
47
47
|
* - `req.signal` aborts only when the client disconnects before the response is written (not on
|
|
48
48
|
* normal completion); long-lived handlers use it to unsubscribe;
|
|
49
49
|
* - a throwing handler is logged (path redacted with `redactPath`) and returns 500 `internal` (the
|
|
50
|
-
* error message is not echoed).
|
|
50
|
+
* error message is not echoed), except a `model.hook_denied` `ApiError` that escaped from
|
|
51
|
+
* `ctx.models.embed` (an organization policy hook denied the call, spec B §5.4): a deliberate
|
|
52
|
+
* outcome, not a failure, so it answers 403 `model.hook_denied` with a generic message (the
|
|
53
|
+
* routes are unauthenticated: the policy extension's name and reason are not echoed).
|
|
51
54
|
* - Fastify's own errors (a body over 1 MiB and so on) are mapped to the error envelope by the
|
|
52
55
|
* scope's error handler: 4xx by the common error code table (413 `payload_too_large`, 415
|
|
53
56
|
* `unsupported_media_type` and so on), 5xx are logged and return `internal`.
|
|
@@ -108,6 +111,15 @@ export async function registerPluginDispatch(fastify, getTable, log) {
|
|
|
108
111
|
res = await pluginHandler(webReq);
|
|
109
112
|
}
|
|
110
113
|
catch (err) {
|
|
114
|
+
if (err instanceof ApiError && err.code === "model.hook_denied") {
|
|
115
|
+
log.warn("plugin handler refused: a policy hook denied its model call", {
|
|
116
|
+
method: req.method,
|
|
117
|
+
path: redactPath(path),
|
|
118
|
+
});
|
|
119
|
+
return reply
|
|
120
|
+
.code(ERROR_CODES["model.hook_denied"])
|
|
121
|
+
.send(errorBody(err.code, "An organization policy denied this model call"));
|
|
122
|
+
}
|
|
111
123
|
log.error("plugin handler failed", { method: req.method, path: redactPath(path), err });
|
|
112
124
|
return reply.code(500).send(errorBody("internal", "Internal error"));
|
|
113
125
|
}
|
|
@@ -10,6 +10,11 @@ export interface Account {
|
|
|
10
10
|
email: string | null;
|
|
11
11
|
status: "active" | "disabled";
|
|
12
12
|
isSuperAdmin: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The account signed in with a generated initial password and must set its own before anything
|
|
15
|
+
* else (Platform tool spec §14.5 item 2): the auth guard refuses every other route until then.
|
|
16
|
+
*/
|
|
17
|
+
mustChangePassword: boolean;
|
|
13
18
|
createdAt: Date;
|
|
14
19
|
}
|
|
15
20
|
/** 超级管理员可改的账号字段。 */
|
|
@@ -19,8 +24,8 @@ export type AccountPatch = {
|
|
|
19
24
|
isSuperAdmin?: boolean;
|
|
20
25
|
};
|
|
21
26
|
/** 构造 `Account` 所需的 accounts 列(供跨表查询 select 使用)。 */
|
|
22
|
-
export declare const ACCOUNT_COLUMNS: readonly ["accounts.id", "accounts.display_name", "accounts.email", "accounts.status", "accounts.is_super_admin", "accounts.created_at"];
|
|
23
|
-
type AccountRow = Pick<Selectable<AccountsTable>, "id" | "display_name" | "email" | "status" | "is_super_admin" | "created_at">;
|
|
27
|
+
export declare const ACCOUNT_COLUMNS: readonly ["accounts.id", "accounts.display_name", "accounts.email", "accounts.status", "accounts.is_super_admin", "accounts.must_change_password", "accounts.created_at"];
|
|
28
|
+
type AccountRow = Pick<Selectable<AccountsTable>, "id" | "display_name" | "email" | "status" | "is_super_admin" | "must_change_password" | "created_at">;
|
|
24
29
|
export declare function toAccount(r: AccountRow): Account;
|
|
25
30
|
export interface LocalAccountInput {
|
|
26
31
|
login: string;
|
|
@@ -28,6 +33,18 @@ export interface LocalAccountInput {
|
|
|
28
33
|
displayName: string;
|
|
29
34
|
email?: string;
|
|
30
35
|
superAdmin?: boolean;
|
|
36
|
+
/** The account must set its own password at first sign-in (a generated initial password). */
|
|
37
|
+
mustChangePassword?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Options of {@link AccountsService.createByAdmin}. */
|
|
40
|
+
export interface AdminCreateOptions {
|
|
41
|
+
/** Merged into the `account.created` audit detail (e.g. the Platform tool's `via: "agent"`). */
|
|
42
|
+
auditDetail?: Record<string, unknown>;
|
|
43
|
+
/**
|
|
44
|
+
* Runs in the creation's transaction right after the insert (the generated password is sealed
|
|
45
|
+
* there), so the account and what goes with it commit or roll back together.
|
|
46
|
+
*/
|
|
47
|
+
inTransaction?: (account: Account) => Promise<void>;
|
|
31
48
|
}
|
|
32
49
|
/**
|
|
33
50
|
* Accounts: local account creation, authentication and administration. Every write is
|
|
@@ -54,7 +71,14 @@ export declare class AccountsService {
|
|
|
54
71
|
* `forbidden`), creates the account and audits `account.created`. The hash is computed before
|
|
55
72
|
* the lock.
|
|
56
73
|
*/
|
|
57
|
-
createByAdmin(input: LocalAccountInput, actorAccountId: string, actorTokenId?: string): Promise<Account>;
|
|
74
|
+
createByAdmin(input: LocalAccountInput, actorAccountId: string, actorTokenId?: string, opts?: AdminCreateOptions): Promise<Account>;
|
|
75
|
+
/**
|
|
76
|
+
* Whether `login` is free for a new local account (`account.login_taken` otherwise) and well
|
|
77
|
+
* formed (`validation_failed`): the read a caller checks before asking a person to confirm.
|
|
78
|
+
*/
|
|
79
|
+
assertLoginFree(login: string): Promise<void>;
|
|
80
|
+
/** The local login of each account that has one (accounts without are left out). */
|
|
81
|
+
localLogins(accountIds: readonly string[]): Promise<Map<string, string>>;
|
|
58
82
|
private createByAdminIn;
|
|
59
83
|
/**
|
|
60
84
|
* CLI: creates a super admin without checking whether the deployment is set up; a taken
|
|
@@ -75,6 +99,19 @@ export declare class AccountsService {
|
|
|
75
99
|
/** 按账号 id 校验本地密码(改密码时核对旧密码);没有本地密码、超长或不符 → false。 */
|
|
76
100
|
verifyPassword(accountId: string, password: string): Promise<boolean>;
|
|
77
101
|
get(id: string): Promise<Account | undefined>;
|
|
102
|
+
/**
|
|
103
|
+
* A person's preferences (run context spec §3.4): `timeZone` is their time zone setting (IANA),
|
|
104
|
+
* null = follow the browser. Missing account → null.
|
|
105
|
+
*/
|
|
106
|
+
preferences(accountId: string): Promise<{
|
|
107
|
+
timeZone: string | null;
|
|
108
|
+
}>;
|
|
109
|
+
/** Sets a person's preferences (the caller validated the time zone). */
|
|
110
|
+
setPreferences(accountId: string, prefs: {
|
|
111
|
+
timeZone: string | null;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
timeZone: string | null;
|
|
114
|
+
}>;
|
|
78
115
|
/** 按 id 升序分页,`after` 为上一页最后一个 id。 */
|
|
79
116
|
list(opts: {
|
|
80
117
|
limit: number;
|
|
@@ -97,7 +134,9 @@ export declare class AccountsService {
|
|
|
97
134
|
* all or nothing; returns the revoked session ids, whose Redis markers the caller writes after
|
|
98
135
|
* the commit (the fast path; a failure is only a warning: auth reads PG).
|
|
99
136
|
*/
|
|
100
|
-
updateAccount(id: string, patch: AccountPatch, actorAccountId: string, actorTokenId?: string
|
|
137
|
+
updateAccount(id: string, patch: AccountPatch, actorAccountId: string, actorTokenId?: string, opts?: {
|
|
138
|
+
auditDetail?: Record<string, unknown>;
|
|
139
|
+
}): Promise<{
|
|
101
140
|
account: Account;
|
|
102
141
|
revokedSessionIds: string[];
|
|
103
142
|
}>;
|
|
@@ -26,6 +26,7 @@ export const ACCOUNT_COLUMNS = [
|
|
|
26
26
|
"accounts.email",
|
|
27
27
|
"accounts.status",
|
|
28
28
|
"accounts.is_super_admin",
|
|
29
|
+
"accounts.must_change_password",
|
|
29
30
|
"accounts.created_at",
|
|
30
31
|
];
|
|
31
32
|
export function toAccount(r) {
|
|
@@ -35,6 +36,7 @@ export function toAccount(r) {
|
|
|
35
36
|
email: r.email,
|
|
36
37
|
status: r.status,
|
|
37
38
|
isSuperAdmin: r.is_super_admin,
|
|
39
|
+
mustChangePassword: r.must_change_password,
|
|
38
40
|
createdAt: r.created_at,
|
|
39
41
|
};
|
|
40
42
|
}
|
|
@@ -87,10 +89,37 @@ let AccountsService = class AccountsService {
|
|
|
87
89
|
* `forbidden`), creates the account and audits `account.created`. The hash is computed before
|
|
88
90
|
* the lock.
|
|
89
91
|
*/
|
|
90
|
-
async createByAdmin(input, actorAccountId, actorTokenId) {
|
|
91
|
-
return this.createByAdminIn(await prepareLocal(input), actorAccountId, actorTokenId);
|
|
92
|
+
async createByAdmin(input, actorAccountId, actorTokenId, opts = {}) {
|
|
93
|
+
return this.createByAdminIn(await prepareLocal(input), actorAccountId, actorTokenId, opts);
|
|
92
94
|
}
|
|
93
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Whether `login` is free for a new local account (`account.login_taken` otherwise) and well
|
|
97
|
+
* formed (`validation_failed`): the read a caller checks before asking a person to confirm.
|
|
98
|
+
*/
|
|
99
|
+
async assertLoginFree(login) {
|
|
100
|
+
const external = normalizeLogin(login);
|
|
101
|
+
const taken = await this.db
|
|
102
|
+
.selectFrom("identities")
|
|
103
|
+
.select("account_id")
|
|
104
|
+
.where("source", "=", "local")
|
|
105
|
+
.where("external_id", "=", external)
|
|
106
|
+
.executeTakeFirst();
|
|
107
|
+
if (taken)
|
|
108
|
+
throw new ApiError("account.login_taken", "Login is already taken");
|
|
109
|
+
}
|
|
110
|
+
/** The local login of each account that has one (accounts without are left out). */
|
|
111
|
+
async localLogins(accountIds) {
|
|
112
|
+
if (accountIds.length === 0)
|
|
113
|
+
return new Map();
|
|
114
|
+
const rows = await this.db
|
|
115
|
+
.selectFrom("identities")
|
|
116
|
+
.select(["account_id", "external_id"])
|
|
117
|
+
.where("source", "=", "local")
|
|
118
|
+
.where("account_id", "in", accountIds)
|
|
119
|
+
.execute();
|
|
120
|
+
return new Map(rows.map((r) => [r.account_id, r.external_id]));
|
|
121
|
+
}
|
|
122
|
+
async createByAdminIn(prepared, actorAccountId, actorTokenId, opts) {
|
|
94
123
|
await this.adminLock.lockAndAuthorize(actorAccountId);
|
|
95
124
|
const a = await this.insertLocal(prepared);
|
|
96
125
|
await audit(this.db.db, {
|
|
@@ -98,8 +127,13 @@ let AccountsService = class AccountsService {
|
|
|
98
127
|
...(actorTokenId !== undefined && { actorTokenId }),
|
|
99
128
|
action: "account.created",
|
|
100
129
|
target: a.id,
|
|
101
|
-
detail: {
|
|
130
|
+
detail: {
|
|
131
|
+
superAdmin: a.isSuperAdmin,
|
|
132
|
+
...(a.mustChangePassword && { mustChangePassword: true }),
|
|
133
|
+
...opts.auditDetail,
|
|
134
|
+
},
|
|
102
135
|
});
|
|
136
|
+
await opts.inTransaction?.(a);
|
|
103
137
|
return a;
|
|
104
138
|
}
|
|
105
139
|
/**
|
|
@@ -164,6 +198,7 @@ let AccountsService = class AccountsService {
|
|
|
164
198
|
"accounts.email_verified",
|
|
165
199
|
"accounts.status",
|
|
166
200
|
"accounts.is_super_admin",
|
|
201
|
+
"accounts.must_change_password",
|
|
167
202
|
"accounts.created_at",
|
|
168
203
|
"accounts.updated_at",
|
|
169
204
|
"local_passwords.password_hash",
|
|
@@ -201,6 +236,27 @@ let AccountsService = class AccountsService {
|
|
|
201
236
|
.executeTakeFirst();
|
|
202
237
|
return row && toAccount(row);
|
|
203
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* A person's preferences (run context spec §3.4): `timeZone` is their time zone setting (IANA),
|
|
241
|
+
* null = follow the browser. Missing account → null.
|
|
242
|
+
*/
|
|
243
|
+
async preferences(accountId) {
|
|
244
|
+
const row = await this.db
|
|
245
|
+
.selectFrom("accounts")
|
|
246
|
+
.select("time_zone")
|
|
247
|
+
.where("id", "=", accountId)
|
|
248
|
+
.executeTakeFirst();
|
|
249
|
+
return { timeZone: row?.time_zone ?? null };
|
|
250
|
+
}
|
|
251
|
+
/** Sets a person's preferences (the caller validated the time zone). */
|
|
252
|
+
async setPreferences(accountId, prefs) {
|
|
253
|
+
await this.db
|
|
254
|
+
.updateTable("accounts")
|
|
255
|
+
.set({ time_zone: prefs.timeZone, updated_at: new Date() })
|
|
256
|
+
.where("id", "=", accountId)
|
|
257
|
+
.execute();
|
|
258
|
+
return this.preferences(accountId);
|
|
259
|
+
}
|
|
204
260
|
/** 按 id 升序分页,`after` 为上一页最后一个 id。 */
|
|
205
261
|
async list(opts) {
|
|
206
262
|
let q = this.db.selectFrom("accounts").selectAll().orderBy("id").limit(opts.limit);
|
|
@@ -224,6 +280,17 @@ let AccountsService = class AccountsService {
|
|
|
224
280
|
}
|
|
225
281
|
async changePasswordIn(accountId, passwordHash, exceptSessionId) {
|
|
226
282
|
await this.writePassword(accountId, passwordHash);
|
|
283
|
+
// the person set their own password: the generated one is no longer theirs to be shown
|
|
284
|
+
await this.db
|
|
285
|
+
.updateTable("accounts")
|
|
286
|
+
.set({ must_change_password: false })
|
|
287
|
+
.where("id", "=", accountId)
|
|
288
|
+
.where("must_change_password", "=", true)
|
|
289
|
+
.execute();
|
|
290
|
+
await this.db
|
|
291
|
+
.deleteFrom("account_initial_passwords")
|
|
292
|
+
.where("account_id", "=", accountId)
|
|
293
|
+
.execute();
|
|
227
294
|
const sessions = await this.db
|
|
228
295
|
.updateTable("sessions")
|
|
229
296
|
.set({ revoked_at: sql `now()` })
|
|
@@ -250,7 +317,7 @@ let AccountsService = class AccountsService {
|
|
|
250
317
|
* all or nothing; returns the revoked session ids, whose Redis markers the caller writes after
|
|
251
318
|
* the commit (the fast path; a failure is only a warning: auth reads PG).
|
|
252
319
|
*/
|
|
253
|
-
async updateAccount(id, patch, actorAccountId, actorTokenId) {
|
|
320
|
+
async updateAccount(id, patch, actorAccountId, actorTokenId, opts = {}) {
|
|
254
321
|
// Every super admin write is serialized by one lock and re-checks the actor under it: two
|
|
255
322
|
// admins revoking each other concurrently cannot leave none, and a just-revoked admin's
|
|
256
323
|
// request in flight fails
|
|
@@ -265,7 +332,7 @@ let AccountsService = class AccountsService {
|
|
|
265
332
|
return this.applyUpdate(before, patch, {
|
|
266
333
|
actorAccountId,
|
|
267
334
|
...(actorTokenId !== undefined && { actorTokenId }),
|
|
268
|
-
detail: patch,
|
|
335
|
+
detail: { ...patch, ...opts.auditDetail },
|
|
269
336
|
});
|
|
270
337
|
}
|
|
271
338
|
/**
|
|
@@ -335,6 +402,7 @@ let AccountsService = class AccountsService {
|
|
|
335
402
|
display_name: input.displayName,
|
|
336
403
|
email: input.email ?? null,
|
|
337
404
|
is_super_admin: input.superAdmin ?? false,
|
|
405
|
+
must_change_password: input.mustChangePassword ?? false,
|
|
338
406
|
})
|
|
339
407
|
.returningAll()
|
|
340
408
|
.executeTakeFirstOrThrow();
|
|
@@ -13,7 +13,7 @@ import { ApiError } from "../errors.js";
|
|
|
13
13
|
import { AccountsService } from "./accounts.js";
|
|
14
14
|
import { ApiTokenService } from "./api-tokens.js";
|
|
15
15
|
import { ACCESS_COOKIE } from "./cookies.js";
|
|
16
|
-
import { ALLOW_SERVICE_KEY, PUBLIC_KEY, SESSION_ONLY_KEY, SUPER_ADMIN_KEY, } from "./principal.js";
|
|
16
|
+
import { ALLOW_SERVICE_KEY, PASSWORD_CHANGE_KEY, PUBLIC_KEY, SESSION_ONLY_KEY, SUPER_ADMIN_KEY, } from "./principal.js";
|
|
17
17
|
import { SessionService } from "./sessions.js";
|
|
18
18
|
/** CSRF 头:Cookie 认证的非安全请求(及所有公开路由的非安全请求)必须带 `X-Capybara-Csrf: 1`。 */
|
|
19
19
|
export const CSRF_HEADER = "x-capybara-csrf";
|
|
@@ -76,6 +76,8 @@ export async function authorizeSuperAdmin(req, s) {
|
|
|
76
76
|
if (p.kind === "service") {
|
|
77
77
|
throw new ApiError("forbidden", "Service tokens cannot access this endpoint");
|
|
78
78
|
}
|
|
79
|
+
if (p.account.mustChangePassword)
|
|
80
|
+
throw passwordChangeRequired();
|
|
79
81
|
if (!p.account.isSuperAdmin)
|
|
80
82
|
throw new ApiError("forbidden", "Super admin required");
|
|
81
83
|
}
|
|
@@ -94,6 +96,8 @@ export async function authenticateOrgUploader(req, s) {
|
|
|
94
96
|
if (resolved.principal.kind === "service") {
|
|
95
97
|
throw new ApiError("forbidden", "Service tokens cannot access this endpoint");
|
|
96
98
|
}
|
|
99
|
+
if (resolved.principal.account.mustChangePassword)
|
|
100
|
+
throw passwordChangeRequired();
|
|
97
101
|
return resolved.principal;
|
|
98
102
|
}
|
|
99
103
|
/**
|
|
@@ -159,6 +163,9 @@ let AuthGuard = class AuthGuard {
|
|
|
159
163
|
if (flag(SESSION_ONLY_KEY) && !(p.kind === "user" && p.via === "session")) {
|
|
160
164
|
throw new ApiError("auth.session_required", "This endpoint requires a web session");
|
|
161
165
|
}
|
|
166
|
+
if (p.kind === "user" && p.account.mustChangePassword && !flag(PASSWORD_CHANGE_KEY)) {
|
|
167
|
+
throw passwordChangeRequired();
|
|
168
|
+
}
|
|
162
169
|
if (flag(SUPER_ADMIN_KEY) && !(p.kind === "user" && p.account.isSuperAdmin)) {
|
|
163
170
|
throw new ApiError("forbidden", "Super admin required");
|
|
164
171
|
}
|
|
@@ -173,6 +180,8 @@ AuthGuard = __decorate([
|
|
|
173
180
|
__param(3, Inject(ApiTokenService))
|
|
174
181
|
], AuthGuard);
|
|
175
182
|
export { AuthGuard };
|
|
183
|
+
/** An account signed in with a generated initial password reaches nothing until it changes it. */
|
|
184
|
+
const passwordChangeRequired = () => new ApiError("auth.password_change_required", "Set a new password first: this account signed in with a generated initial password");
|
|
176
185
|
function requireActive(account) {
|
|
177
186
|
if (account.status !== "active") {
|
|
178
187
|
throw new ApiError("auth.account_disabled", "Account is disabled");
|
|
@@ -29,3 +29,9 @@ export declare function clearSessionCookies(reply: FastifyReply): void;
|
|
|
29
29
|
* Path cookie and the new one sends both, the more specific Path first.
|
|
30
30
|
*/
|
|
31
31
|
export declare function refreshCookieValues(header: string | undefined): string[];
|
|
32
|
+
/**
|
|
33
|
+
* The startup warning for an http trial that cannot sign in: session cookies are Secure but the
|
|
34
|
+
* configured public URL is plain http, so browsers drop them. Null when cookies are not Secure,
|
|
35
|
+
* or the public URL is https or unset (an unset URL says nothing about how people reach the app).
|
|
36
|
+
*/
|
|
37
|
+
export declare function insecurePublicUrlWarning(cfg: KernelConfig): string | null;
|