@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
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ConnectionGuideState } from "../extensions/plugin-guides.js";
|
|
2
3
|
import { PluginIcons } from "../extensions/plugin-icons.js";
|
|
3
4
|
import { type Principal } from "../identity/principal.js";
|
|
4
5
|
import { type OrgContext } from "../orgs/org.guard.js";
|
|
5
6
|
import { ConnectorAccountPolicies, type MemberToolPolicyView } from "./connector-account-policies.js";
|
|
6
|
-
import { CredentialValue, MemberToolPoliciesBody } from "./connectors.schemas.js";
|
|
7
|
+
import { ConnectorGuideAckSchema, CredentialValue, MemberToolPoliciesBody } from "./connectors.schemas.js";
|
|
7
8
|
import { type ConnectorDetail, type ConnectorPreview, type ConnectorSummary, ConnectorsService, type ToolIssue } from "./connectors.service.js";
|
|
8
9
|
declare const CreateBody: z.ZodObject<{
|
|
9
10
|
name: z.ZodString;
|
|
@@ -169,6 +170,14 @@ declare const UpdateBody: z.ZodObject<{
|
|
|
169
170
|
}, z.core.$strict>>>;
|
|
170
171
|
allowUnannotated: z.ZodOptional<z.ZodBoolean>;
|
|
171
172
|
}, z.core.$strict>;
|
|
173
|
+
/**
|
|
174
|
+
* A connector as the org's pages show it: with its plugin's icon (`icon`, see `withIcons`), its
|
|
175
|
+
* template's setup guide and the drift since it was set up (`setupGuide`, `guideDrift`; spec
|
|
176
|
+
* 2026-11-09-setup-guides-v2-design.md §9.3, §11).
|
|
177
|
+
*/
|
|
178
|
+
export type ConnectorPage<T extends ConnectorSummary = ConnectorDetail> = T & ConnectionGuideState & {
|
|
179
|
+
icon: string | null;
|
|
180
|
+
};
|
|
172
181
|
/**
|
|
173
182
|
* 连接器(`/api/v1/orgs/:orgId/connectors`):读与个人凭据用 `connectors.use`(访客起),安装 / 修改 / 删除 / 刷新 /
|
|
174
183
|
* 组织凭据用 `connectors.manage`(管理员起);两者都仅限用户主体。
|
|
@@ -185,10 +194,11 @@ export declare class ConnectorsController {
|
|
|
185
194
|
*/
|
|
186
195
|
private withIcons;
|
|
187
196
|
list(org: OrgContext): Promise<{
|
|
188
|
-
connectors:
|
|
189
|
-
icon: string | null;
|
|
190
|
-
})[];
|
|
197
|
+
connectors: ConnectorPage<ConnectorSummary>[];
|
|
191
198
|
}>;
|
|
199
|
+
/** Adds the icon and the setup guide fields to connector views (one lookup each for all). */
|
|
200
|
+
private withGuides;
|
|
201
|
+
private withGuide;
|
|
192
202
|
/**
|
|
193
203
|
* The connector kinds the org can create connectors of, each with the plugin providing it (the
|
|
194
204
|
* install wizard offers only these; an empty list means no connector extension is enabled).
|
|
@@ -200,7 +210,7 @@ export declare class ConnectorsController {
|
|
|
200
210
|
}[];
|
|
201
211
|
}>;
|
|
202
212
|
create(principal: Principal, org: OrgContext, body: z.infer<typeof CreateBody>): Promise<{
|
|
203
|
-
connector:
|
|
213
|
+
connector: ConnectorPage;
|
|
204
214
|
issues: ToolIssue[];
|
|
205
215
|
}>;
|
|
206
216
|
/**
|
|
@@ -209,16 +219,14 @@ export declare class ConnectorsController {
|
|
|
209
219
|
*/
|
|
210
220
|
preview(principal: Principal, org: OrgContext, body: z.infer<typeof PreviewBody>): Promise<ConnectorPreview>;
|
|
211
221
|
get(principal: Principal, org: OrgContext, connectorId: string): Promise<{
|
|
212
|
-
connector:
|
|
213
|
-
icon: string | null;
|
|
214
|
-
};
|
|
222
|
+
connector: ConnectorPage;
|
|
215
223
|
}>;
|
|
216
224
|
update(principal: Principal, org: OrgContext, connectorId: string, body: z.infer<typeof UpdateBody>): Promise<{
|
|
217
|
-
connector:
|
|
225
|
+
connector: ConnectorPage;
|
|
218
226
|
}>;
|
|
219
227
|
remove(principal: Principal, org: OrgContext, connectorId: string): Promise<void>;
|
|
220
228
|
refresh(principal: Principal, org: OrgContext, connectorId: string): Promise<{
|
|
221
|
-
connector:
|
|
229
|
+
connector: ConnectorPage;
|
|
222
230
|
issues: ToolIssue[];
|
|
223
231
|
changes: {
|
|
224
232
|
added: string[];
|
|
@@ -228,7 +236,16 @@ export declare class ConnectorsController {
|
|
|
228
236
|
}>;
|
|
229
237
|
/** 复核待复核的工具(漂移检测,spec 7.3):approve 采用新定义并启用,reject 停用并保留旧定义。 */
|
|
230
238
|
review(principal: Principal, org: OrgContext, connectorId: string, name: string, body: z.infer<typeof ReviewBody>): Promise<{
|
|
231
|
-
connector:
|
|
239
|
+
connector: ConnectorPage;
|
|
240
|
+
}>;
|
|
241
|
+
/**
|
|
242
|
+
* 「我已更新应用」: the org admin updated the third-party app to the connector template's current
|
|
243
|
+
* setup guide (`{ hash }` of the guide shown) -> 200 `{ connector }`; 409
|
|
244
|
+
* `connector.guide_changed` when the guide moved on since, 404 `catalog.guide_not_found` for a
|
|
245
|
+
* connector without a template guide.
|
|
246
|
+
*/
|
|
247
|
+
ackGuide(principal: Principal, org: OrgContext, connectorId: string, body: z.infer<typeof ConnectorGuideAckSchema>): Promise<{
|
|
248
|
+
connector: ConnectorPage;
|
|
232
249
|
}>;
|
|
233
250
|
setOrgCredential(principal: Principal, org: OrgContext, connectorId: string, body: z.infer<typeof CredentialValue>): Promise<void>;
|
|
234
251
|
setMyCredential(principal: Principal, org: OrgContext, connectorId: string, body: z.infer<typeof CredentialValue>): Promise<void>;
|
|
@@ -17,7 +17,7 @@ import { ZBody } from "../infra/validation/zod-params.js";
|
|
|
17
17
|
import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
|
|
18
18
|
import { can } from "../orgs/roles.js";
|
|
19
19
|
import { ConnectorAccountPolicies, } from "./connector-account-policies.js";
|
|
20
|
-
import { CredentialValue, MemberToolPoliciesBody } from "./connectors.schemas.js";
|
|
20
|
+
import { ConnectorGuideAckSchema, CredentialValue, MemberToolPoliciesBody, } from "./connectors.schemas.js";
|
|
21
21
|
import { ConnectorsService, } from "./connectors.service.js";
|
|
22
22
|
import { publicEndpoint } from "./endpoint.js";
|
|
23
23
|
/**
|
|
@@ -88,6 +88,8 @@ class ConnectorCredentialBody extends createZodDto(CredentialValue, "ConnectorCr
|
|
|
88
88
|
}
|
|
89
89
|
class MemberToolPoliciesDto extends createZodDto(MemberToolPoliciesBody, "MemberToolPoliciesBody") {
|
|
90
90
|
}
|
|
91
|
+
class ConnectorGuideAckBody extends createZodDto(ConnectorGuideAckSchema, "ConnectorGuideAckBody") {
|
|
92
|
+
}
|
|
91
93
|
/**
|
|
92
94
|
* 连接器(`/api/v1/orgs/:orgId/connectors`):读与个人凭据用 `connectors.use`(访客起),安装 / 修改 / 删除 / 刷新 /
|
|
93
95
|
* 组织凭据用 `connectors.manage`(管理员起);两者都仅限用户主体。
|
|
@@ -115,8 +117,22 @@ let ConnectorsController = class ConnectorsController {
|
|
|
115
117
|
}));
|
|
116
118
|
}
|
|
117
119
|
async list(org) {
|
|
118
|
-
const
|
|
119
|
-
return { connectors: await this.
|
|
120
|
+
const list = (await this.connectors.list(org.orgId)).map((a) => forViewer(org, a));
|
|
121
|
+
return { connectors: await this.withGuides(org, list) };
|
|
122
|
+
}
|
|
123
|
+
/** Adds the icon and the setup guide fields to connector views (one lookup each for all). */
|
|
124
|
+
async withGuides(org, views) {
|
|
125
|
+
const [withIcons, states] = await Promise.all([
|
|
126
|
+
this.withIcons(org, views),
|
|
127
|
+
this.connectors.guideStates(org, views.map((v) => v.id)),
|
|
128
|
+
]);
|
|
129
|
+
return withIcons.map((v) => ({
|
|
130
|
+
...v,
|
|
131
|
+
...(states.get(v.id) ?? { setupGuide: null, guideDrift: null }),
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
async withGuide(org, view) {
|
|
135
|
+
return (await this.withGuides(org, [view]))[0];
|
|
120
136
|
}
|
|
121
137
|
/**
|
|
122
138
|
* The connector kinds the org can create connectors of, each with the plugin providing it (the
|
|
@@ -127,7 +143,8 @@ let ConnectorsController = class ConnectorsController {
|
|
|
127
143
|
}
|
|
128
144
|
async create(principal, org, body) {
|
|
129
145
|
const p = requireUser(principal);
|
|
130
|
-
|
|
146
|
+
const r = await this.connectors.create(org.orgId, p.account.id, body, patTokenId(p));
|
|
147
|
+
return { ...r, connector: await this.withGuide(org, r.connector) };
|
|
131
148
|
}
|
|
132
149
|
/**
|
|
133
150
|
* 预览(安装向导):读端点描述(认证提示、操作清单)并在能认证时列出工具,什么都不写。
|
|
@@ -139,15 +156,13 @@ let ConnectorsController = class ConnectorsController {
|
|
|
139
156
|
}
|
|
140
157
|
async get(principal, org, connectorId) {
|
|
141
158
|
const p = requireUser(principal);
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
return { connector: connector };
|
|
159
|
+
const view = forViewer(org, await this.connectors.get(org.orgId, connectorId, p.account.id));
|
|
160
|
+
return { connector: await this.withGuide(org, view) };
|
|
145
161
|
}
|
|
146
162
|
async update(principal, org, connectorId, body) {
|
|
147
163
|
const p = requireUser(principal);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
};
|
|
164
|
+
const view = await this.connectors.update(org.orgId, connectorId, p.account.id, body, patTokenId(p));
|
|
165
|
+
return { connector: await this.withGuide(org, view) };
|
|
151
166
|
}
|
|
152
167
|
async remove(principal, org, connectorId) {
|
|
153
168
|
const p = requireUser(principal);
|
|
@@ -155,14 +170,25 @@ let ConnectorsController = class ConnectorsController {
|
|
|
155
170
|
}
|
|
156
171
|
async refresh(principal, org, connectorId) {
|
|
157
172
|
const p = requireUser(principal);
|
|
158
|
-
|
|
173
|
+
const r = await this.connectors.refresh(org.orgId, connectorId, p.account.id, patTokenId(p));
|
|
174
|
+
return { ...r, connector: await this.withGuide(org, r.connector) };
|
|
159
175
|
}
|
|
160
176
|
/** 复核待复核的工具(漂移检测,spec 7.3):approve 采用新定义并启用,reject 停用并保留旧定义。 */
|
|
161
177
|
async review(principal, org, connectorId, name, body) {
|
|
162
178
|
const p = requireUser(principal);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
const view = await this.connectors.reviewTool(org.orgId, connectorId, name, body.action, p.account.id, patTokenId(p));
|
|
180
|
+
return { connector: await this.withGuide(org, view) };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 「我已更新应用」: the org admin updated the third-party app to the connector template's current
|
|
184
|
+
* setup guide (`{ hash }` of the guide shown) -> 200 `{ connector }`; 409
|
|
185
|
+
* `connector.guide_changed` when the guide moved on since, 404 `catalog.guide_not_found` for a
|
|
186
|
+
* connector without a template guide.
|
|
187
|
+
*/
|
|
188
|
+
async ackGuide(principal, org, connectorId, body) {
|
|
189
|
+
const p = requireUser(principal);
|
|
190
|
+
const view = await this.connectors.ackGuide({ orgId: org.orgId, role: org.role }, connectorId, body.hash, p.account.id, patTokenId(p));
|
|
191
|
+
return { connector: await this.withGuide(org, view) };
|
|
166
192
|
}
|
|
167
193
|
async setOrgCredential(principal, org, connectorId, body) {
|
|
168
194
|
const p = requireUser(principal);
|
|
@@ -263,6 +289,15 @@ __decorate([
|
|
|
263
289
|
__param(3, Param("name")),
|
|
264
290
|
__param(4, ZBody(ConnectorToolReviewBody))
|
|
265
291
|
], ConnectorsController.prototype, "review", null);
|
|
292
|
+
__decorate([
|
|
293
|
+
Post(":connectorId/guide-ack"),
|
|
294
|
+
HttpCode(200),
|
|
295
|
+
OrgAction("connectors.manage"),
|
|
296
|
+
__param(0, CurrentPrincipal()),
|
|
297
|
+
__param(1, CurrentOrg()),
|
|
298
|
+
__param(2, Param("connectorId")),
|
|
299
|
+
__param(3, ZBody(ConnectorGuideAckBody))
|
|
300
|
+
], ConnectorsController.prototype, "ackGuide", null);
|
|
266
301
|
__decorate([
|
|
267
302
|
Put(":connectorId/credentials/org"),
|
|
268
303
|
HttpCode(204),
|
|
@@ -5,6 +5,10 @@ import type { RouteSchemas } from "../platform/route-schemas.js";
|
|
|
5
5
|
* echoed); this only bounds its size.
|
|
6
6
|
*/
|
|
7
7
|
export declare const CredentialValue: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
8
|
+
/** 「我已更新应用」: the admin drift hash of the connector template guide the person was shown. */
|
|
9
|
+
export declare const ConnectorGuideAckSchema: z.ZodObject<{
|
|
10
|
+
hash: z.ZodString;
|
|
11
|
+
}, z.core.$strict>;
|
|
8
12
|
/** `:connectorId` as the routes take it (`@Param`). */
|
|
9
13
|
export declare const ConnectorPathParams: z.ZodObject<{
|
|
10
14
|
connectorId: z.ZodString;
|
|
@@ -6,6 +6,10 @@ import { z } from "zod";
|
|
|
6
6
|
export const CredentialValue = z
|
|
7
7
|
.record(z.string().max(100), z.unknown())
|
|
8
8
|
.refine((v) => JSON.stringify(v).length <= 16_384, { message: "Credential is too large" });
|
|
9
|
+
/** 「我已更新应用」: the admin drift hash of the connector template guide the person was shown. */
|
|
10
|
+
export const ConnectorGuideAckSchema = z
|
|
11
|
+
.object({ hash: z.string().regex(/^[0-9a-f]{64}$/) })
|
|
12
|
+
.strict();
|
|
9
13
|
/** `:connectorId` as the routes take it (`@Param`). */
|
|
10
14
|
export const ConnectorPathParams = z.object({ connectorId: z.string().min(1) });
|
|
11
15
|
export const CONNECTOR_ROUTES = [
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type AuthHint, type ConnectorOperation, type ToolAnnotations } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { type ConnectionGuideState, PluginGuides } from "../extensions/plugin-guides.js";
|
|
2
3
|
import { ExtensionRegistry } from "../extensions/registry.js";
|
|
3
4
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
4
5
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
5
6
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
6
7
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
8
|
+
import type { OrgRole } from "../orgs/roles.js";
|
|
7
9
|
import { type ConnectorAuth, type CredentialOwner, Credentials, type StaticSecret } from "./credentials.js";
|
|
8
10
|
import { type DriftChanges, ToolDrift, type ToolIssue } from "./drift.js";
|
|
9
11
|
import { type OAuthClientRecord, type OAuthTokenRecord } from "./oauth/tokens.js";
|
|
@@ -212,11 +214,15 @@ export declare class ConnectorsService {
|
|
|
212
214
|
/** The org row lock (orgs/org-lock.ts): joins the caller's transaction. */
|
|
213
215
|
private readonly orgLock;
|
|
214
216
|
readonly txHost: TransactionHost;
|
|
217
|
+
/** Setup guides of connector templates (spec 2026-11-09-setup-guides-v2-design.md §11). */
|
|
218
|
+
private readonly guides;
|
|
215
219
|
constructor(kdb: KernelDb, registry: ToolRegistry,
|
|
216
220
|
/** Extension manifests (a slug may not take an extension's name). */
|
|
217
221
|
extensions: Pick<ExtensionRegistry, "manifests">, credentials: Credentials, config: Pick<KernelConfigService, "get">, drift: ToolDrift,
|
|
218
222
|
/** The org row lock (orgs/org-lock.ts): joins the caller's transaction. */
|
|
219
|
-
orgLock: Pick<OrgLock, "lockAndAuthorize">, txHost: TransactionHost
|
|
223
|
+
orgLock: Pick<OrgLock, "lockAndAuthorize">, txHost: TransactionHost,
|
|
224
|
+
/** Setup guides of connector templates (spec 2026-11-09-setup-guides-v2-design.md §11). */
|
|
225
|
+
guides: Pick<PluginGuides, "templateAck" | "connectorStates">);
|
|
220
226
|
/** The kernel-schema handle of the current context (its transaction, else the pool). */
|
|
221
227
|
private get db();
|
|
222
228
|
/**
|
|
@@ -305,7 +311,29 @@ export declare class ConnectorsService {
|
|
|
305
311
|
private row;
|
|
306
312
|
private summary;
|
|
307
313
|
private detail;
|
|
308
|
-
/**
|
|
314
|
+
/**
|
|
315
|
+
* The setup guide fields of the org's connectors (`setupGuide`, `guideDrift`; spec
|
|
316
|
+
* 2026-11-09-setup-guides-v2-design.md §9.3, §11): resolved through each connector's platform
|
|
317
|
+
* template to its item's guide for that template; custom connectors get nulls.
|
|
318
|
+
*/
|
|
319
|
+
guideStates(org: {
|
|
320
|
+
orgId: string;
|
|
321
|
+
role: OrgRole;
|
|
322
|
+
}, connectorIds: string[]): Promise<Map<string, ConnectionGuideState>>;
|
|
323
|
+
/**
|
|
324
|
+
* 「我已更新应用」 for a connector made from a template: records the template's current guide as
|
|
325
|
+
* the one it is set up with. `hash` is the admin drift hash of the guide the person was shown;
|
|
326
|
+
* when the plugin moved on since, 409 `connector.guide_changed` (show the new guide first). A
|
|
327
|
+
* connector without a template guide, or whose item the org's catalog does not show -> 404
|
|
328
|
+
* `catalog.guide_not_found`.
|
|
329
|
+
*/
|
|
330
|
+
ackGuide(org: {
|
|
331
|
+
orgId: string;
|
|
332
|
+
role: OrgRole;
|
|
333
|
+
}, connectorId: string, hash: string, actorAccountId: string, actorTokenId?: string): Promise<ConnectorDetail>;
|
|
334
|
+
/** The row and audit of {@link ackGuide}, in one transaction under the org lock. */
|
|
335
|
+
private ackIn;
|
|
336
|
+
/** The org's connectors that are not deleted (by creation time). */
|
|
309
337
|
list(orgId: string): Promise<ConnectorSummary[]>;
|
|
310
338
|
get(orgId: string, connectorId: string, viewerAccountId: string): Promise<ConnectorDetail>;
|
|
311
339
|
/** 改名、启停连接器、工具启停与默认策略、批量把无注解工具改为 allow(`connectors.manage`)。 */
|
|
@@ -15,6 +15,7 @@ import { z } from "zod";
|
|
|
15
15
|
import { connectorTemplateState } from "../catalog/component-state.js";
|
|
16
16
|
import { assertItemInstallable } from "../catalog/request-rules.js";
|
|
17
17
|
import { ApiError } from "../errors.js";
|
|
18
|
+
import { PluginGuides, } from "../extensions/plugin-guides.js";
|
|
18
19
|
import { ExtensionRegistry } from "../extensions/registry.js";
|
|
19
20
|
import { audit } from "../identity/audit.js";
|
|
20
21
|
import { assertCustomAllowed } from "../identity/settings.js";
|
|
@@ -93,11 +94,14 @@ let ConnectorsService = class ConnectorsService {
|
|
|
93
94
|
drift;
|
|
94
95
|
orgLock;
|
|
95
96
|
txHost;
|
|
97
|
+
guides;
|
|
96
98
|
constructor(kdb, registry,
|
|
97
99
|
/** Extension manifests (a slug may not take an extension's name). */
|
|
98
100
|
extensions, credentials, config, drift,
|
|
99
101
|
/** The org row lock (orgs/org-lock.ts): joins the caller's transaction. */
|
|
100
|
-
orgLock, txHost
|
|
102
|
+
orgLock, txHost,
|
|
103
|
+
/** Setup guides of connector templates (spec 2026-11-09-setup-guides-v2-design.md §11). */
|
|
104
|
+
guides) {
|
|
101
105
|
this.kdb = kdb;
|
|
102
106
|
this.registry = registry;
|
|
103
107
|
this.extensions = extensions;
|
|
@@ -106,6 +110,7 @@ let ConnectorsService = class ConnectorsService {
|
|
|
106
110
|
this.drift = drift;
|
|
107
111
|
this.orgLock = orgLock;
|
|
108
112
|
this.txHost = txHost;
|
|
113
|
+
this.guides = guides;
|
|
109
114
|
}
|
|
110
115
|
/** The kernel-schema handle of the current context (its transaction, else the pool). */
|
|
111
116
|
get db() {
|
|
@@ -366,6 +371,11 @@ let ConnectorsService = class ConnectorsService {
|
|
|
366
371
|
return this.credentials.injectionFor(id, auth, secret);
|
|
367
372
|
}, { orgId, slug });
|
|
368
373
|
}
|
|
374
|
+
// the guide the wizard and 补充配置 showed: the template's current one (spec §11)
|
|
375
|
+
const tpl = input.template;
|
|
376
|
+
const guideAck = tpl?.templateId !== undefined
|
|
377
|
+
? await this.guides.templateAck(tpl.itemId, tpl.templateId)
|
|
378
|
+
: null;
|
|
369
379
|
return this.createIn(orgId, actorAccountId, input, actorTokenId, {
|
|
370
380
|
id,
|
|
371
381
|
slug,
|
|
@@ -374,6 +384,7 @@ let ConnectorsService = class ConnectorsService {
|
|
|
374
384
|
secret,
|
|
375
385
|
oauth,
|
|
376
386
|
listed,
|
|
387
|
+
guideAck,
|
|
377
388
|
});
|
|
378
389
|
}
|
|
379
390
|
/** The org-locked, re-checked insert of {@link create} (the outbound checks ran before). */
|
|
@@ -434,6 +445,8 @@ let ConnectorsService = class ConnectorsService {
|
|
|
434
445
|
catalog_item_id: input.template?.itemId ?? null,
|
|
435
446
|
catalog_version: input.template?.version ?? null,
|
|
436
447
|
platform_template_id: platformTemplate?.id ?? null,
|
|
448
|
+
// linked to its template only through the platform component (drift is judged there)
|
|
449
|
+
guide_ack: platformTemplate !== undefined && c.guideAck !== null ? JSON.stringify(c.guideAck) : null,
|
|
437
450
|
// 授权码连接器安装时没有快照:模板的默认策略留到首个快照时应用
|
|
438
451
|
template_tool_policies: input.template?.defaultToolPolicies
|
|
439
452
|
? JSON.stringify(input.template.defaultToolPolicies)
|
|
@@ -826,7 +839,85 @@ let ConnectorsService = class ConnectorsService {
|
|
|
826
839
|
credential: { ownership: auth.type === "none" ? null : auth.ownership, status },
|
|
827
840
|
};
|
|
828
841
|
}
|
|
829
|
-
/**
|
|
842
|
+
/**
|
|
843
|
+
* The setup guide fields of the org's connectors (`setupGuide`, `guideDrift`; spec
|
|
844
|
+
* 2026-11-09-setup-guides-v2-design.md §9.3, §11): resolved through each connector's platform
|
|
845
|
+
* template to its item's guide for that template; custom connectors get nulls.
|
|
846
|
+
*/
|
|
847
|
+
async guideStates(org, connectorIds) {
|
|
848
|
+
if (connectorIds.length === 0)
|
|
849
|
+
return new Map();
|
|
850
|
+
const rows = await this.db
|
|
851
|
+
.selectFrom("connectors as c")
|
|
852
|
+
.leftJoin("platform_connector_templates as t", "t.id", "c.platform_template_id")
|
|
853
|
+
.select(["c.id", "c.guide_ack", "t.catalog_item_id", "t.template_id"])
|
|
854
|
+
.where("c.org_id", "=", org.orgId)
|
|
855
|
+
.where("c.id", "in", [...new Set(connectorIds)])
|
|
856
|
+
.where("c.deleted_at", "is", null)
|
|
857
|
+
.execute();
|
|
858
|
+
return this.guides.connectorStates(rows.map((r) => ({
|
|
859
|
+
id: r.id,
|
|
860
|
+
itemId: r.catalog_item_id ?? null,
|
|
861
|
+
templateId: r.template_id ?? null,
|
|
862
|
+
guideAck: r.guide_ack ?? null,
|
|
863
|
+
})), org);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* 「我已更新应用」 for a connector made from a template: records the template's current guide as
|
|
867
|
+
* the one it is set up with. `hash` is the admin drift hash of the guide the person was shown;
|
|
868
|
+
* when the plugin moved on since, 409 `connector.guide_changed` (show the new guide first). A
|
|
869
|
+
* connector without a template guide, or whose item the org's catalog does not show -> 404
|
|
870
|
+
* `catalog.guide_not_found`.
|
|
871
|
+
*/
|
|
872
|
+
async ackGuide(org, connectorId, hash, actorAccountId, actorTokenId) {
|
|
873
|
+
const { orgId } = org;
|
|
874
|
+
const r = await this.db
|
|
875
|
+
.selectFrom("connectors as c")
|
|
876
|
+
.leftJoin("platform_connector_templates as t", "t.id", "c.platform_template_id")
|
|
877
|
+
.select(["c.id", "t.catalog_item_id", "t.template_id"])
|
|
878
|
+
.where("c.id", "=", connectorId)
|
|
879
|
+
.where("c.org_id", "=", orgId)
|
|
880
|
+
.where("c.deleted_at", "is", null)
|
|
881
|
+
.executeTakeFirst();
|
|
882
|
+
if (!r)
|
|
883
|
+
throw notFound();
|
|
884
|
+
const ack = r.catalog_item_id && r.template_id
|
|
885
|
+
? // the guide read's visibility: an item the org's catalog does not show has no guide
|
|
886
|
+
await this.guides.templateAck(r.catalog_item_id, r.template_id, org)
|
|
887
|
+
: null;
|
|
888
|
+
if (ack === null) {
|
|
889
|
+
throw new ApiError("catalog.guide_not_found", "The connector has no template setup guide");
|
|
890
|
+
}
|
|
891
|
+
if (ack.hash !== hash) {
|
|
892
|
+
throw new ApiError("connector.guide_changed", "The connector template's setup guide changed since it was shown; review the new guide first");
|
|
893
|
+
}
|
|
894
|
+
return this.ackIn(orgId, connectorId, ack, actorAccountId, actorTokenId);
|
|
895
|
+
}
|
|
896
|
+
/** The row and audit of {@link ackGuide}, in one transaction under the org lock. */
|
|
897
|
+
async ackIn(orgId, connectorId, ack, actorAccountId, actorTokenId) {
|
|
898
|
+
const t = this.db;
|
|
899
|
+
await this.orgLock.lockAndAuthorize(orgId, actorAccountId, "connectors.manage");
|
|
900
|
+
const updated = await t
|
|
901
|
+
.updateTable("connectors")
|
|
902
|
+
.set({ guide_ack: JSON.stringify(ack), updated_at: sql `now()` })
|
|
903
|
+
.where("id", "=", connectorId)
|
|
904
|
+
.where("org_id", "=", orgId)
|
|
905
|
+
.where("deleted_at", "is", null)
|
|
906
|
+
.returning("id")
|
|
907
|
+
.executeTakeFirst();
|
|
908
|
+
if (!updated)
|
|
909
|
+
throw notFound();
|
|
910
|
+
await audit(t, {
|
|
911
|
+
actorAccountId,
|
|
912
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
913
|
+
orgId,
|
|
914
|
+
action: "connector.guide_confirmed",
|
|
915
|
+
target: connectorId,
|
|
916
|
+
detail: { guideId: ack.guideId, version: ack.version },
|
|
917
|
+
});
|
|
918
|
+
return this.detail(t, orgId, connectorId, actorAccountId);
|
|
919
|
+
}
|
|
920
|
+
/** The org's connectors that are not deleted (by creation time). */
|
|
830
921
|
async list(orgId) {
|
|
831
922
|
const rows = await this.db
|
|
832
923
|
.selectFrom("connectors")
|
|
@@ -1236,6 +1327,9 @@ __decorate([
|
|
|
1236
1327
|
__decorate([
|
|
1237
1328
|
Transactional({ propagation: "mandatory" })
|
|
1238
1329
|
], ConnectorsService.prototype, "applyTemplateIn", null);
|
|
1330
|
+
__decorate([
|
|
1331
|
+
Transactional()
|
|
1332
|
+
], ConnectorsService.prototype, "ackIn", null);
|
|
1239
1333
|
__decorate([
|
|
1240
1334
|
Transactional()
|
|
1241
1335
|
], ConnectorsService.prototype, "update", null);
|
|
@@ -1269,6 +1363,7 @@ ConnectorsService = __decorate([
|
|
|
1269
1363
|
__param(4, Inject(KernelConfigService)),
|
|
1270
1364
|
__param(5, Inject(ToolDrift)),
|
|
1271
1365
|
__param(6, Inject(OrgLock)),
|
|
1272
|
-
__param(7, Inject(TransactionHost))
|
|
1366
|
+
__param(7, Inject(TransactionHost)),
|
|
1367
|
+
__param(8, Inject(PluginGuides))
|
|
1273
1368
|
], ConnectorsService);
|
|
1274
1369
|
export { ConnectorsService };
|
|
@@ -119,6 +119,26 @@ export declare class Credentials {
|
|
|
119
119
|
* 都会更新写入时间),最多 `limit` 个。漂移检查用它挑个人凭据型连接器的凭据。
|
|
120
120
|
*/
|
|
121
121
|
personalHolders(orgId: string, connectorId: string, limit: number): Promise<string[]>;
|
|
122
|
+
/**
|
|
123
|
+
* For setup checks (setup guides v2 §10.4): the input revision of a connector's credentials,
|
|
124
|
+
* the `updated_at` of its OAuth client row, its org credential row and, given `accountId`, that
|
|
125
|
+
* member's row (ISO), never a value. Reads no secret.
|
|
126
|
+
*/
|
|
127
|
+
checkRevision(orgId: string, connectorId: string, accountId: string | null): Promise<string>;
|
|
128
|
+
/**
|
|
129
|
+
* For setup checks (setup guides v2 §10.8), never refreshing or writing anything: every stored
|
|
130
|
+
* credential value of a connector (decrypted: the OAuth client secret and DCR registration
|
|
131
|
+
* token, the org credential, every member's access and refresh tokens or static values) that a
|
|
132
|
+
* check result is redacted by, with the forms they are sent in (what `injectionSecrets` covers
|
|
133
|
+
* for a tool call: the Basic header value, its base64 token and decoded `user:pass`, the
|
|
134
|
+
* `encodeURIComponent` forms; for the client also the `client_secret_basic` header the token
|
|
135
|
+
* request sends and the raw `id:secret`), and the stored OAuth client id (null without a
|
|
136
|
+
* client). Never echo the values; a plugin check gets only a manual client's id.
|
|
137
|
+
*/
|
|
138
|
+
checkMaterial(orgId: string, connectorId: string): Promise<{
|
|
139
|
+
secrets: string[];
|
|
140
|
+
clientId: string | null;
|
|
141
|
+
}>;
|
|
122
142
|
/** 只看与 auth.ownership 对应的那一条凭据是否存在(不解密);none 恒为 connected。 */
|
|
123
143
|
status(orgId: string, connectorId: string, auth: ConnectorAuth, accountId: string): Promise<"connected" | "missing">;
|
|
124
144
|
/** 返回本次请求要注入的头 / 查询参数;缺凭据抛 CredentialMissing。 */
|
|
@@ -17,7 +17,7 @@ import { KernelDb } from "../infra/database/kernel-db.js";
|
|
|
17
17
|
import { LockService } from "../infra/lock/lock.service.js";
|
|
18
18
|
import { KERNEL_LOGGER, KEYRING, REDIS } from "../infra/tokens.js";
|
|
19
19
|
import { oauthHttpOptions } from "./oauth/discovery.js";
|
|
20
|
-
import { OAuthReconnectRequired, OAuthTokens, } from "./oauth/tokens.js";
|
|
20
|
+
import { basicClientAuth, OAuthReconnectRequired, OAuthTokens, } from "./oauth/tokens.js";
|
|
21
21
|
import { injectionSecrets } from "./redact.js";
|
|
22
22
|
export const isOAuth = (auth) => auth.type === "oauth_code" || auth.type === "oauth_client";
|
|
23
23
|
/** 缺凭据:只带连接器 id 与归属,绝不带值。 */
|
|
@@ -239,6 +239,95 @@ let Credentials = class Credentials {
|
|
|
239
239
|
LIMIT ${limit}`.execute(this.db.db);
|
|
240
240
|
return rows.rows.map((r) => r.account_id);
|
|
241
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* For setup checks (setup guides v2 §10.4): the input revision of a connector's credentials,
|
|
244
|
+
* the `updated_at` of its OAuth client row, its org credential row and, given `accountId`, that
|
|
245
|
+
* member's row (ISO), never a value. Reads no secret.
|
|
246
|
+
*/
|
|
247
|
+
async checkRevision(orgId, connectorId, accountId) {
|
|
248
|
+
const keys = [clientKey(connectorId), orgKey(connectorId)];
|
|
249
|
+
if (accountId !== null)
|
|
250
|
+
keys.push(userKey(connectorId, accountId));
|
|
251
|
+
const rows = await this.db
|
|
252
|
+
.selectFrom("secrets")
|
|
253
|
+
.select(["key", "updated_at"])
|
|
254
|
+
.where("namespace", "=", NAMESPACE)
|
|
255
|
+
.where("org_id", "=", orgId)
|
|
256
|
+
.where("key", "in", keys)
|
|
257
|
+
.execute();
|
|
258
|
+
const at = new Map(rows.map((r) => [r.key, new Date(r.updated_at).toISOString()]));
|
|
259
|
+
return keys.map((k) => at.get(k) ?? "-").join("|");
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* For setup checks (setup guides v2 §10.8), never refreshing or writing anything: every stored
|
|
263
|
+
* credential value of a connector (decrypted: the OAuth client secret and DCR registration
|
|
264
|
+
* token, the org credential, every member's access and refresh tokens or static values) that a
|
|
265
|
+
* check result is redacted by, with the forms they are sent in (what `injectionSecrets` covers
|
|
266
|
+
* for a tool call: the Basic header value, its base64 token and decoded `user:pass`, the
|
|
267
|
+
* `encodeURIComponent` forms; for the client also the `client_secret_basic` header the token
|
|
268
|
+
* request sends and the raw `id:secret`), and the stored OAuth client id (null without a
|
|
269
|
+
* client). Never echo the values; a plugin check gets only a manual client's id.
|
|
270
|
+
*/
|
|
271
|
+
async checkMaterial(orgId, connectorId) {
|
|
272
|
+
const prefix = orgKey(connectorId).slice(0, -"org".length);
|
|
273
|
+
const rows = await this.db
|
|
274
|
+
.selectFrom("secrets")
|
|
275
|
+
.select("key")
|
|
276
|
+
.where("namespace", "=", NAMESPACE)
|
|
277
|
+
.where("org_id", "=", orgId)
|
|
278
|
+
.where(sql `left(key, ${prefix.length})`, "=", prefix)
|
|
279
|
+
.execute();
|
|
280
|
+
const secrets = new Set();
|
|
281
|
+
const push = (...vs) => {
|
|
282
|
+
for (const v of vs) {
|
|
283
|
+
if (typeof v !== "string" || v === "")
|
|
284
|
+
continue;
|
|
285
|
+
// the value and the forms an injection carries it in (`Bearer`, query, percent-encoded)
|
|
286
|
+
for (const s of injectionSecrets({ headers: { a: `Bearer ${v}` }, query: { q: v } })) {
|
|
287
|
+
secrets.add(s);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const pushBasic = (user, password) => {
|
|
292
|
+
const header = `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`;
|
|
293
|
+
for (const s of injectionSecrets({ headers: { a: header } }))
|
|
294
|
+
secrets.add(s);
|
|
295
|
+
};
|
|
296
|
+
let clientId = null;
|
|
297
|
+
for (const r of rows) {
|
|
298
|
+
const v = (await this.readJson(orgId, r.key, connectorId));
|
|
299
|
+
if (v === null || typeof v !== "object")
|
|
300
|
+
continue;
|
|
301
|
+
if (r.key === clientKey(connectorId)) {
|
|
302
|
+
// the client id is not a secret (a plugin check gets it); the secret and DCR token are
|
|
303
|
+
if (typeof v.clientId === "string")
|
|
304
|
+
clientId = v.clientId;
|
|
305
|
+
push(v.clientSecret, v.registration?.accessToken);
|
|
306
|
+
if (typeof v.clientId === "string" && typeof v.clientSecret === "string") {
|
|
307
|
+
// as the token request sends it (both parts form-encoded), and as typed
|
|
308
|
+
const header = basicClientAuth(v.clientId, v.clientSecret);
|
|
309
|
+
for (const s of injectionSecrets({ headers: { a: header } }))
|
|
310
|
+
secrets.add(s);
|
|
311
|
+
pushBasic(v.clientId, v.clientSecret);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else if (typeof v.access_token === "string") {
|
|
315
|
+
push(v.access_token, v.refresh_token);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
push(v.token, v.password);
|
|
319
|
+
if (typeof v.username === "string" && typeof v.password === "string") {
|
|
320
|
+
pushBasic(v.username, v.password);
|
|
321
|
+
}
|
|
322
|
+
if (typeof v.headers === "object" && v.headers !== null) {
|
|
323
|
+
const headers = Object.fromEntries(Object.entries(v.headers).filter((e) => typeof e[1] === "string"));
|
|
324
|
+
for (const s of injectionSecrets({ headers }))
|
|
325
|
+
secrets.add(s);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return { secrets: [...secrets], clientId };
|
|
330
|
+
}
|
|
242
331
|
/** 只看与 auth.ownership 对应的那一条凭据是否存在(不解密);none 恒为 connected。 */
|
|
243
332
|
async status(orgId, connectorId, auth, accountId) {
|
|
244
333
|
if (auth.type === "none")
|
|
@@ -75,6 +75,26 @@ export interface TokenRequestOptions {
|
|
|
75
75
|
/** More `token_type` values to accept as bearer tokens (`auth.tokenTypes`, case-insensitive). */
|
|
76
76
|
tokenTypes?: readonly string[] | undefined;
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The headers and form of a token request (RFC 6749 §3.2): client_id / secret per the client's
|
|
80
|
+
* auth method (Basic form-encodes them first, §2.3.1; otherwise `client_id`, plus
|
|
81
|
+
* `client_secret` for `client_secret_post`). Empty parameters are left out.
|
|
82
|
+
*/
|
|
83
|
+
export declare function tokenRequestInit(client: OAuthClientRecord, params: Record<string, string | undefined>): {
|
|
84
|
+
headers: Record<string, string>;
|
|
85
|
+
body: URLSearchParams;
|
|
86
|
+
};
|
|
87
|
+
/** The form encoding of a Basic client credential part (RFC 6749 §2.3.1). */
|
|
88
|
+
export declare const formEncode: (s: string) => string;
|
|
89
|
+
/** The `Authorization` value of `client_secret_basic` (both parts form-encoded first). */
|
|
90
|
+
export declare const basicClientAuth: (clientId: string, clientSecret: string) => string;
|
|
91
|
+
/**
|
|
92
|
+
* The refusal code of a token endpoint answer, or null when it is not a refusal (the one parser of
|
|
93
|
+
* token refusals): a 400 / 401 whose JSON body has an RFC 6749-shaped `error`, or a 200 whose body
|
|
94
|
+
* carries `ok: false` (Slack) or an `error` and no `access_token`, with a code that is not
|
|
95
|
+
* transient. Only codes matching the RFC 6749 shape are returned, never other text of the body.
|
|
96
|
+
*/
|
|
97
|
+
export declare function parseTokenRefusal(status: number, body: unknown): string | null;
|
|
78
98
|
/**
|
|
79
99
|
* Calls the token endpoint (RFC 6749 §3.2), sending client_id / secret per the client's auth method
|
|
80
100
|
* (Basic form-encodes them first, §2.3.1).
|