@capybara-hq/kernel 0.1.0-rc.12 → 0.1.0-rc.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/agents/agent-lookup.d.ts +5 -0
- package/dist/agents/agent-lookup.js +15 -0
- package/dist/background/background.module.js +2 -2
- package/dist/background/launch-lock.d.ts +1 -1
- package/dist/background/launch-lock.js +1 -1
- package/dist/background/poll.job.d.ts +2 -2
- package/dist/background/poll.job.js +10 -10
- package/dist/background/stop.d.ts +1 -1
- package/dist/background/stop.js +3 -3
- package/dist/background/store.d.ts +5 -5
- package/dist/background/store.js +5 -5
- package/dist/background/tasks.service.d.ts +6 -6
- package/dist/background/tasks.service.js +13 -13
- package/dist/catalog/admin-catalog.controller.d.ts +13 -2
- package/dist/catalog/admin-catalog.controller.js +24 -3
- package/dist/catalog/admin-catalog.schemas.d.ts +10 -0
- package/dist/catalog/admin-catalog.schemas.js +7 -0
- package/dist/catalog/catalog-content.d.ts +9 -1
- package/dist/catalog/catalog-content.js +2 -1
- package/dist/catalog/catalog-files.d.ts +3 -2
- package/dist/catalog/catalog-files.js +8 -5
- package/dist/catalog/component-scope.service.d.ts +14 -1
- package/dist/catalog/component-scope.service.js +12 -2
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-catalog.controller.d.ts +5 -4
- package/dist/catalog/org-catalog.controller.js +5 -4
- package/dist/catalog/org-catalog.schemas.d.ts +18 -2
- package/dist/catalog/org-catalog.schemas.js +16 -2
- package/dist/catalog/org-catalog.service.js +8 -2
- package/dist/catalog/plugin-import.js +1 -1
- package/dist/catalog/plugin-package.js +37 -9
- package/dist/catalog/plugin-upgrade.d.ts +15 -1
- package/dist/catalog/plugin-upgrade.js +18 -5
- package/dist/channels/channels.module.js +2 -2
- package/dist/channels/connections.controller.d.ts +1 -1
- package/dist/channels/connections.controller.js +1 -1
- package/dist/channels/connections.service.d.ts +22 -5
- package/dist/channels/connections.service.js +56 -10
- package/dist/channels/inbound.d.ts +8 -8
- package/dist/channels/inbound.js +31 -31
- package/dist/channels/phrases.d.ts +27 -27
- package/dist/channels/phrases.js +27 -27
- package/dist/channels/webhook.d.ts +21 -1
- package/dist/channels/webhook.js +39 -4
- package/dist/config/docs.js +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +21 -21
- package/dist/conversations/conversations.controller.d.ts +11 -11
- package/dist/conversations/conversations.controller.js +15 -15
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +7 -7
- package/dist/conversations/conversations.schemas.js +1 -1
- package/dist/conversations/conversations.service.d.ts +14 -14
- package/dist/conversations/conversations.service.js +19 -19
- package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
- package/dist/conversations/{environment-status.js → device-status.js} +18 -18
- package/dist/conversations/event-log.d.ts +1 -1
- package/dist/conversations/event-log.js +1 -1
- package/dist/conversations/events.d.ts +1 -1
- package/dist/conversations/events.js +2 -2
- package/dist/ctx/create-ctx.d.ts +26 -3
- package/dist/ctx/create-ctx.js +134 -26
- package/dist/db/kernel-schema.d.ts +37 -25
- package/dist/{environments → devices}/access.d.ts +19 -19
- package/dist/{environments → devices}/access.js +28 -28
- package/dist/devices/conversation-devices.d.ts +75 -0
- package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
- package/dist/devices/devices.controller.d.ts +36 -0
- package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
- package/dist/devices/devices.module.d.ts +5 -13
- package/dist/devices/devices.module.js +16 -29
- package/dist/devices/devices.schemas.d.ts +3 -0
- package/dist/devices/devices.schemas.js +14 -0
- package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
- package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
- package/dist/devices/dto.d.ts +13 -54
- package/dist/devices/dto.js +7 -39
- package/dist/devices/label.d.ts +11 -0
- package/dist/{environments → devices}/label.js +7 -7
- package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
- package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
- package/dist/errors.d.ts +29 -25
- package/dist/errors.js +29 -25
- package/dist/evals/recorded-tools.d.ts +2 -2
- package/dist/evals/recorded-tools.js +6 -6
- package/dist/extensions/admin-ops.js +1 -0
- package/dist/extensions/admin-view.js +2 -0
- package/dist/extensions/effective-config.d.ts +6 -0
- package/dist/extensions/effective-config.js +18 -7
- package/dist/extensions/guide-places.d.ts +66 -0
- package/dist/extensions/guide-places.js +152 -0
- package/dist/extensions/host.d.ts +13 -2
- package/dist/extensions/host.js +27 -6
- package/dist/extensions/instance.d.ts +17 -2
- package/dist/extensions/instance.js +21 -0
- package/dist/extensions/ledger.d.ts +1 -1
- package/dist/extensions/permission-set.d.ts +16 -2
- package/dist/extensions/permission-set.js +17 -3
- package/dist/extensions/permission-view.d.ts +10 -1
- package/dist/extensions/plugin-guides.d.ts +207 -54
- package/dist/extensions/plugin-guides.js +436 -165
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +1 -1
- package/dist/http/api.module.js +16 -6
- package/dist/http/gateway-routes.d.ts +1 -1
- package/dist/http/gateway-routes.js +1 -1
- package/dist/identity/settings.d.ts +32 -0
- package/dist/identity/settings.js +26 -2
- package/dist/infra/config/kernel-config.service.js +4 -4
- package/dist/infra/lock/lock.service.d.ts +8 -0
- package/dist/infra/lock/lock.service.js +27 -0
- package/dist/infra/throttler/named-throttlers.d.ts +4 -1
- package/dist/infra/throttler/named-throttlers.js +16 -1
- package/dist/infra/throttler/throttler.guard.js +1 -1
- package/dist/kernel.module.js +3 -3
- package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
- package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
- package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
- package/dist/{devices → local-devices}/device-auth.js +51 -53
- package/dist/local-devices/device-auth.module.d.ts +7 -0
- package/dist/{devices → local-devices}/device-auth.module.js +5 -5
- package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
- package/dist/{devices → local-devices}/device-routes.js +2 -2
- package/dist/local-devices/dto.d.ts +66 -0
- package/dist/local-devices/dto.js +44 -0
- package/dist/{devices → local-devices}/keys.d.ts +11 -11
- package/dist/{devices → local-devices}/keys.js +11 -11
- package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
- package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
- package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
- package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
- package/dist/local-devices/local-devices.module.d.ts +16 -0
- package/dist/local-devices/local-devices.module.js +44 -0
- package/dist/{devices → local-devices}/machines.d.ts +26 -26
- package/dist/{devices → local-devices}/machines.js +71 -71
- package/dist/{devices → local-devices}/relay.d.ts +15 -15
- package/dist/{devices → local-devices}/relay.js +55 -55
- package/dist/{devices → local-devices}/targets.d.ts +8 -8
- package/dist/{devices → local-devices}/targets.js +14 -14
- package/dist/orgs/offboarding.d.ts +6 -6
- package/dist/orgs/offboarding.js +12 -12
- package/dist/orgs/settings.service.d.ts +28 -0
- package/dist/orgs/settings.service.js +20 -1
- package/dist/overrides.d.ts +3 -1
- package/dist/overrides.js +2 -0
- package/dist/platform/exclusions.js +48 -8
- package/dist/platform/operation.js +10 -2
- package/dist/platform/ops/admin.ops.js +8 -2
- package/dist/platform/ops/connectors.ops.js +2 -0
- package/dist/platform/ops/conversations.ops.d.ts +3 -3
- package/dist/platform/ops/conversations.ops.js +9 -9
- package/dist/platform/ops/devices.ops.d.ts +26 -0
- package/dist/platform/ops/devices.ops.js +311 -0
- package/dist/platform/ops/org-settings.ops.js +2 -2
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/setup.ops.d.ts +24 -0
- package/dist/platform/ops/setup.ops.js +212 -0
- package/dist/platform/ops/ui.ops.d.ts +8 -0
- package/dist/platform/ops/ui.ops.js +41 -0
- package/dist/platform/platform-ops.module.d.ts +4 -2
- package/dist/platform/platform-ops.module.js +13 -5
- package/dist/platform/route-schemas.js +11 -3
- package/dist/roles/gateway-role.d.ts +3 -3
- package/dist/roles/gateway-role.js +4 -4
- package/dist/roles/gateway.module.d.ts +1 -1
- package/dist/roles/gateway.module.js +5 -5
- package/dist/roles/worker.module.js +1 -1
- package/dist/runtime/context/build.d.ts +1 -1
- package/dist/runtime/context/build.js +6 -6
- package/dist/runtime/context/compaction.js +1 -1
- package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
- package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
- package/dist/runtime/maintenance.d.ts +1 -1
- package/dist/sandbox/jobs.d.ts +13 -13
- package/dist/sandbox/jobs.js +20 -20
- package/dist/sandbox/leases.d.ts +9 -9
- package/dist/sandbox/leases.js +14 -14
- package/dist/sandbox/providers.d.ts +8 -8
- package/dist/sandbox/providers.js +8 -8
- package/dist/sandbox/sandbox.module.d.ts +1 -1
- package/dist/sandbox/sandbox.module.js +1 -1
- package/dist/sandbox/sandbox.service.d.ts +76 -76
- package/dist/sandbox/sandbox.service.js +230 -230
- package/dist/setup/kernel-checks.d.ts +91 -0
- package/dist/setup/kernel-checks.js +295 -0
- package/dist/setup/oauth-token-probe.d.ts +47 -0
- package/dist/setup/oauth-token-probe.js +108 -0
- package/dist/setup/redact-check.d.ts +18 -0
- package/dist/setup/redact-check.js +46 -0
- package/dist/setup/setup-check-registry.d.ts +86 -0
- package/dist/setup/setup-check-registry.js +75 -0
- package/dist/setup/setup-checks.controller.d.ts +28 -0
- package/dist/setup/setup-checks.controller.js +78 -0
- package/dist/setup/setup-checks.schemas.d.ts +38 -0
- package/dist/setup/setup-checks.schemas.js +43 -0
- package/dist/setup/setup-checks.service.d.ts +144 -0
- package/dist/setup/setup-checks.service.js +683 -0
- package/dist/setup/setup-guides.controller.d.ts +18 -0
- package/dist/setup/setup-guides.controller.js +48 -0
- package/dist/setup/setup-guides.schemas.d.ts +10 -0
- package/dist/setup/setup-guides.schemas.js +6 -0
- package/dist/setup/setup-guides.service.d.ts +126 -0
- package/dist/setup/setup-guides.service.js +315 -0
- package/dist/setup/setup.module.d.ts +8 -0
- package/dist/setup/setup.module.js +31 -0
- package/dist/tools/builtins/builtin-tools.d.ts +2 -2
- package/dist/tools/builtins/builtin-tools.js +5 -5
- package/dist/tools/builtins/platform.js +1 -1
- package/dist/tools/builtins/sandbox/bash.js +6 -6
- package/dist/tools/builtins/sandbox/common.d.ts +25 -25
- package/dist/tools/builtins/sandbox/common.js +51 -51
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
- package/dist/tools/builtins/sandbox/task-output.js +10 -10
- package/dist/tools/builtins/sandbox/task-stop.js +2 -2
- package/dist/tools/builtins/sandbox/write.js +2 -2
- package/dist/tools/builtins/skill-load.d.ts +1 -1
- package/dist/tools/builtins/skill-load.js +2 -2
- package/dist/tools/connectors.controller.d.ts +28 -11
- package/dist/tools/connectors.controller.js +49 -14
- package/dist/tools/connectors.schemas.d.ts +4 -0
- package/dist/tools/connectors.schemas.js +4 -0
- package/dist/tools/connectors.service.d.ts +30 -2
- package/dist/tools/connectors.service.js +98 -3
- package/dist/tools/credentials.d.ts +20 -0
- package/dist/tools/credentials.js +90 -1
- package/dist/tools/oauth/tokens.d.ts +20 -0
- package/dist/tools/oauth/tokens.js +49 -24
- package/dist/tools/pipeline.js +4 -3
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/tools.module.js +3 -3
- package/dist/ui/admin-ui.controller.d.ts +56 -0
- package/dist/ui/admin-ui.controller.js +192 -0
- package/dist/ui/arrangement.d.ts +74 -0
- package/dist/ui/arrangement.js +98 -0
- package/dist/ui/embed-token.d.ts +2 -2
- package/dist/ui/embed-token.js +30 -5
- package/dist/ui/registry.d.ts +29 -14
- package/dist/ui/registry.js +31 -10
- package/dist/ui/slots.controller.d.ts +11 -0
- package/dist/ui/slots.controller.js +25 -0
- package/dist/ui/ui-stream.d.ts +20 -3
- package/dist/ui/ui-stream.js +25 -7
- package/dist/ui/ui.schemas.d.ts +66 -0
- package/dist/ui/ui.schemas.js +65 -0
- package/dist/ui/views.controller.d.ts +35 -49
- package/dist/ui/views.controller.js +48 -70
- package/dist/ui/views.d.ts +84 -18
- package/dist/ui/views.js +201 -38
- package/package.json +3 -3
- package/src/migrations/0105_devices_rename.sql +136 -0
- package/src/migrations/0106_setup_guides_v2.sql +10 -0
- package/dist/devices/device-auth.module.d.ts +0 -7
- package/dist/environments/conversation-environments.d.ts +0 -75
- package/dist/environments/dto.d.ts +0 -25
- package/dist/environments/dto.js +0 -12
- package/dist/environments/environments.controller.d.ts +0 -36
- package/dist/environments/environments.module.d.ts +0 -8
- package/dist/environments/environments.module.js +0 -31
- package/dist/environments/environments.schemas.d.ts +0 -3
- package/dist/environments/environments.schemas.js +0 -14
- package/dist/environments/label.d.ts +0 -11
- package/dist/platform/ops/environments.ops.d.ts +0 -26
- package/dist/platform/ops/environments.ops.js +0 -311
|
@@ -87,7 +87,7 @@ export declare class PreviewerRegistry {
|
|
|
87
87
|
locale: "zh" | "en";
|
|
88
88
|
}): Promise<UiView>;
|
|
89
89
|
/**
|
|
90
|
-
* Whether an embed token for a `file
|
|
90
|
+
* Whether an embed token for a `file.preview` contribution may be issued for this file: the
|
|
91
91
|
* viewer reads the conversation, the file is in it, and an enabled previewer of that extension
|
|
92
92
|
* with `embed: contribution` takes it. Conversation / file not found throws 404.
|
|
93
93
|
*/
|
package/dist/files/previewers.js
CHANGED
|
@@ -299,7 +299,7 @@ let PreviewerRegistry = class PreviewerRegistry {
|
|
|
299
299
|
return view;
|
|
300
300
|
}
|
|
301
301
|
/**
|
|
302
|
-
* Whether an embed token for a `file
|
|
302
|
+
* Whether an embed token for a `file.preview` contribution may be issued for this file: the
|
|
303
303
|
* viewer reads the conversation, the file is in it, and an enabled previewer of that extension
|
|
304
304
|
* with `embed: contribution` takes it. Conversation / file not found throws 404.
|
|
305
305
|
*/
|
package/dist/http/api.module.js
CHANGED
|
@@ -30,10 +30,8 @@ import { ChannelConnectionsController } from "../channels/connections.controller
|
|
|
30
30
|
import { AttachmentsController } from "../conversations/attachments.controller.js";
|
|
31
31
|
import { ConversationsController } from "../conversations/conversations.controller.js";
|
|
32
32
|
import { ConversationsModule } from "../conversations/conversations.module.js";
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import { EnvironmentsController } from "../environments/environments.controller.js";
|
|
36
|
-
import { EnvironmentsModule } from "../environments/environments.module.js";
|
|
33
|
+
import { DevicesController } from "../devices/devices.controller.js";
|
|
34
|
+
import { DevicesModule } from "../devices/devices.module.js";
|
|
37
35
|
import { EvalsModule } from "../evals/evals.module.js";
|
|
38
36
|
import { EvalRunsController } from "../evals/runs.controller.js";
|
|
39
37
|
import { EvalSetsController } from "../evals/sets.controller.js";
|
|
@@ -50,6 +48,8 @@ import { MeController } from "../identity/me.controller.js";
|
|
|
50
48
|
import { BindController, MeIdentitiesController, SsoController, } from "../identity/sso.controller.js";
|
|
51
49
|
import { InboxModule } from "../inbox/inbox.module.js";
|
|
52
50
|
import { PlatformInboxController } from "../inbox/platform-inbox.controller.js";
|
|
51
|
+
import { DeviceAuthController } from "../local-devices/device-auth.controller.js";
|
|
52
|
+
import { DeviceAuthModule } from "../local-devices/device-auth.module.js";
|
|
53
53
|
import { ModelEnablementController } from "../models/enablement.controller.js";
|
|
54
54
|
import { ModelsModule } from "../models/models.module.js";
|
|
55
55
|
import { ModelPurposesController } from "../models/purposes.controller.js";
|
|
@@ -60,6 +60,9 @@ import { OrgsModule } from "../orgs/orgs.module.js";
|
|
|
60
60
|
import { OrgSettingsController } from "../orgs/settings.controller.js";
|
|
61
61
|
import { RuntimeModule } from "../runtime/runtime.module.js";
|
|
62
62
|
import { ConversationStreamController } from "../runtime/stream.controller.js";
|
|
63
|
+
import { SetupModule } from "../setup/setup.module.js";
|
|
64
|
+
import { SetupChecksController } from "../setup/setup-checks.controller.js";
|
|
65
|
+
import { SetupGuidesController } from "../setup/setup-guides.controller.js";
|
|
63
66
|
import { AgentSkillsController, InboxController, SkillChangesController, } from "../skills/changes.controller.js";
|
|
64
67
|
import { InvocableSkillsController } from "../skills/invocable.controller.js";
|
|
65
68
|
import { SkillsController } from "../skills/skills.controller.js";
|
|
@@ -75,6 +78,8 @@ import { ExtensionToolsController } from "../tools/extension-tools.controller.js
|
|
|
75
78
|
import { OAuthCallbackController, OAuthConnectController, } from "../tools/oauth/oauth.controller.js";
|
|
76
79
|
import { QuestionsController } from "../tools/questions.controller.js";
|
|
77
80
|
import { ToolsModule } from "../tools/tools.module.js";
|
|
81
|
+
import { AdminUiController } from "../ui/admin-ui.controller.js";
|
|
82
|
+
import { SlotsController } from "../ui/slots.controller.js";
|
|
78
83
|
import { UiModule } from "../ui/ui.module.js";
|
|
79
84
|
import { UiController } from "../ui/views.controller.js";
|
|
80
85
|
/** Every controller of the kernel API. */
|
|
@@ -104,7 +109,7 @@ const CONTROLLERS = [
|
|
|
104
109
|
ReadinessController,
|
|
105
110
|
ConversationsController,
|
|
106
111
|
BackgroundController,
|
|
107
|
-
|
|
112
|
+
DevicesController,
|
|
108
113
|
AttachmentsController,
|
|
109
114
|
SkillsController,
|
|
110
115
|
SkillChangesController,
|
|
@@ -127,6 +132,8 @@ const CONTROLLERS = [
|
|
|
127
132
|
ChannelConnectionsController,
|
|
128
133
|
DirectorySyncController,
|
|
129
134
|
UiController,
|
|
135
|
+
AdminUiController,
|
|
136
|
+
SlotsController,
|
|
130
137
|
FilePreviewersController,
|
|
131
138
|
ExtensionPointDefaultsController,
|
|
132
139
|
TrajectoryController,
|
|
@@ -134,6 +141,8 @@ const CONTROLLERS = [
|
|
|
134
141
|
EvalRunsController,
|
|
135
142
|
ModelPurposesController,
|
|
136
143
|
OrgCatalogController,
|
|
144
|
+
SetupChecksController,
|
|
145
|
+
SetupGuidesController,
|
|
137
146
|
OrgPluginUploadsController,
|
|
138
147
|
OrgOwnedPluginsController,
|
|
139
148
|
OrgComponentsController,
|
|
@@ -166,7 +175,7 @@ ApiModule = __decorate([
|
|
|
166
175
|
AgentsModule,
|
|
167
176
|
ConversationsModule,
|
|
168
177
|
BackgroundModule,
|
|
169
|
-
|
|
178
|
+
DevicesModule,
|
|
170
179
|
DeviceAuthModule,
|
|
171
180
|
RuntimeModule,
|
|
172
181
|
ChannelsModule,
|
|
@@ -175,6 +184,7 @@ ApiModule = __decorate([
|
|
|
175
184
|
UiModule,
|
|
176
185
|
InboxModule,
|
|
177
186
|
ThemesModule,
|
|
187
|
+
SetupModule,
|
|
178
188
|
],
|
|
179
189
|
controllers: CONTROLLERS,
|
|
180
190
|
providers: [{ provide: APP_GUARD, useClass: AuthGuard }],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { FastifyInstance } from "fastify";
|
|
3
3
|
import type { ChannelWebhooks } from "../channels/webhook.js";
|
|
4
|
-
import { type DeviceRoutesOptions } from "../devices/device-routes.js";
|
|
4
|
+
import { type DeviceRoutesOptions } from "../local-devices/device-routes.js";
|
|
5
5
|
/** What the gateway role serves over HTTP besides health and plugin routes. */
|
|
6
6
|
export interface GatewayRoutes {
|
|
7
7
|
webhooks: Pick<ChannelWebhooks, "handle">;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { registerChannelWebhookRoute } from "../channels/webhook.controller.js";
|
|
2
|
-
import { registerDeviceConnectRoute } from "../devices/device-routes.js";
|
|
2
|
+
import { registerDeviceConnectRoute, } from "../local-devices/device-routes.js";
|
|
3
3
|
/**
|
|
4
4
|
* Registers the gateway role's HTTP routes (`serveGateway = roles.includes("gateway")`): the
|
|
5
5
|
* channel webhook and the device connection WebSocket. These are raw Fastify routes, not a Nest
|
|
@@ -3,6 +3,7 @@ import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
|
3
3
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
4
4
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
5
5
|
import type { KernelLogger } from "../log.js";
|
|
6
|
+
import { type UiArrangement } from "../ui/arrangement.js";
|
|
6
7
|
import { SuperAdminLock } from "./super-admin.js";
|
|
7
8
|
/** 沙箱 cpu(核)与内存(MB)覆盖的范围(C19)。 */
|
|
8
9
|
export declare const SANDBOX_CPU_RANGE: {
|
|
@@ -72,6 +73,19 @@ export declare const DEPLOYMENT_SETTINGS: z.ZodObject<{
|
|
|
72
73
|
uiTheme: z.ZodDefault<z.ZodObject<{
|
|
73
74
|
id: z.ZodNullable<z.ZodString>;
|
|
74
75
|
}, z.core.$strip>>;
|
|
76
|
+
uiArrangement: z.ZodDefault<z.ZodRecord<z.ZodEnum<{
|
|
77
|
+
"agent.detail.section": "agent.detail.section";
|
|
78
|
+
"conversation.panel": "conversation.panel";
|
|
79
|
+
"conversation.properties.section": "conversation.properties.section";
|
|
80
|
+
"conversation.tool-result.card": "conversation.tool-result.card";
|
|
81
|
+
"file.preview": "file.preview";
|
|
82
|
+
"org.page": "org.page";
|
|
83
|
+
"org.settings.section": "org.settings.section";
|
|
84
|
+
"platform.page": "platform.page";
|
|
85
|
+
}> & z.core.$partial, z.ZodObject<{
|
|
86
|
+
hidden: z.ZodArray<z.ZodString>;
|
|
87
|
+
order: z.ZodArray<z.ZodString>;
|
|
88
|
+
}, z.core.$strict>>>;
|
|
75
89
|
}, z.core.$strip>;
|
|
76
90
|
export type DeploymentSettings = z.infer<typeof DEPLOYMENT_SETTINGS>;
|
|
77
91
|
/**
|
|
@@ -111,6 +125,19 @@ export declare const DEPLOYMENT_SETTINGS_PATCH: z.ZodObject<{
|
|
|
111
125
|
uiTheme: z.ZodOptional<z.ZodObject<{
|
|
112
126
|
id: z.ZodNullable<z.ZodString>;
|
|
113
127
|
}, z.core.$strict>>;
|
|
128
|
+
uiArrangement: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
129
|
+
"agent.detail.section": "agent.detail.section";
|
|
130
|
+
"conversation.panel": "conversation.panel";
|
|
131
|
+
"conversation.properties.section": "conversation.properties.section";
|
|
132
|
+
"conversation.tool-result.card": "conversation.tool-result.card";
|
|
133
|
+
"file.preview": "file.preview";
|
|
134
|
+
"org.page": "org.page";
|
|
135
|
+
"org.settings.section": "org.settings.section";
|
|
136
|
+
"platform.page": "platform.page";
|
|
137
|
+
}> & z.core.$partial, z.ZodNullable<z.ZodObject<{
|
|
138
|
+
hidden: z.ZodArray<z.ZodString>;
|
|
139
|
+
order: z.ZodArray<z.ZodString>;
|
|
140
|
+
}, z.core.$strict>>>>;
|
|
114
141
|
}, z.core.$strict>;
|
|
115
142
|
export type DeploymentSettingsPatch = z.infer<typeof DEPLOYMENT_SETTINGS_PATCH>;
|
|
116
143
|
/**
|
|
@@ -145,6 +172,11 @@ export declare function readOrgMarketplaceBrowse(db: KernelSchemaDb): Promise<bo
|
|
|
145
172
|
export declare function readUiTheme(db: KernelSchemaDb, opts?: {
|
|
146
173
|
lock?: boolean;
|
|
147
174
|
}): Promise<UiTheme>;
|
|
175
|
+
/**
|
|
176
|
+
* The platform default arrangement of UI slots, read live (the lists apply it). An invalid
|
|
177
|
+
* stored value reads as `{}` (the same fallback {@link SettingsService.get} uses).
|
|
178
|
+
*/
|
|
179
|
+
export declare function readUiArrangement(db: KernelSchemaDb): Promise<UiArrangement>;
|
|
148
180
|
/** Deployment settings: one row per key, defaults for missing keys. */
|
|
149
181
|
export declare class SettingsService {
|
|
150
182
|
private readonly db;
|
|
@@ -15,6 +15,7 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
|
15
15
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
16
16
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
17
17
|
import { assertPlatformDefaultEligible, lockThemeShared } from "../themes/theme-state.js";
|
|
18
|
+
import { mergeArrangement, UiArrangementPatchSchema, UiArrangementSchema, } from "../ui/arrangement.js";
|
|
18
19
|
import { audit } from "./audit.js";
|
|
19
20
|
import { SuperAdminLock } from "./super-admin.js";
|
|
20
21
|
/** 币种代码:ISO 4217 的三位大写字母(如 USD、CNY)。 */
|
|
@@ -100,6 +101,8 @@ export const DEPLOYMENT_SETTINGS = z.object({
|
|
|
100
101
|
orgMarketplaceBrowse: z.boolean().default(true),
|
|
101
102
|
/** The platform default theme (themes spec §7); `{ id: null }`: the built-in theme. */
|
|
102
103
|
uiTheme: UiThemeSetting.default({ id: null }),
|
|
104
|
+
/** The platform default arrangement of UI slots (UI slots spec §5); orgs override per slot. */
|
|
105
|
+
uiArrangement: UiArrangementSchema.default({}),
|
|
103
106
|
});
|
|
104
107
|
const DEFAULTS = DEPLOYMENT_SETTINGS.parse({});
|
|
105
108
|
/**
|
|
@@ -131,6 +134,8 @@ export const DEPLOYMENT_SETTINGS_PATCH = z
|
|
|
131
134
|
* disabled (else 400 `theme.not_available`), or `{ id: null }` for the built-in theme.
|
|
132
135
|
*/
|
|
133
136
|
uiTheme: UiThemeSetting.strict().optional(),
|
|
137
|
+
/** Per slot, the entry to hide / order contributions with; null removes a slot's entry. */
|
|
138
|
+
uiArrangement: UiArrangementPatchSchema.optional(),
|
|
134
139
|
})
|
|
135
140
|
.strict();
|
|
136
141
|
/**
|
|
@@ -240,6 +245,19 @@ async function lockUiThemeRow(db) {
|
|
|
240
245
|
.forUpdate()
|
|
241
246
|
.execute();
|
|
242
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* The platform default arrangement of UI slots, read live (the lists apply it). An invalid
|
|
250
|
+
* stored value reads as `{}` (the same fallback {@link SettingsService.get} uses).
|
|
251
|
+
*/
|
|
252
|
+
export async function readUiArrangement(db) {
|
|
253
|
+
const row = await db
|
|
254
|
+
.selectFrom("deployment_settings")
|
|
255
|
+
.select("value")
|
|
256
|
+
.where("key", "=", "uiArrangement")
|
|
257
|
+
.executeTakeFirst();
|
|
258
|
+
const parsed = UiArrangementSchema.safeParse(row?.value);
|
|
259
|
+
return parsed.success ? parsed.data : {};
|
|
260
|
+
}
|
|
243
261
|
/** 按组织合并覆盖:值为 null 删除该组织,其余整项替换;未列出的组织不变。 */
|
|
244
262
|
function mergeByOrg(current, patch) {
|
|
245
263
|
const merged = { ...current };
|
|
@@ -331,9 +349,15 @@ let SettingsService = class SettingsService {
|
|
|
331
349
|
}
|
|
332
350
|
next.uiTheme = { id: patch.uiTheme.id };
|
|
333
351
|
}
|
|
334
|
-
const { runConcurrencyOverrides: runPatch, sandboxLimitOverrides: sandboxPatch, subagentLimitOverrides: subagentPatch, } = patch;
|
|
335
|
-
if (runPatch !== undefined ||
|
|
352
|
+
const { runConcurrencyOverrides: runPatch, sandboxLimitOverrides: sandboxPatch, subagentLimitOverrides: subagentPatch, uiArrangement: arrangementPatch, } = patch;
|
|
353
|
+
if (runPatch !== undefined ||
|
|
354
|
+
sandboxPatch !== undefined ||
|
|
355
|
+
subagentPatch !== undefined ||
|
|
356
|
+
arrangementPatch !== undefined) {
|
|
336
357
|
const current = await this.get();
|
|
358
|
+
if (arrangementPatch !== undefined) {
|
|
359
|
+
next.uiArrangement = mergeArrangement(current.uiArrangement, arrangementPatch);
|
|
360
|
+
}
|
|
337
361
|
if (runPatch !== undefined) {
|
|
338
362
|
next.runConcurrencyOverrides = mergeByOrg(current.runConcurrencyOverrides, runPatch);
|
|
339
363
|
}
|
|
@@ -33,10 +33,10 @@ const HOT_APPLIERS = {
|
|
|
33
33
|
"models.embedTimeoutMs": () => { },
|
|
34
34
|
// SandboxService reads the shared-lease cap at every acquisition.
|
|
35
35
|
"sandbox.maxConcurrentCommands": () => { },
|
|
36
|
-
// The
|
|
37
|
-
"
|
|
38
|
-
// The device relay reads the reconnect grace at every disconnect and token response.
|
|
39
|
-
"
|
|
36
|
+
// The devices service reads the personal limit at every create.
|
|
37
|
+
"devices.maxPersonal": () => { },
|
|
38
|
+
// The local device relay reads the reconnect grace at every disconnect and token response.
|
|
39
|
+
"devices.local.reconnectGraceSeconds": () => { },
|
|
40
40
|
// Sub-agent limits are read at every dispatch, child step and tool resolution.
|
|
41
41
|
"subagents.maxDepth": () => { },
|
|
42
42
|
"subagents.maxConcurrentPerConversation": () => { },
|
|
@@ -74,6 +74,14 @@ export declare class LockService {
|
|
|
74
74
|
holderOf(key: string): Promise<string | null>;
|
|
75
75
|
/** Deletes `key` when `holder` still owns it. */
|
|
76
76
|
releaseIf(key: string, holder: string): Promise<boolean>;
|
|
77
|
+
/**
|
|
78
|
+
* Takes one of `limit` slots of the counting semaphore `key` for `holder` (a unique token), for at
|
|
79
|
+
* most `ttlMs` (a crashed holder's slot frees itself then; no renewal). False when every slot is
|
|
80
|
+
* taken. Release with {@link releaseSlot}.
|
|
81
|
+
*/
|
|
82
|
+
takeSlot(key: string, holder: string, limit: number, ttlMs: number): Promise<boolean>;
|
|
83
|
+
/** Gives back `holder`'s slot of the semaphore `key` (nothing when it already expired). */
|
|
84
|
+
releaseSlot(key: string, holder: string): Promise<void>;
|
|
77
85
|
/**
|
|
78
86
|
* Takes `key` (no `lock:` prefix) with the caller's `holder` value for `ttlMs`, unless it is
|
|
79
87
|
* held, and renews it every TTL/3 like {@link acquire} (a run longer than the TTL keeps it, a
|
|
@@ -20,6 +20,20 @@ import { ACQUIRE_EXCLUSIVE, ACQUIRE_SHARED, COUNT_SHARED_LEASES, DOWNGRADE_SHARE
|
|
|
20
20
|
const RELEASE_IF = `if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end`;
|
|
21
21
|
/** Extends the key only while it holds our token. */
|
|
22
22
|
const RENEW_IF = `if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('pexpire', KEYS[1], tonumber(ARGV[2])) else return 0 end`;
|
|
23
|
+
/**
|
|
24
|
+
* Takes a slot of a counting semaphore: a sorted set of holder tokens scored by expiry time. Expired
|
|
25
|
+
* holders (a crashed replica's) drop out first, so a slot is never lost for longer than its TTL;
|
|
26
|
+
* then the token is added when fewer than ARGV[2] slots are taken. The set itself expires with
|
|
27
|
+
* its last slot. KEYS[1] the set; ARGV: token, limit, ttl ms. Returns 1 when taken.
|
|
28
|
+
*/
|
|
29
|
+
const TAKE_SLOT = `local now = redis.call('time')
|
|
30
|
+
local ms = tonumber(now[1]) * 1000 + math.floor(tonumber(now[2]) / 1000)
|
|
31
|
+
redis.call('zremrangebyscore', KEYS[1], '-inf', ms)
|
|
32
|
+
if redis.call('zcard', KEYS[1]) >= tonumber(ARGV[2]) then return 0 end
|
|
33
|
+
redis.call('zadd', KEYS[1], ms + tonumber(ARGV[3]), ARGV[1])
|
|
34
|
+
local last = redis.call('zrange', KEYS[1], -1, -1, 'withscores')
|
|
35
|
+
redis.call('pexpireat', KEYS[1], tonumber(last[2]))
|
|
36
|
+
return 1`;
|
|
23
37
|
/** Resolves after `ms`; rejects with the abort reason when `signal` aborts first. */
|
|
24
38
|
function sleep(ms, signal) {
|
|
25
39
|
return new Promise((resolve, reject) => {
|
|
@@ -117,6 +131,19 @@ let LockService = class LockService {
|
|
|
117
131
|
async releaseIf(key, holder) {
|
|
118
132
|
return (await this.redis.eval(RELEASE_IF, 1, key, holder)) === 1;
|
|
119
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Takes one of `limit` slots of the counting semaphore `key` for `holder` (a unique token), for at
|
|
136
|
+
* most `ttlMs` (a crashed holder's slot frees itself then; no renewal). False when every slot is
|
|
137
|
+
* taken. Release with {@link releaseSlot}.
|
|
138
|
+
*/
|
|
139
|
+
async takeSlot(key, holder, limit, ttlMs) {
|
|
140
|
+
assertNoTransaction("takeSlot");
|
|
141
|
+
return ((await this.redis.eval(TAKE_SLOT, 1, key, holder, String(limit), String(Math.ceil(ttlMs)))) === 1);
|
|
142
|
+
}
|
|
143
|
+
/** Gives back `holder`'s slot of the semaphore `key` (nothing when it already expired). */
|
|
144
|
+
async releaseSlot(key, holder) {
|
|
145
|
+
await this.redis.zrem(key, holder);
|
|
146
|
+
}
|
|
120
147
|
/**
|
|
121
148
|
* Takes `key` (no `lock:` prefix) with the caller's `holder` value for `ttlMs`, unless it is
|
|
122
149
|
* held, and renews it every TTL/3 like {@link acquire} (a run longer than the TTL keeps it, a
|
|
@@ -8,6 +8,8 @@ export interface NamedThrottler {
|
|
|
8
8
|
ttl: number;
|
|
9
9
|
/** The 429 message (today's text of the route that used the limiter). */
|
|
10
10
|
message: string;
|
|
11
|
+
/** The 429 error code; default `auth.rate_limited` (the credential routes'). */
|
|
12
|
+
code?: "auth.rate_limited" | "rate_limited";
|
|
11
13
|
/** The credential group: throttlers of one group are reserved together (one Redis hash tag). */
|
|
12
14
|
group: string;
|
|
13
15
|
/** What a successful attempt does to this counter: delete it, or give one attempt back. */
|
|
@@ -29,7 +31,8 @@ export interface NamedThrottler {
|
|
|
29
31
|
*
|
|
30
32
|
* `POST /api/v1/device/authorize` and `POST /api/v1/device/token` opt in to `device-authorize-ip`
|
|
31
33
|
* and `device-token-ip` with `@Throttled` (every request counts; neither checks a guessable
|
|
32
|
-
* credential: the device code is 32 random bytes).
|
|
34
|
+
* credential: the device code is 32 random bytes). `POST …/guides/:guideId/checks/:checkId/run`
|
|
35
|
+
* opts in to `setup-check` (setup guides v2 §10.3: each run may call a third party).
|
|
33
36
|
*/
|
|
34
37
|
export declare const NAMED_THROTTLERS: readonly NamedThrottler[];
|
|
35
38
|
/** The storage key of a named throttler's counter for a tracker (shared by the guard and success paths). */
|
|
@@ -32,7 +32,8 @@ const LOGIN_MSG = "Too many failed login attempts; try again later";
|
|
|
32
32
|
*
|
|
33
33
|
* `POST /api/v1/device/authorize` and `POST /api/v1/device/token` opt in to `device-authorize-ip`
|
|
34
34
|
* and `device-token-ip` with `@Throttled` (every request counts; neither checks a guessable
|
|
35
|
-
* credential: the device code is 32 random bytes).
|
|
35
|
+
* credential: the device code is 32 random bytes). `POST …/guides/:guideId/checks/:checkId/run`
|
|
36
|
+
* opts in to `setup-check` (setup guides v2 §10.3: each run may call a third party).
|
|
36
37
|
*/
|
|
37
38
|
export const NAMED_THROTTLERS = [
|
|
38
39
|
// (login, IP): 10; an attacker filling one login from one IP leaves the owner's other IPs alone (R25)
|
|
@@ -152,6 +153,20 @@ export const NAMED_THROTTLERS = [
|
|
|
152
153
|
message: "Too many device code attempts; try again later",
|
|
153
154
|
getTracker: (req) => sha256(principalAccountId(req)),
|
|
154
155
|
},
|
|
156
|
+
// setup check runs per signed-in person (setup guides v2 §10.5): 30 a minute, every request
|
|
157
|
+
// counts (@Throttled); a cached answer costs no third-party call but still counts, as the page
|
|
158
|
+
// asks at most once per row and stale result. The edge of the route (with `retry-after`): the
|
|
159
|
+
// budget shared with the Platform tool's setup.check is SetupChecksService's own counter
|
|
160
|
+
{
|
|
161
|
+
name: "setup-check",
|
|
162
|
+
group: "setup-check",
|
|
163
|
+
onSuccess: "clear",
|
|
164
|
+
limit: 30,
|
|
165
|
+
ttl: 60_000,
|
|
166
|
+
message: "Too many setup check runs; try again in a minute",
|
|
167
|
+
code: "rate_limited",
|
|
168
|
+
getTracker: (req) => sha256(principalAccountId(req)),
|
|
169
|
+
},
|
|
155
170
|
];
|
|
156
171
|
/** The storage key of a named throttler's counter for a tracker (shared by the guard and success paths). */
|
|
157
172
|
export const throttlerKey = (name, tracker) => sha256(`${name}:${tracker}`);
|
|
@@ -56,7 +56,7 @@ let KernelThrottlerGuard = class KernelThrottlerGuard extends ThrottlerGuard {
|
|
|
56
56
|
const known = NAMED_THROTTLERS.find((t) => t.name === name);
|
|
57
57
|
if (!known)
|
|
58
58
|
throw new Error(`unknown throttler "${name}"`);
|
|
59
|
-
throw new ApiError("auth.rate_limited", known.message);
|
|
59
|
+
throw new ApiError(known.code ?? "auth.rate_limited", known.message);
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
KernelThrottlerGuard = __decorate([
|
package/dist/kernel.module.js
CHANGED
|
@@ -10,7 +10,6 @@ import { APP_INTERCEPTOR } from "@nestjs/core";
|
|
|
10
10
|
import { CatalogModule } from "./catalog/catalog.module.js";
|
|
11
11
|
import { ChannelsModule } from "./channels/channels.module.js";
|
|
12
12
|
import { TitlesModule } from "./conversations/titles.js";
|
|
13
|
-
import { DevicesModule } from "./devices/devices.module.js";
|
|
14
13
|
import { ExtensionsModule } from "./extensions/extensions.module.js";
|
|
15
14
|
import { ApiModule } from "./http/api.module.js";
|
|
16
15
|
import { ErrorFilterModule } from "./http/error-filter.module.js";
|
|
@@ -32,6 +31,7 @@ import { KERNEL_POOL, REDIS } from "./infra/tokens.js";
|
|
|
32
31
|
import { ValidationModule } from "./infra/validation/validation.module.js";
|
|
33
32
|
import { KernelLifecycle } from "./lifecycle/kernel-lifecycle.js";
|
|
34
33
|
import { KERNEL_APP_OPTIONS } from "./lifecycle/tokens.js";
|
|
34
|
+
import { LocalDevicesModule } from "./local-devices/local-devices.module.js";
|
|
35
35
|
import { createConfiguredLogger } from "./log-config.js";
|
|
36
36
|
import { KERNEL_OVERRIDE_TOKENS } from "./overrides.js";
|
|
37
37
|
import { PlatformModule } from "./platform/platform.module.js";
|
|
@@ -111,8 +111,8 @@ let KernelModule = KernelModule_1 = class KernelModule {
|
|
|
111
111
|
TitlesModule,
|
|
112
112
|
UsageReportModule,
|
|
113
113
|
ChannelsModule,
|
|
114
|
-
// the @
|
|
115
|
-
|
|
114
|
+
// the @local sandbox provider, registered on every role (any replica may relay to a machine)
|
|
115
|
+
LocalDevicesModule,
|
|
116
116
|
// the Platform tool's operation registry and actor facts
|
|
117
117
|
PlatformModule,
|
|
118
118
|
// its operations (skills, agents, ...), registered at start on every role
|
|
@@ -11,15 +11,15 @@ import { type DeviceAuthorizeBody, type DeviceConfirmBody, type DeviceTokenBody,
|
|
|
11
11
|
* they need `X-Capybara-Csrf: 1`, which `capybara-device` sends:
|
|
12
12
|
* - `POST /authorize { name, os, arch, programVersion }` → `{ deviceCode, userCode,
|
|
13
13
|
* verificationUri, verificationUriComplete, interval, expiresIn }` (`device-authorize-ip`);
|
|
14
|
-
* - `POST /token { deviceCode }` → `{ credential, orgId,
|
|
15
|
-
* reconnectGraceSeconds, maxFrameBytes }` once, else `
|
|
16
|
-
* `
|
|
14
|
+
* - `POST /token { deviceCode }` → `{ credential, orgId, deviceId, connectUrl,
|
|
15
|
+
* reconnectGraceSeconds, maxFrameBytes }` once, else `device_sign_in.authorization_pending` / `device_sign_in.slow_down` /
|
|
16
|
+
* `device_sign_in.denied` / `device_sign_in.expired` (`device-token-ip`).
|
|
17
17
|
*
|
|
18
18
|
* The person's routes need a web session (the confirmation page `/device`); each try of a user
|
|
19
19
|
* code counts on `device-code-account` (refunded on success):
|
|
20
20
|
* - `GET /pending/:userCode` → `{ machine, expiresAt }`;
|
|
21
|
-
* - `POST /confirm { userCode, orgId,
|
|
22
|
-
* (`
|
|
21
|
+
* - `POST /confirm { userCode, orgId, deviceId | name }` → `{ deviceId }`
|
|
22
|
+
* (`device_sign_in.expired` / `device_sign_in.unavailable` when the credential could not be handed over: the
|
|
23
23
|
* machine is revoked again and the person runs login again);
|
|
24
24
|
* - `POST /deny { userCode }` → 204.
|
|
25
25
|
*/
|
|
@@ -34,7 +34,7 @@ export declare class DeviceAuthController {
|
|
|
34
34
|
expiresAt: string;
|
|
35
35
|
}>;
|
|
36
36
|
confirm(principal: Principal, body: z.infer<typeof DeviceConfirmBody>, req: FastifyRequest, reply: FastifyReply): Promise<{
|
|
37
|
-
|
|
37
|
+
deviceId: string;
|
|
38
38
|
}>;
|
|
39
39
|
deny(principal: Principal, body: z.infer<typeof DeviceUserCodeBody>, req: FastifyRequest, reply: FastifyReply): Promise<void>;
|
|
40
40
|
/** Runs `fn` as one counted try of a user code; a success gives the try back. */
|
|
@@ -23,15 +23,15 @@ const CODE_THROTTLER = ["device-code-account"];
|
|
|
23
23
|
* they need `X-Capybara-Csrf: 1`, which `capybara-device` sends:
|
|
24
24
|
* - `POST /authorize { name, os, arch, programVersion }` → `{ deviceCode, userCode,
|
|
25
25
|
* verificationUri, verificationUriComplete, interval, expiresIn }` (`device-authorize-ip`);
|
|
26
|
-
* - `POST /token { deviceCode }` → `{ credential, orgId,
|
|
27
|
-
* reconnectGraceSeconds, maxFrameBytes }` once, else `
|
|
28
|
-
* `
|
|
26
|
+
* - `POST /token { deviceCode }` → `{ credential, orgId, deviceId, connectUrl,
|
|
27
|
+
* reconnectGraceSeconds, maxFrameBytes }` once, else `device_sign_in.authorization_pending` / `device_sign_in.slow_down` /
|
|
28
|
+
* `device_sign_in.denied` / `device_sign_in.expired` (`device-token-ip`).
|
|
29
29
|
*
|
|
30
30
|
* The person's routes need a web session (the confirmation page `/device`); each try of a user
|
|
31
31
|
* code counts on `device-code-account` (refunded on success):
|
|
32
32
|
* - `GET /pending/:userCode` → `{ machine, expiresAt }`;
|
|
33
|
-
* - `POST /confirm { userCode, orgId,
|
|
34
|
-
* (`
|
|
33
|
+
* - `POST /confirm { userCode, orgId, deviceId | name }` → `{ deviceId }`
|
|
34
|
+
* (`device_sign_in.expired` / `device_sign_in.unavailable` when the credential could not be handed over: the
|
|
35
35
|
* machine is revoked again and the person runs login again);
|
|
36
36
|
* - `POST /deny { userCode }` → 204.
|
|
37
37
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Redis } from "ioredis";
|
|
2
|
-
import {
|
|
2
|
+
import { DevicesService } from "../devices/devices.service.js";
|
|
3
3
|
import type { UserPrincipal } from "../identity/principal.js";
|
|
4
4
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
5
5
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
@@ -10,8 +10,8 @@ import { MachinesService } from "./machines.js";
|
|
|
10
10
|
export declare const USER_CODE_ALPHABET = "BCDFGHJKLMNPQRSTVWXZ";
|
|
11
11
|
/** What `slow_down` adds to the poll interval (RFC 8628 §3.5). */
|
|
12
12
|
export declare const SLOW_DOWN_STEP_SECONDS = 5;
|
|
13
|
-
/** The web page that confirms a code: `<http.publicUrl>/
|
|
14
|
-
export declare const DEVICE_PAGE_PATH = "/
|
|
13
|
+
/** The web page that confirms a code: `<http.publicUrl>/devices/link`. */
|
|
14
|
+
export declare const DEVICE_PAGE_PATH = "/devices/link";
|
|
15
15
|
/** The machine's WebSocket route: `ws(s)://<http.publicUrl host>/device/connect`. */
|
|
16
16
|
export declare const DEVICE_CONNECT_PATH = "/device/connect";
|
|
17
17
|
/** The sign-in state of one device code: `capk:device-auth:<sha256(deviceCode)>` (a hash). */
|
|
@@ -28,7 +28,7 @@ export interface DeviceMachineInfo {
|
|
|
28
28
|
interface Grant {
|
|
29
29
|
credential: string;
|
|
30
30
|
orgId: string;
|
|
31
|
-
|
|
31
|
+
deviceId: string;
|
|
32
32
|
}
|
|
33
33
|
export interface DeviceAuthorization {
|
|
34
34
|
deviceCode: string;
|
|
@@ -41,7 +41,7 @@ export interface DeviceAuthorization {
|
|
|
41
41
|
export interface DeviceGrant extends Grant {
|
|
42
42
|
connectUrl: string;
|
|
43
43
|
reconnectGraceSeconds: number;
|
|
44
|
-
/** `
|
|
44
|
+
/** `devices.local.maxFrameBytes`: the program never sends a larger frame (ruling R26). */
|
|
45
45
|
maxFrameBytes: number;
|
|
46
46
|
}
|
|
47
47
|
/** A user code as typed → `XXXX-XXXX`, or null when it cannot be one. */
|
|
@@ -51,7 +51,7 @@ export declare function normalizeUserCode(input: string): string | null;
|
|
|
51
51
|
* for a code pair (`authorize`), the signed-in person confirms the user code on the web page
|
|
52
52
|
* `/device` (`pending`, `confirm` or `deny`), and the program polls `token` until it gets the
|
|
53
53
|
* machine credential, once. State lives only in Redis, both keys with the code's TTL
|
|
54
|
-
* (`
|
|
54
|
+
* (`devices.local.authCodeTtlSeconds`): `capk:device-auth:<sha256(deviceCode)>` (a hash:
|
|
55
55
|
* `info` JSON, `status`, `interval`, `lastPollAt`, the parked `grant`) and
|
|
56
56
|
* `capk:device-user:<userCode>` → the device code's hash. The device code itself is never stored.
|
|
57
57
|
*/
|
|
@@ -60,16 +60,16 @@ export declare class DeviceAuthService {
|
|
|
60
60
|
readonly txHost: TransactionHost;
|
|
61
61
|
private readonly redis;
|
|
62
62
|
private readonly config;
|
|
63
|
-
private readonly
|
|
63
|
+
private readonly devices;
|
|
64
64
|
private readonly machines;
|
|
65
65
|
private readonly log;
|
|
66
|
-
constructor(db: KernelDb, txHost: TransactionHost, redis: Redis, config: Pick<KernelConfigService, "get">,
|
|
66
|
+
constructor(db: KernelDb, txHost: TransactionHost, redis: Redis, config: Pick<KernelConfigService, "get">, devices: Pick<DevicesService, "createLocal">, machines: Pick<MachinesService, "issue" | "revokeMachine">, log: Pick<KernelLogger, "warn">);
|
|
67
67
|
/** A new code pair for a machine. Needs `http.publicUrl` (the page and the connection URL). */
|
|
68
68
|
authorize(machine: DeviceMachineInfo): Promise<DeviceAuthorization>;
|
|
69
69
|
/**
|
|
70
70
|
* The program's poll: the grant once the person confirmed (the code is consumed), else
|
|
71
|
-
* `
|
|
72
|
-
* interval), `
|
|
71
|
+
* `device_sign_in.authorization_pending`, `device_sign_in.slow_down` (details `[{ interval }]`, the grown
|
|
72
|
+
* interval), `device_sign_in.denied` or `device_sign_in.expired` (also for an unknown code).
|
|
73
73
|
*/
|
|
74
74
|
token(deviceCode: string): Promise<DeviceGrant>;
|
|
75
75
|
/** The machine waiting behind a user code, for the confirmation page. */
|
|
@@ -79,10 +79,10 @@ export declare class DeviceAuthService {
|
|
|
79
79
|
}>;
|
|
80
80
|
/**
|
|
81
81
|
* The person confirms a user code: in an org where they may use agents (`agents.use`), into
|
|
82
|
-
* one of their own live
|
|
83
|
-
* while the name is taken). One transaction creates the
|
|
84
|
-
* machine (revoking the
|
|
85
|
-
* `
|
|
82
|
+
* one of their own live local devices or a new one named `name` (` 2`, ` 3`, … appended
|
|
83
|
+
* while the name is taken). One transaction creates the device if needed, issues the
|
|
84
|
+
* machine (revoking the device's previous one) and audits
|
|
85
|
+
* `device.machine_connected` (retried once when a concurrent confirmation took the new
|
|
86
86
|
* name); after the commit the credential is parked for the poll ({@link park}). The code is
|
|
87
87
|
* claimed first, so two confirmations of one code cannot both issue a machine; a confirmation
|
|
88
88
|
* that fails before the commit leaves it pending.
|
|
@@ -90,28 +90,28 @@ export declare class DeviceAuthService {
|
|
|
90
90
|
confirm(principal: UserPrincipal, input: {
|
|
91
91
|
userCode: string;
|
|
92
92
|
orgId: string;
|
|
93
|
-
|
|
93
|
+
deviceId?: string | undefined;
|
|
94
94
|
name?: string | undefined;
|
|
95
95
|
}): Promise<{
|
|
96
|
-
|
|
96
|
+
deviceId: string;
|
|
97
97
|
}>;
|
|
98
98
|
/**
|
|
99
99
|
* Parks the committed machine's credential for the poll. When that fails (the code expired
|
|
100
100
|
* meanwhile, or Redis failed) the machine is revoked again, so no credential nobody holds stays
|
|
101
|
-
* valid, and the person is told to start over: `
|
|
101
|
+
* valid, and the person is told to start over: `device_sign_in.expired` / `device_sign_in.unavailable`.
|
|
102
102
|
*/
|
|
103
103
|
private park;
|
|
104
104
|
/** Revokes a machine whose credential never reached the program (see {@link park}). */
|
|
105
105
|
private abandon;
|
|
106
|
-
/** The person refuses a user code: the program's next poll gets `
|
|
106
|
+
/** The person refuses a user code: the program's next poll gets `device_sign_in.denied`. */
|
|
107
107
|
deny(userCode: string): Promise<void>;
|
|
108
108
|
private confirmIn;
|
|
109
109
|
/** `name`, or `name 2`, `name 3`, … : the first that is none of the person's live names. */
|
|
110
110
|
private freeName;
|
|
111
|
-
/** The code behind a user code with status `status`, else `
|
|
111
|
+
/** The code behind a user code with status `status`, else `device_sign_in.code_invalid`. */
|
|
112
112
|
private lookup;
|
|
113
113
|
private transition;
|
|
114
|
-
/** `http.publicUrl` without trailing slashes; unset → `
|
|
114
|
+
/** `http.publicUrl` without trailing slashes; unset → `device.unavailable`. */
|
|
115
115
|
private publicUrl;
|
|
116
116
|
/** The machine's WebSocket URL: the public URL with `ws` / `wss` and `/device/connect`. */
|
|
117
117
|
private connectUrl;
|