@capybara-hq/kernel 0.1.0-rc.13 → 0.1.0-rc.15

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.
Files changed (170) hide show
  1. package/dist/admin/admin.schemas.d.ts +5 -13
  2. package/dist/catalog/admin-catalog.controller.d.ts +39 -5
  3. package/dist/catalog/admin-catalog.controller.js +75 -6
  4. package/dist/catalog/admin-catalog.schemas.d.ts +10 -0
  5. package/dist/catalog/admin-catalog.schemas.js +7 -0
  6. package/dist/catalog/appearance.schemas.d.ts +10 -0
  7. package/dist/catalog/appearance.schemas.js +20 -0
  8. package/dist/catalog/appearance.service.d.ts +105 -0
  9. package/dist/catalog/appearance.service.js +306 -0
  10. package/dist/catalog/catalog-content.d.ts +9 -1
  11. package/dist/catalog/catalog-content.js +2 -1
  12. package/dist/catalog/catalog-files.d.ts +3 -2
  13. package/dist/catalog/catalog-files.js +8 -5
  14. package/dist/catalog/catalog-import.module.js +3 -0
  15. package/dist/catalog/catalog-items.d.ts +11 -0
  16. package/dist/catalog/catalog-items.js +21 -0
  17. package/dist/catalog/catalog-scope.service.d.ts +7 -0
  18. package/dist/catalog/catalog-scope.service.js +55 -15
  19. package/dist/catalog/catalog.service.js +10 -2
  20. package/dist/catalog/cli.js +3 -0
  21. package/dist/catalog/component-scope.service.d.ts +14 -1
  22. package/dist/catalog/component-scope.service.js +12 -2
  23. package/dist/catalog/marketplaces.service.d.ts +1 -1
  24. package/dist/catalog/org-catalog.controller.d.ts +5 -4
  25. package/dist/catalog/org-catalog.controller.js +5 -4
  26. package/dist/catalog/org-catalog.schemas.d.ts +18 -2
  27. package/dist/catalog/org-catalog.schemas.js +16 -2
  28. package/dist/catalog/org-catalog.service.js +8 -2
  29. package/dist/catalog/org-extension.controller.d.ts +27 -7
  30. package/dist/catalog/org-extension.controller.js +48 -6
  31. package/dist/catalog/plugin-import.d.ts +28 -4
  32. package/dist/catalog/plugin-import.js +96 -20
  33. package/dist/catalog/plugin-package.d.ts +4 -2
  34. package/dist/catalog/plugin-package.js +66 -12
  35. package/dist/catalog/plugin-upgrade.d.ts +15 -1
  36. package/dist/catalog/plugin-upgrade.js +18 -5
  37. package/dist/channels/connections.controller.d.ts +1 -1
  38. package/dist/channels/connections.controller.js +1 -1
  39. package/dist/channels/connections.service.d.ts +22 -5
  40. package/dist/channels/connections.service.js +56 -10
  41. package/dist/channels/webhook.d.ts +21 -1
  42. package/dist/channels/webhook.js +39 -4
  43. package/dist/client/client-access.service.d.ts +101 -0
  44. package/dist/client/client-access.service.js +294 -0
  45. package/dist/client/client-builds.service.d.ts +109 -0
  46. package/dist/client/client-builds.service.js +229 -0
  47. package/dist/client/client-delivery.controller.d.ts +25 -0
  48. package/dist/client/client-delivery.controller.js +66 -0
  49. package/dist/client/client-files.d.ts +48 -0
  50. package/dist/client/client-files.js +136 -0
  51. package/dist/client/client-reports.cron.d.ts +13 -0
  52. package/dist/client/client-reports.cron.js +42 -0
  53. package/dist/client/client-reports.service.d.ts +30 -0
  54. package/dist/client/client-reports.service.js +102 -0
  55. package/dist/client/client.controller.d.ts +45 -0
  56. package/dist/client/client.controller.js +121 -0
  57. package/dist/client/client.module.d.ts +7 -0
  58. package/dist/client/client.module.js +26 -0
  59. package/dist/client/client.schemas.d.ts +55 -0
  60. package/dist/client/client.schemas.js +27 -0
  61. package/dist/ctx/create-ctx.d.ts +19 -4
  62. package/dist/ctx/create-ctx.js +51 -3
  63. package/dist/db/kernel-schema.d.ts +58 -2
  64. package/dist/errors.d.ts +33 -0
  65. package/dist/errors.js +33 -0
  66. package/dist/extensions/admin-ops.d.ts +4 -1
  67. package/dist/extensions/admin-ops.js +22 -1
  68. package/dist/extensions/admin-view.d.ts +8 -0
  69. package/dist/extensions/admin-view.js +78 -0
  70. package/dist/extensions/blobs.d.ts +14 -1
  71. package/dist/extensions/blobs.js +48 -5
  72. package/dist/extensions/guide-places.d.ts +66 -0
  73. package/dist/extensions/guide-places.js +152 -0
  74. package/dist/extensions/host.d.ts +6 -1
  75. package/dist/extensions/host.js +23 -12
  76. package/dist/extensions/instance.d.ts +5 -1
  77. package/dist/extensions/instance.js +8 -0
  78. package/dist/extensions/ledger.d.ts +1 -1
  79. package/dist/extensions/package.d.ts +4 -3
  80. package/dist/extensions/package.js +5 -1
  81. package/dist/extensions/permission-set.d.ts +35 -5
  82. package/dist/extensions/permission-set.js +36 -5
  83. package/dist/extensions/permission-view.d.ts +38 -7
  84. package/dist/extensions/permission-view.js +27 -8
  85. package/dist/extensions/plugin-guides.d.ts +207 -54
  86. package/dist/extensions/plugin-guides.js +436 -165
  87. package/dist/extensions/sources.d.ts +6 -0
  88. package/dist/extensions/sources.js +2 -0
  89. package/dist/extensions/state.module.js +9 -1
  90. package/dist/http/api.module.js +16 -0
  91. package/dist/identity/settings.d.ts +41 -26
  92. package/dist/identity/settings.js +87 -4
  93. package/dist/infra/lock/lock.service.d.ts +8 -0
  94. package/dist/infra/lock/lock.service.js +27 -0
  95. package/dist/infra/throttler/named-throttlers.d.ts +8 -1
  96. package/dist/infra/throttler/named-throttlers.js +30 -1
  97. package/dist/infra/throttler/throttler.guard.js +1 -1
  98. package/dist/kernel.module.js +3 -0
  99. package/dist/orgs/settings.service.d.ts +2 -26
  100. package/dist/overrides.d.ts +3 -1
  101. package/dist/overrides.js +2 -0
  102. package/dist/platform/exclusions.js +37 -6
  103. package/dist/platform/operation.js +4 -0
  104. package/dist/platform/ops/admin.ops.js +17 -2
  105. package/dist/platform/ops/catalog-admin.ops.d.ts +19 -1
  106. package/dist/platform/ops/catalog-admin.ops.js +85 -2
  107. package/dist/platform/ops/connectors.ops.js +2 -0
  108. package/dist/platform/ops/org-plugins.ops.d.ts +7 -1
  109. package/dist/platform/ops/org-plugins.ops.js +63 -4
  110. package/dist/platform/ops/org-settings.ops.js +2 -2
  111. package/dist/platform/ops/orgs.ops.js +1 -0
  112. package/dist/platform/ops/setup.ops.d.ts +24 -0
  113. package/dist/platform/ops/setup.ops.js +212 -0
  114. package/dist/platform/ops/ui.ops.js +1 -1
  115. package/dist/platform/platform-ops.module.d.ts +2 -1
  116. package/dist/platform/platform-ops.module.js +7 -0
  117. package/dist/platform/route-schemas.js +8 -0
  118. package/dist/roles/worker.module.js +4 -0
  119. package/dist/setup/kernel-checks.d.ts +91 -0
  120. package/dist/setup/kernel-checks.js +295 -0
  121. package/dist/setup/oauth-token-probe.d.ts +47 -0
  122. package/dist/setup/oauth-token-probe.js +108 -0
  123. package/dist/setup/redact-check.d.ts +18 -0
  124. package/dist/setup/redact-check.js +46 -0
  125. package/dist/setup/setup-check-registry.d.ts +86 -0
  126. package/dist/setup/setup-check-registry.js +75 -0
  127. package/dist/setup/setup-checks.controller.d.ts +28 -0
  128. package/dist/setup/setup-checks.controller.js +78 -0
  129. package/dist/setup/setup-checks.schemas.d.ts +38 -0
  130. package/dist/setup/setup-checks.schemas.js +43 -0
  131. package/dist/setup/setup-checks.service.d.ts +144 -0
  132. package/dist/setup/setup-checks.service.js +683 -0
  133. package/dist/setup/setup-guides.controller.d.ts +18 -0
  134. package/dist/setup/setup-guides.controller.js +48 -0
  135. package/dist/setup/setup-guides.schemas.d.ts +10 -0
  136. package/dist/setup/setup-guides.schemas.js +6 -0
  137. package/dist/setup/setup-guides.service.d.ts +126 -0
  138. package/dist/setup/setup-guides.service.js +315 -0
  139. package/dist/setup/setup.module.d.ts +8 -0
  140. package/dist/setup/setup.module.js +31 -0
  141. package/dist/themes/render-css.d.ts +2 -1
  142. package/dist/themes/render-css.js +5 -2
  143. package/dist/themes/theme-delivery.service.d.ts +4 -2
  144. package/dist/themes/theme-delivery.service.js +8 -3
  145. package/dist/themes/theme-state.d.ts +28 -7
  146. package/dist/themes/theme-state.js +24 -6
  147. package/dist/themes/themes-public.controller.d.ts +7 -2
  148. package/dist/themes/themes-public.controller.js +11 -5
  149. package/dist/themes/themes.service.js +2 -2
  150. package/dist/tools/connectors.controller.d.ts +28 -11
  151. package/dist/tools/connectors.controller.js +49 -14
  152. package/dist/tools/connectors.schemas.d.ts +4 -0
  153. package/dist/tools/connectors.schemas.js +4 -0
  154. package/dist/tools/connectors.service.d.ts +30 -2
  155. package/dist/tools/connectors.service.js +98 -3
  156. package/dist/tools/credentials.d.ts +20 -0
  157. package/dist/tools/credentials.js +90 -1
  158. package/dist/tools/oauth/tokens.d.ts +20 -0
  159. package/dist/tools/oauth/tokens.js +49 -24
  160. package/dist/tools/pipeline.d.ts +3 -2
  161. package/dist/ui/arrangement.d.ts +41 -50
  162. package/dist/ui/arrangement.js +88 -15
  163. package/dist/ui/registry.d.ts +13 -3
  164. package/dist/ui/registry.js +15 -4
  165. package/dist/ui/ui.schemas.d.ts +4 -0
  166. package/dist/ui/views.d.ts +36 -9
  167. package/dist/ui/views.js +58 -28
  168. package/package.json +3 -3
  169. package/src/migrations/0106_setup_guides_v2.sql +10 -0
  170. package/src/migrations/0107_extension_client_builds.sql +50 -0
@@ -0,0 +1,75 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { SETUP_CHECK_ID_RE, SETUP_GUIDE_PLACES } from "@capybara-hq/plugin-sdk";
11
+ import { Inject, Injectable } from "@nestjs/common";
12
+ import { ExtensionRegistry } from "../extensions/registry.js";
13
+ const KERNEL_ID_RE = new RegExp(`^capybara:${SETUP_CHECK_ID_RE.source.slice(1)}`);
14
+ /**
15
+ * Where setup checks come from (spec §10.2, §10.6): the kernel's own `capybara:*` checks, in a
16
+ * map of their own registered once at module init (static code, the same on every replica, like
17
+ * the builtin tools), and an extension's checks, read from its active instance on this replica
18
+ * (registered in its `setup` through `ctx.setup.check`, revoked with the instance). An extension
19
+ * can never register a `capybara:` id (`SETUP_CHECK_ID_RE` has no colon), so it cannot shadow a
20
+ * kernel check.
21
+ */
22
+ let SetupCheckRegistry = class SetupCheckRegistry {
23
+ extensions;
24
+ kernel = new Map();
25
+ constructor(extensions) {
26
+ this.extensions = extensions;
27
+ }
28
+ /** Registers a kernel check; an id twice, a malformed id or an unknown place throws. */
29
+ registerKernel(id, place, run) {
30
+ if (!KERNEL_ID_RE.test(id))
31
+ throw new Error(`setup check id "${id}" is not capybara:<id>`);
32
+ if (place !== "any" && !SETUP_GUIDE_PLACES.includes(place)) {
33
+ throw new Error(`setup check "${id}": unknown place "${place}"`);
34
+ }
35
+ if (typeof run !== "function")
36
+ throw new Error(`setup check "${id}": run must be a function`);
37
+ if (this.kernel.has(id))
38
+ throw new Error(`duplicate kernel setup check "${id}"`);
39
+ this.kernel.set(id, Object.freeze({ place, run }));
40
+ }
41
+ /**
42
+ * The check behind a guide's `::check <id>` line of `plugin`'s guide: a kernel check for
43
+ * `capybara:*`, else the plugin's own (null when this replica does not run the extension or the
44
+ * extension did not register the id).
45
+ */
46
+ resolve(plugin, id) {
47
+ if (id.startsWith("capybara:")) {
48
+ const k = this.kernel.get(id);
49
+ return k ? { source: "kernel", id, place: k.place, run: k.run } : null;
50
+ }
51
+ const inst = this.extensions.current(plugin);
52
+ const c = inst?.setupChecks.get(id);
53
+ if (!inst || !c)
54
+ return null;
55
+ return {
56
+ source: "plugin",
57
+ id,
58
+ place: c.place,
59
+ run: c.run,
60
+ inflight: inst.inflight,
61
+ signal: inst.signal,
62
+ version: inst.version,
63
+ generation: inst.generation,
64
+ };
65
+ }
66
+ /** Whether `plugin` runs on this replica. */
67
+ running(plugin) {
68
+ return this.extensions.current(plugin) !== undefined;
69
+ }
70
+ };
71
+ SetupCheckRegistry = __decorate([
72
+ Injectable(),
73
+ __param(0, Inject(ExtensionRegistry))
74
+ ], SetupCheckRegistry);
75
+ export { SetupCheckRegistry };
@@ -0,0 +1,28 @@
1
+ import type { z } from "zod";
2
+ import { type Principal } from "../identity/principal.js";
3
+ import { type OrgContext } from "../orgs/org.guard.js";
4
+ import type { SetupCheckState } from "./setup-check-registry.js";
5
+ import { SetupCheckPathParams, SetupCheckRunBody, SetupChecksQuery, SetupGuidePathParams } from "./setup-checks.schemas.js";
6
+ import { SetupChecksService } from "./setup-checks.service.js";
7
+ /**
8
+ * The live rows of a setup guide (spec 2026-11-09-setup-guides-v2-design.md §10.3). Authorization
9
+ * is the guide route's (`catalog.read` here; catalog visibility, the place and audience action
10
+ * and the target are checked by the service before anything is loaded). A response carries only
11
+ * the fixed fields of {@link SetupCheckState}.
12
+ */
13
+ export declare class SetupChecksController {
14
+ private readonly checks;
15
+ constructor(checks: SetupChecksService);
16
+ /** The cached state of each check of the rendered guide; never runs anything. */
17
+ states(principal: Principal, org: OrgContext, params: z.infer<typeof SetupGuidePathParams>, q: z.infer<typeof SetupChecksQuery>): Promise<{
18
+ results: Record<string, SetupCheckState>;
19
+ }>;
20
+ /**
21
+ * Runs one check unless a fresh result is cached (`force`: rerun, once per 10 s per check and
22
+ * target). 30 runs a minute per account (429 `rate_limited`): counted by the service, shared
23
+ * with the `Platform` tool's `setup.check`; the throttler also guards the route (`retry-after`).
24
+ */
25
+ run(principal: Principal, org: OrgContext, params: z.infer<typeof SetupCheckPathParams>, body: z.infer<typeof SetupCheckRunBody>): Promise<{
26
+ result: SetupCheckState;
27
+ }>;
28
+ }
@@ -0,0 +1,78 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Controller, Get, HttpCode, Inject, Post } from "@nestjs/common";
11
+ import { CurrentPrincipal, requireUser } from "../identity/principal.js";
12
+ import { Throttled } from "../infra/throttler/throttler.guard.js";
13
+ import { createZodDto } from "../infra/validation/create-zod-dto.js";
14
+ import { ZBody, ZParam, ZQuery } from "../infra/validation/zod-params.js";
15
+ import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
16
+ import { SetupCheckPathParams, SetupCheckRunBody, SetupChecksQuery, SetupGuidePathParams, } from "./setup-checks.schemas.js";
17
+ import { SetupChecksService } from "./setup-checks.service.js";
18
+ class SetupGuideParamsDto extends createZodDto(SetupGuidePathParams, "SetupGuidePathParams") {
19
+ }
20
+ class SetupCheckParamsDto extends createZodDto(SetupCheckPathParams, "SetupCheckPathParams") {
21
+ }
22
+ class SetupChecksQueryDto extends createZodDto(SetupChecksQuery, "SetupChecksQuery") {
23
+ }
24
+ class SetupCheckRunBodyDto extends createZodDto(SetupCheckRunBody, "SetupCheckRunBody") {
25
+ }
26
+ /**
27
+ * The live rows of a setup guide (spec 2026-11-09-setup-guides-v2-design.md §10.3). Authorization
28
+ * is the guide route's (`catalog.read` here; catalog visibility, the place and audience action
29
+ * and the target are checked by the service before anything is loaded). A response carries only
30
+ * the fixed fields of {@link SetupCheckState}.
31
+ */
32
+ let SetupChecksController = class SetupChecksController {
33
+ checks;
34
+ constructor(checks) {
35
+ this.checks = checks;
36
+ }
37
+ /** The cached state of each check of the rendered guide; never runs anything. */
38
+ async states(principal, org, params, q) {
39
+ const p = requireUser(principal);
40
+ return {
41
+ results: await this.checks.states({ orgId: org.orgId, role: org.role, accountId: p.account.id }, params.itemId, params.guideId, q),
42
+ };
43
+ }
44
+ /**
45
+ * Runs one check unless a fresh result is cached (`force`: rerun, once per 10 s per check and
46
+ * target). 30 runs a minute per account (429 `rate_limited`): counted by the service, shared
47
+ * with the `Platform` tool's `setup.check`; the throttler also guards the route (`retry-after`).
48
+ */
49
+ async run(principal, org, params, body) {
50
+ const p = requireUser(principal);
51
+ return {
52
+ result: await this.checks.run({ orgId: org.orgId, role: org.role, accountId: p.account.id }, params.itemId, params.guideId, params.checkId, body),
53
+ };
54
+ }
55
+ };
56
+ __decorate([
57
+ Get(),
58
+ OrgAction("catalog.read"),
59
+ __param(0, CurrentPrincipal()),
60
+ __param(1, CurrentOrg()),
61
+ __param(2, ZParam(SetupGuideParamsDto)),
62
+ __param(3, ZQuery(SetupChecksQueryDto))
63
+ ], SetupChecksController.prototype, "states", null);
64
+ __decorate([
65
+ Post(":checkId/run"),
66
+ HttpCode(200),
67
+ OrgAction("catalog.read"),
68
+ Throttled("setup-check"),
69
+ __param(0, CurrentPrincipal()),
70
+ __param(1, CurrentOrg()),
71
+ __param(2, ZParam(SetupCheckParamsDto)),
72
+ __param(3, ZBody(SetupCheckRunBodyDto))
73
+ ], SetupChecksController.prototype, "run", null);
74
+ SetupChecksController = __decorate([
75
+ Controller("api/v1/orgs/:orgId/catalog/:itemId/guides/:guideId/checks"),
76
+ __param(0, Inject(SetupChecksService))
77
+ ], SetupChecksController);
78
+ export { SetupChecksController };
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import type { RouteSchemas } from "../platform/route-schemas.js";
3
+ /** `:itemId` / `:guideId` of the check routes. */
4
+ export declare const SetupGuidePathParams: z.ZodObject<{
5
+ itemId: z.ZodString;
6
+ guideId: z.ZodString;
7
+ }, z.core.$strip>;
8
+ /** `:itemId` / `:guideId` / `:checkId` of the run route (`capybara:<id>` for a kernel check). */
9
+ export declare const SetupCheckPathParams: z.ZodObject<{
10
+ itemId: z.ZodString;
11
+ guideId: z.ZodString;
12
+ checkId: z.ZodString;
13
+ }, z.core.$strip>;
14
+ /** `GET …/guides/:guideId/checks`: the cached states, nothing runs. */
15
+ export declare const SetupChecksQuery: z.ZodObject<{
16
+ mode: z.ZodOptional<z.ZodString>;
17
+ audience: z.ZodOptional<z.ZodEnum<{
18
+ admin: "admin";
19
+ member: "member";
20
+ }>>;
21
+ connectionId: z.ZodOptional<z.ZodString>;
22
+ connectorId: z.ZodOptional<z.ZodString>;
23
+ }, z.core.$strict>;
24
+ /**
25
+ * `POST …/guides/:guideId/checks/:checkId/run`: runs the check unless a fresh cached result exists;
26
+ * `force` reruns it (at most once per 10 seconds per check and target).
27
+ */
28
+ export declare const SetupCheckRunBody: z.ZodObject<{
29
+ mode: z.ZodOptional<z.ZodString>;
30
+ audience: z.ZodOptional<z.ZodEnum<{
31
+ admin: "admin";
32
+ member: "member";
33
+ }>>;
34
+ connectionId: z.ZodOptional<z.ZodString>;
35
+ connectorId: z.ZodOptional<z.ZodString>;
36
+ force: z.ZodOptional<z.ZodBoolean>;
37
+ }, z.core.$strict>;
38
+ export declare const SETUP_CHECK_ROUTES: readonly RouteSchemas[];
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ /** `:itemId` / `:guideId` of the check routes. */
3
+ export const SetupGuidePathParams = z.object({
4
+ itemId: z.string().min(1).max(100),
5
+ guideId: z.string().min(1).max(64),
6
+ });
7
+ /** `:itemId` / `:guideId` / `:checkId` of the run route (`capybara:<id>` for a kernel check). */
8
+ export const SetupCheckPathParams = SetupGuidePathParams.extend({
9
+ checkId: z.string().min(1).max(64),
10
+ });
11
+ /**
12
+ * The guide the checks belong to, as the guide route renders it (spec
13
+ * 2026-11-09-setup-guides-v2-design.md §10.3): its mode and audience (checked against the place by
14
+ * the service) and the target (`connectionId` for a channel connection, `connectorId` for a
15
+ * connector made from the template). Checks need a target.
16
+ */
17
+ const GuideSelection = {
18
+ mode: z.string().min(1).max(64).optional(),
19
+ audience: z.enum(["admin", "member"]).optional(),
20
+ connectionId: z.string().min(1).max(100).optional(),
21
+ connectorId: z.string().min(1).max(100).optional(),
22
+ };
23
+ /** `GET …/guides/:guideId/checks`: the cached states, nothing runs. */
24
+ export const SetupChecksQuery = z.object(GuideSelection).strict();
25
+ /**
26
+ * `POST …/guides/:guideId/checks/:checkId/run`: runs the check unless a fresh cached result exists;
27
+ * `force` reruns it (at most once per 10 seconds per check and target).
28
+ */
29
+ export const SetupCheckRunBody = z
30
+ .object({ ...GuideSelection, force: z.boolean().optional() })
31
+ .strict();
32
+ export const SETUP_CHECK_ROUTES = [
33
+ {
34
+ route: "GET /api/v1/orgs/:orgId/catalog/:itemId/guides/:guideId/checks",
35
+ params: SetupGuidePathParams,
36
+ query: SetupChecksQuery,
37
+ },
38
+ {
39
+ route: "POST /api/v1/orgs/:orgId/catalog/:itemId/guides/:guideId/checks/:checkId/run",
40
+ params: SetupCheckPathParams,
41
+ body: SetupCheckRunBody,
42
+ },
43
+ ];
@@ -0,0 +1,144 @@
1
+ import type { Redis } from "ioredis";
2
+ import { ChannelConnections } from "../channels/connections.service.js";
3
+ import type { Keyring } from "../ctx/secrets.js";
4
+ import { EffectiveConfigs } from "../extensions/effective-config.js";
5
+ import { OrgExtensionConfigs } from "../extensions/org-config.js";
6
+ import { PluginGuides } from "../extensions/plugin-guides.js";
7
+ import { ExtensionRegistry } from "../extensions/registry.js";
8
+ import { KernelDb } from "../infra/database/kernel-db.js";
9
+ import { LockService } from "../infra/lock/lock.service.js";
10
+ import type { KernelLogger } from "../log.js";
11
+ import type { OrgRole } from "../orgs/roles.js";
12
+ import { Credentials } from "../tools/credentials.js";
13
+ import { SetupCheckRegistry, type SetupCheckState } from "./setup-check-registry.js";
14
+ /** Optional provider: the per-run time limit (ms) instead of `SETUP_CHECK_LIMITS.timeoutMs` (tests). */
15
+ export declare const SETUP_CHECK_TIMEOUT: unique symbol;
16
+ /** Who asks: the org, their role in it and their account. */
17
+ export interface CheckCaller {
18
+ orgId: string;
19
+ role: OrgRole;
20
+ accountId: string;
21
+ }
22
+ /** The guide the checks belong to: mode, audience and target, as the guide route takes them. */
23
+ export interface CheckSelection {
24
+ mode?: string | undefined;
25
+ audience?: "admin" | "member" | undefined;
26
+ connectionId?: string | undefined;
27
+ connectorId?: string | undefined;
28
+ }
29
+ /**
30
+ * Setup checks (spec 2026-11-09-setup-guides-v2-design.md §10): reads the cached state of a
31
+ * guide's checks and runs one on request. Authorization is the guide route's (catalog visibility,
32
+ * then the place and audience action, then the target, all through `PluginGuides.render`) before
33
+ * any target is loaded; the check must be in the guide rendered for that mode and audience.
34
+ *
35
+ * Multi-replica (§10.7): results, cooldowns, the single-flight lock and the org's concurrency
36
+ * semaphore live in Redis, every key with a TTL, none touched inside a transaction; nothing is in
37
+ * process memory. A run takes `capk:setup-check-run:<key>` (`LockService.lease`, 15 s, longer than
38
+ * the 10 s time limit) and a slot of `capk:setup-check-org:<orgId>` (8, self-expiring), and frees
39
+ * both on every path. Runs are limited per account (`capk:setup-check-rate:<accountId>`, 30 a
40
+ * minute, 429 `rate_limited`) here, so the HTTP route and the `Platform` tool share one budget.
41
+ * A check runs on the replica that took the lock, in the extension loaded
42
+ * there, raced against `AbortSignal.any([timeout, ctx.signal])` so one that ignores its signal
43
+ * still answers `unknown` at the limit (its late settle is dropped).
44
+ *
45
+ * Results never leak secrets (§10.8): a result is validated, redacted by every secret value the
46
+ * kernel knows for the target and the extension's config (the plugin's own, the connector's
47
+ * stored credentials it never got, the platform and the org's effective deployment config) and
48
+ * validated again; only that output is cached and returned. A throw, a timeout or an invalid
49
+ * result is `unknown` with a kernel reason; only the redacted problem or error message is logged.
50
+ */
51
+ export declare class SetupChecksService {
52
+ private readonly db;
53
+ private readonly redis;
54
+ private readonly locks;
55
+ private readonly keyring;
56
+ private readonly guides;
57
+ private readonly registry;
58
+ private readonly extensions;
59
+ private readonly effective;
60
+ private readonly orgConfigs;
61
+ private readonly channels;
62
+ private readonly credentials;
63
+ private readonly log;
64
+ private readonly timeoutMs;
65
+ constructor(db: KernelDb, redis: Pick<Redis, "get" | "set" | "pttl" | "mget" | "exists" | "eval">, locks: Pick<LockService, "lease" | "releaseIf" | "takeSlot" | "releaseSlot">, keyring: Keyring, guides: Pick<PluginGuides, "render">, registry: SetupCheckRegistry, extensions: Pick<ExtensionRegistry, "current">, effective: Pick<EffectiveConfigs, "get">, orgConfigs: Pick<OrgExtensionConfigs, "get">, channels: Pick<ChannelConnections, "checkRevision" | "checkSecrets" | "runtime">, credentials: Pick<Credentials, "checkRevision" | "checkMaterial">, log: Pick<KernelLogger, "warn">, timeoutMs?: number);
66
+ /**
67
+ * The cached state of every check of the rendered guide (`GET …/checks`), by check id; nothing
68
+ * runs. `not_run` without a fresh result for the current input fingerprint; `running` while a
69
+ * run holds the lock. Redis down: every row `unknown` ("temporarily unavailable").
70
+ */
71
+ states(caller: CheckCaller, itemId: string, guideId: string, q: CheckSelection): Promise<Record<string, SetupCheckState>>;
72
+ /**
73
+ * Runs one check (`POST …/checks/:checkId/run`) unless a fresh result for the current input
74
+ * fingerprint is cached (or `force`, refused within 10 s of the last run: the cached state with
75
+ * `cooldownUntil`). Another run in progress (any replica) or the org's 8 concurrent runs taken:
76
+ * `running`. Kernel reasons (`unknown`) when the check cannot run here.
77
+ */
78
+ run(caller: CheckCaller, itemId: string, guideId: string, checkId: string, body: CheckSelection & {
79
+ force?: boolean | undefined;
80
+ }): Promise<SetupCheckState>;
81
+ /**
82
+ * Authorization and the guide (the guide route's rules, `PluginGuides.render`: catalog
83
+ * visibility, then the place and audience action, then the target), then the check's presence
84
+ * in the guide rendered for that mode and audience (404 `catalog.check_not_found`), then the
85
+ * target (400: checks need a saved connection or connector).
86
+ */
87
+ private prepare;
88
+ /**
89
+ * A plugin check runs only where its extension runs on this replica, is enabled in the org and
90
+ * has a valid effective config there (nothing is called otherwise): the effective config, or the
91
+ * kernel's answer.
92
+ */
93
+ private pluginGate;
94
+ /** The Redis keys of a check of the prepared target (spec §10.7). */
95
+ private keys;
96
+ /**
97
+ * The input revision of a prepared target (spec §10.4): the target's and its credentials'
98
+ * `updated_at`, the org's extension config and copy revisions; never a value.
99
+ */
100
+ private revision;
101
+ private channelRevision;
102
+ private connectorRevision;
103
+ /**
104
+ * The input fingerprint (spec §10.4): an HMAC with a key derived from the kernel's master key
105
+ * over revisions only (the target and credentials revision, the org config revisions, the
106
+ * plugin version, the loaded extension version and the mode), never a value, so it cannot be
107
+ * reversed to a secret.
108
+ */
109
+ private fingerprint;
110
+ /**
111
+ * After the lock is taken: the cache read again. A fresh result written since the first read
112
+ * (another run settled in between) is answered as is, with its cooldown when this was a forced
113
+ * run; null when this run must call the check.
114
+ */
115
+ private settledWhileLocking;
116
+ /** Counts one run of the account in its window; false at the limit (nothing counted). */
117
+ private allowRun;
118
+ /** Writes a result (TTL 5 min) and the force cooldown (10 s), outside any transaction. */
119
+ private store;
120
+ /**
121
+ * Loads the target (built field by field), runs the check against the time limit and turns what
122
+ * it answers into a validated, redacted, re-validated result. Never throws for anything the
123
+ * check does: a throw, a timeout or an invalid result is an `unknown` result.
124
+ */
125
+ private execute;
126
+ /**
127
+ * The target material: for a channel connection its revision and stored secret values (and, for
128
+ * a plugin check, the connection config decrypted exactly as `channel@1` verify gets it); for a
129
+ * connector its credentials' values (redaction only), the manual OAuth client id and the
130
+ * template id. A `result` when the material cannot be read (the check is not called).
131
+ */
132
+ private material;
133
+ /** The secret values of the extension's platform and effective deployment config. */
134
+ private configSecrets;
135
+ /**
136
+ * The secret values of the extension's org-level config (`config.org`) in the org: the check
137
+ * never gets them, but the extension holds them, so a result is redacted by them too. Nothing
138
+ * when the plugin has no org config; a read that fails throws (the check is not run: a result
139
+ * is never redacted by fewer secrets than the extension holds).
140
+ */
141
+ private orgConfigSecrets;
142
+ /** The frozen arguments of a plugin check (the target built field by field). */
143
+ private pluginArgs;
144
+ }