@cat-factory/contracts 0.6.0

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 (166) hide show
  1. package/LICENSE +21 -0
  2. package/dist/accounts.d.ts +103 -0
  3. package/dist/accounts.d.ts.map +1 -0
  4. package/dist/accounts.js +102 -0
  5. package/dist/accounts.js.map +1 -0
  6. package/dist/agent-config.d.ts +77 -0
  7. package/dist/agent-config.d.ts.map +1 -0
  8. package/dist/agent-config.js +78 -0
  9. package/dist/agent-config.js.map +1 -0
  10. package/dist/api-keys.d.ts +44 -0
  11. package/dist/api-keys.d.ts.map +1 -0
  12. package/dist/api-keys.js +49 -0
  13. package/dist/api-keys.js.map +1 -0
  14. package/dist/auth.d.ts +24 -0
  15. package/dist/auth.d.ts.map +1 -0
  16. package/dist/auth.js +15 -0
  17. package/dist/auth.js.map +1 -0
  18. package/dist/board-scan.d.ts +89 -0
  19. package/dist/board-scan.d.ts.map +1 -0
  20. package/dist/board-scan.js +122 -0
  21. package/dist/board-scan.js.map +1 -0
  22. package/dist/bootstrap.d.ts +168 -0
  23. package/dist/bootstrap.d.ts.map +1 -0
  24. package/dist/bootstrap.js +148 -0
  25. package/dist/bootstrap.js.map +1 -0
  26. package/dist/clarity.d.ts +75 -0
  27. package/dist/clarity.d.ts.map +1 -0
  28. package/dist/clarity.js +66 -0
  29. package/dist/clarity.js.map +1 -0
  30. package/dist/companion.d.ts +32 -0
  31. package/dist/companion.d.ts.map +1 -0
  32. package/dist/companion.js +43 -0
  33. package/dist/companion.js.map +1 -0
  34. package/dist/consensus.d.ts +195 -0
  35. package/dist/consensus.d.ts.map +1 -0
  36. package/dist/consensus.js +164 -0
  37. package/dist/consensus.js.map +1 -0
  38. package/dist/documents.d.ts +197 -0
  39. package/dist/documents.d.ts.map +1 -0
  40. package/dist/documents.js +161 -0
  41. package/dist/documents.js.map +1 -0
  42. package/dist/entities.d.ts +1691 -0
  43. package/dist/entities.d.ts.map +1 -0
  44. package/dist/entities.js +853 -0
  45. package/dist/entities.js.map +1 -0
  46. package/dist/environments.d.ts +426 -0
  47. package/dist/environments.d.ts.map +1 -0
  48. package/dist/environments.js +190 -0
  49. package/dist/environments.js.map +1 -0
  50. package/dist/events.d.ts +98 -0
  51. package/dist/events.d.ts.map +1 -0
  52. package/dist/events.js +2 -0
  53. package/dist/events.js.map +1 -0
  54. package/dist/fragment-library.d.ts +123 -0
  55. package/dist/fragment-library.d.ts.map +1 -0
  56. package/dist/fragment-library.js +88 -0
  57. package/dist/fragment-library.js.map +1 -0
  58. package/dist/github.d.ts +215 -0
  59. package/dist/github.d.ts.map +1 -0
  60. package/dist/github.js +204 -0
  61. package/dist/github.js.map +1 -0
  62. package/dist/index.d.ts +41 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +41 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/iteration-cap.d.ts +17 -0
  67. package/dist/iteration-cap.d.ts.map +1 -0
  68. package/dist/iteration-cap.js +25 -0
  69. package/dist/iteration-cap.js.map +1 -0
  70. package/dist/localModels.d.ts +54 -0
  71. package/dist/localModels.d.ts.map +1 -0
  72. package/dist/localModels.js +79 -0
  73. package/dist/localModels.js.map +1 -0
  74. package/dist/merge.d.ts +106 -0
  75. package/dist/merge.d.ts.map +1 -0
  76. package/dist/merge.js +129 -0
  77. package/dist/merge.js.map +1 -0
  78. package/dist/model-defaults.d.ts +23 -0
  79. package/dist/model-defaults.d.ts.map +1 -0
  80. package/dist/model-defaults.js +34 -0
  81. package/dist/model-defaults.js.map +1 -0
  82. package/dist/notifications.d.ts +136 -0
  83. package/dist/notifications.d.ts.map +1 -0
  84. package/dist/notifications.js +125 -0
  85. package/dist/notifications.js.map +1 -0
  86. package/dist/observability.d.ts +271 -0
  87. package/dist/observability.d.ts.map +1 -0
  88. package/dist/observability.js +152 -0
  89. package/dist/observability.js.map +1 -0
  90. package/dist/personal-subscriptions.d.ts +66 -0
  91. package/dist/personal-subscriptions.d.ts.map +1 -0
  92. package/dist/personal-subscriptions.js +70 -0
  93. package/dist/personal-subscriptions.js.map +1 -0
  94. package/dist/primitives.d.ts +57 -0
  95. package/dist/primitives.d.ts.map +1 -0
  96. package/dist/primitives.js +66 -0
  97. package/dist/primitives.js.map +1 -0
  98. package/dist/provisioning.d.ts +46 -0
  99. package/dist/provisioning.d.ts.map +1 -0
  100. package/dist/provisioning.js +107 -0
  101. package/dist/provisioning.js.map +1 -0
  102. package/dist/recurring.d.ts +117 -0
  103. package/dist/recurring.d.ts.map +1 -0
  104. package/dist/recurring.js +99 -0
  105. package/dist/recurring.js.map +1 -0
  106. package/dist/release.d.ts +60 -0
  107. package/dist/release.d.ts.map +1 -0
  108. package/dist/release.js +75 -0
  109. package/dist/release.js.map +1 -0
  110. package/dist/requests.d.ts +451 -0
  111. package/dist/requests.d.ts.map +1 -0
  112. package/dist/requests.js +231 -0
  113. package/dist/requests.js.map +1 -0
  114. package/dist/requirements.d.ts +127 -0
  115. package/dist/requirements.d.ts.map +1 -0
  116. package/dist/requirements.js +137 -0
  117. package/dist/requirements.js.map +1 -0
  118. package/dist/runners.d.ts +387 -0
  119. package/dist/runners.d.ts.map +1 -0
  120. package/dist/runners.js +117 -0
  121. package/dist/runners.js.map +1 -0
  122. package/dist/sandbox.d.ts +300 -0
  123. package/dist/sandbox.d.ts.map +1 -0
  124. package/dist/sandbox.js +243 -0
  125. package/dist/sandbox.js.map +1 -0
  126. package/dist/service-fragment-defaults.d.ts +16 -0
  127. package/dist/service-fragment-defaults.d.ts.map +1 -0
  128. package/dist/service-fragment-defaults.js +23 -0
  129. package/dist/service-fragment-defaults.js.map +1 -0
  130. package/dist/services.d.ts +81 -0
  131. package/dist/services.d.ts.map +1 -0
  132. package/dist/services.js +77 -0
  133. package/dist/services.js.map +1 -0
  134. package/dist/slack.d.ts +104 -0
  135. package/dist/slack.d.ts.map +1 -0
  136. package/dist/slack.js +98 -0
  137. package/dist/slack.js.map +1 -0
  138. package/dist/snapshot.d.ts +522 -0
  139. package/dist/snapshot.d.ts.map +1 -0
  140. package/dist/snapshot.js +104 -0
  141. package/dist/snapshot.js.map +1 -0
  142. package/dist/spec.d.ts +174 -0
  143. package/dist/spec.d.ts.map +1 -0
  144. package/dist/spec.js +173 -0
  145. package/dist/spec.js.map +1 -0
  146. package/dist/tasks.d.ts +150 -0
  147. package/dist/tasks.d.ts.map +1 -0
  148. package/dist/tasks.js +146 -0
  149. package/dist/tasks.js.map +1 -0
  150. package/dist/testing.d.ts +67 -0
  151. package/dist/testing.d.ts.map +1 -0
  152. package/dist/testing.js +64 -0
  153. package/dist/testing.js.map +1 -0
  154. package/dist/tracker.d.ts +18 -0
  155. package/dist/tracker.d.ts.map +1 -0
  156. package/dist/tracker.js +24 -0
  157. package/dist/tracker.js.map +1 -0
  158. package/dist/vendor-credentials.d.ts +37 -0
  159. package/dist/vendor-credentials.d.ts.map +1 -0
  160. package/dist/vendor-credentials.js +40 -0
  161. package/dist/vendor-credentials.js.map +1 -0
  162. package/dist/workspace-settings.d.ts +36 -0
  163. package/dist/workspace-settings.d.ts.map +1 -0
  164. package/dist/workspace-settings.js +41 -0
  165. package/dist/workspace-settings.js.map +1 -0
  166. package/package.json +31 -0
@@ -0,0 +1,81 @@
1
+ import * as v from 'valibot';
2
+ /**
3
+ * The canonical, account-owned service record. Owns exactly one service frame
4
+ * block (`frameBlockId`) and, when connected, the GitHub repo the frame's tasks
5
+ * target (`installationId` + `repoGithubId`). Shared across the workspaces that
6
+ * mount it.
7
+ */
8
+ export declare const serviceSchema: v.ObjectSchema<{
9
+ /** Globally unique service id (stable; survives re-mounting). */
10
+ readonly id: v.StringSchema<undefined>;
11
+ /** The owning account (org/personal), or null for a legacy/unscoped board. */
12
+ readonly accountId: v.NullableSchema<v.StringSchema<undefined>, undefined>;
13
+ /** The root service-frame block this service owns (its subtree is the service). */
14
+ readonly frameBlockId: v.StringSchema<undefined>;
15
+ /** The GitHub App installation backing the linked repo, when connected. */
16
+ readonly installationId: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
17
+ /** The GitHub numeric id of the linked repo, when connected. */
18
+ readonly repoGithubId: v.NullableSchema<v.NumberSchema<undefined>, undefined>;
19
+ /**
20
+ * The subdirectory within the linked repo this service lives in, relative to the
21
+ * repo root (e.g. `packages/api`). Set only for services in a monorepo (a repo
22
+ * flagged {@link GitHubRepo.isMonorepo}); null means the service is the whole repo.
23
+ * When the repo is a monorepo this path is fed to every agent working on the
24
+ * service so it operates within (and is told about) the right subtree.
25
+ */
26
+ readonly directory: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
27
+ /** Epoch ms the service was created. */
28
+ readonly createdAt: v.NumberSchema<undefined>;
29
+ /**
30
+ * How many workspaces currently mount this service. Derived (not persisted); set only on
31
+ * the org catalog so the board can badge a frame mounted on >1 board as "Shared". Absent
32
+ * means "not computed".
33
+ */
34
+ readonly mountCount: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
35
+ }, undefined>;
36
+ export type Service = v.InferOutput<typeof serviceSchema>;
37
+ /**
38
+ * A *mount*: a service placed onto a workspace's board. The primary key is
39
+ * `(workspaceId, serviceId)`. The position/size are the per-workspace LAYOUT
40
+ * OVERRIDE for the service's frame — each board can position the shared frame
41
+ * independently, while the task/module positions inside it stay shared.
42
+ */
43
+ export declare const workspaceMountSchema: v.ObjectSchema<{
44
+ readonly workspaceId: v.StringSchema<undefined>;
45
+ readonly serviceId: v.StringSchema<undefined>;
46
+ /** Per-workspace board position of the service's frame. */
47
+ readonly position: v.ObjectSchema<{
48
+ readonly x: v.NumberSchema<undefined>;
49
+ readonly y: v.NumberSchema<undefined>;
50
+ }, undefined>;
51
+ /** Per-workspace dragged frame size; absent => auto-size from contents. */
52
+ readonly size: v.OptionalSchema<v.NullableSchema<v.ObjectSchema<{
53
+ readonly w: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, undefined>]>;
54
+ readonly h: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, undefined>]>;
55
+ }, undefined>, undefined>, undefined>;
56
+ /** Epoch ms the service was mounted onto this workspace. */
57
+ readonly createdAt: v.NumberSchema<undefined>;
58
+ }, undefined>;
59
+ export type WorkspaceMount = v.InferOutput<typeof workspaceMountSchema>;
60
+ /** Body for mounting an existing org service onto a workspace board. */
61
+ export declare const mountServiceInputSchema: v.ObjectSchema<{
62
+ /** Where to place the frame on this board; defaults applied server-side when absent. */
63
+ readonly position: v.OptionalSchema<v.ObjectSchema<{
64
+ readonly x: v.NumberSchema<undefined>;
65
+ readonly y: v.NumberSchema<undefined>;
66
+ }, undefined>, undefined>;
67
+ }, undefined>;
68
+ export type MountServiceInput = v.InferOutput<typeof mountServiceInputSchema>;
69
+ /** Body for updating a mount's per-workspace layout override. */
70
+ export declare const updateMountInputSchema: v.ObjectSchema<{
71
+ readonly position: v.OptionalSchema<v.ObjectSchema<{
72
+ readonly x: v.NumberSchema<undefined>;
73
+ readonly y: v.NumberSchema<undefined>;
74
+ }, undefined>, undefined>;
75
+ readonly size: v.OptionalSchema<v.NullableSchema<v.ObjectSchema<{
76
+ readonly w: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, undefined>]>;
77
+ readonly h: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.MinValueAction<number, 1, undefined>]>;
78
+ }, undefined>, undefined>, undefined>;
79
+ }, undefined>;
80
+ export type UpdateMountInput = v.InferOutput<typeof updateMountInputSchema>;
81
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAkB5B;;;;;GAKG;AACH,eAAO,MAAM,aAAa;IACxB,iEAAiE;;IAEjE,8EAA8E;;IAE9E,mFAAmF;;IAEnF,2EAA2E;;IAE3E,gEAAgE;;IAEhE;;;;;;OAMG;;IAEH,wCAAwC;;IAExC;;;;OAIG;;aAEH,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,aAAa,CAAC,CAAA;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;IAG/B,2DAA2D;;;;;IAE3D,2EAA2E;;;;;IAE3E,4DAA4D;;aAE5D,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEvE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB;IAClC,wFAAwF;;;;;aAExF,CAAA;AACF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAE7E,iEAAiE;AACjE,eAAO,MAAM,sBAAsB;;;;;;;;;aAGjC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,sBAAsB,CAAC,CAAA"}
@@ -0,0 +1,77 @@
1
+ import * as v from 'valibot';
2
+ import { positionSchema, sizeSchema } from './primitives.js';
3
+ // ---------------------------------------------------------------------------
4
+ // In-org shared services.
5
+ //
6
+ // A *service* is the canonical, account-owned unit of work on the board: the
7
+ // service frame plus its modules + tasks, its linked GitHub repo, its
8
+ // executions and its sync. It is owned by an *account* (org), not a single
9
+ // workspace. A *workspace* is a curated VIEW that *mounts* a subset of the
10
+ // org's services; the same service can be mounted onto several teams' boards,
11
+ // where its state and task list are one shared set (only the frame's board
12
+ // position/size is per-workspace, carried on the mount).
13
+ //
14
+ // This is the deduplication seam: a service is synced once per org, and a state
15
+ // change to it is relevant to every workspace that mounts it.
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * The canonical, account-owned service record. Owns exactly one service frame
19
+ * block (`frameBlockId`) and, when connected, the GitHub repo the frame's tasks
20
+ * target (`installationId` + `repoGithubId`). Shared across the workspaces that
21
+ * mount it.
22
+ */
23
+ export const serviceSchema = v.object({
24
+ /** Globally unique service id (stable; survives re-mounting). */
25
+ id: v.string(),
26
+ /** The owning account (org/personal), or null for a legacy/unscoped board. */
27
+ accountId: v.nullable(v.string()),
28
+ /** The root service-frame block this service owns (its subtree is the service). */
29
+ frameBlockId: v.string(),
30
+ /** The GitHub App installation backing the linked repo, when connected. */
31
+ installationId: v.nullable(v.number()),
32
+ /** The GitHub numeric id of the linked repo, when connected. */
33
+ repoGithubId: v.nullable(v.number()),
34
+ /**
35
+ * The subdirectory within the linked repo this service lives in, relative to the
36
+ * repo root (e.g. `packages/api`). Set only for services in a monorepo (a repo
37
+ * flagged {@link GitHubRepo.isMonorepo}); null means the service is the whole repo.
38
+ * When the repo is a monorepo this path is fed to every agent working on the
39
+ * service so it operates within (and is told about) the right subtree.
40
+ */
41
+ directory: v.optional(v.nullable(v.string())),
42
+ /** Epoch ms the service was created. */
43
+ createdAt: v.number(),
44
+ /**
45
+ * How many workspaces currently mount this service. Derived (not persisted); set only on
46
+ * the org catalog so the board can badge a frame mounted on >1 board as "Shared". Absent
47
+ * means "not computed".
48
+ */
49
+ mountCount: v.optional(v.number()),
50
+ });
51
+ /**
52
+ * A *mount*: a service placed onto a workspace's board. The primary key is
53
+ * `(workspaceId, serviceId)`. The position/size are the per-workspace LAYOUT
54
+ * OVERRIDE for the service's frame — each board can position the shared frame
55
+ * independently, while the task/module positions inside it stay shared.
56
+ */
57
+ export const workspaceMountSchema = v.object({
58
+ workspaceId: v.string(),
59
+ serviceId: v.string(),
60
+ /** Per-workspace board position of the service's frame. */
61
+ position: positionSchema,
62
+ /** Per-workspace dragged frame size; absent => auto-size from contents. */
63
+ size: v.optional(v.nullable(sizeSchema)),
64
+ /** Epoch ms the service was mounted onto this workspace. */
65
+ createdAt: v.number(),
66
+ });
67
+ /** Body for mounting an existing org service onto a workspace board. */
68
+ export const mountServiceInputSchema = v.object({
69
+ /** Where to place the frame on this board; defaults applied server-side when absent. */
70
+ position: v.optional(positionSchema),
71
+ });
72
+ /** Body for updating a mount's per-workspace layout override. */
73
+ export const updateMountInputSchema = v.object({
74
+ position: v.optional(positionSchema),
75
+ size: v.optional(v.nullable(sizeSchema)),
76
+ });
77
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5D,8EAA8E;AAC9E,0BAA0B;AAC1B,EAAE;AACF,6EAA6E;AAC7E,sEAAsE;AACtE,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,2EAA2E;AAC3E,yDAAyD;AACzD,EAAE;AACF,gFAAgF;AAChF,8DAA8D;AAC9D,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,iEAAiE;IACjE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,8EAA8E;IAC9E,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,mFAAmF;IACnF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,2EAA2E;IAC3E,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtC,gEAAgE;IAChE,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACpC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,wCAAwC;IACxC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB;;;;OAIG;IACH,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACnC,CAAC,CAAA;AAGF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,2DAA2D;IAC3D,QAAQ,EAAE,cAAc;IACxB,2EAA2E;IAC3E,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxC,4DAA4D;IAC5D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAA;AAGF,wEAAwE;AACxE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,wFAAwF;IACxF,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC;CACrC,CAAC,CAAA;AAGF,iEAAiE;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;CACzC,CAAC,CAAA"}
@@ -0,0 +1,104 @@
1
+ import * as v from 'valibot';
2
+ /**
3
+ * A account's Slack connection, as exposed to clients — safe metadata ONLY.
4
+ * The bot token is never part of this shape (it lives encrypted server-side).
5
+ */
6
+ export declare const slackConnectionSchema: v.ObjectSchema<{
7
+ /** The Slack team (workspace) id, e.g. `T012AB3C4`. */
8
+ readonly teamId: v.StringSchema<undefined>;
9
+ /** The Slack team display name. */
10
+ readonly teamName: v.StringSchema<undefined>;
11
+ /** Team icon URL, when Slack returned one. */
12
+ readonly teamIconUrl: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
13
+ /** The bot user id the app posts as (`auth.test` `user_id`), when known. */
14
+ readonly botUserId: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
15
+ /** OAuth scopes the bot token was granted, when known. */
16
+ readonly scopes: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
17
+ readonly connectedAt: v.NumberSchema<undefined>;
18
+ }, undefined>;
19
+ export type SlackConnection = v.InferOutput<typeof slackConnectionSchema>;
20
+ /** Routing for a single notification type: whether it posts, and where. */
21
+ export declare const slackRouteSchema: v.ObjectSchema<{
22
+ readonly enabled: v.BooleanSchema<undefined>;
23
+ /** A channel id (`C0123…`) or name (`#general`); empty = unrouted. */
24
+ readonly channel: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 200, undefined>]>;
25
+ }, undefined>;
26
+ export type SlackRoute = v.InferOutput<typeof slackRouteSchema>;
27
+ /**
28
+ * A workspace's Slack notification settings: a partial map of notification type
29
+ * → route, plus whether to resolve @-mentions from the account member mapping. A
30
+ * type absent from `routes`, disabled, or with an empty channel does not post.
31
+ */
32
+ export declare const slackNotificationSettingsSchema: v.ObjectSchema<{
33
+ readonly routes: v.RecordSchema<v.PicklistSchema<["merge_review", "pipeline_complete", "ci_failed", "test_failed", "requirement_review", "clarity_review", "release_regression", "decision_required"], undefined>, v.ObjectSchema<{
34
+ readonly enabled: v.BooleanSchema<undefined>;
35
+ /** A channel id (`C0123…`) or name (`#general`); empty = unrouted. */
36
+ readonly channel: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 200, undefined>]>;
37
+ }, undefined>, undefined>;
38
+ /** Resolve @-mentions from the per-account member mapping when posting. */
39
+ readonly mentionsEnabled: v.BooleanSchema<undefined>;
40
+ readonly updatedAt: v.NumberSchema<undefined>;
41
+ }, undefined>;
42
+ export type SlackNotificationSettings = v.InferOutput<typeof slackNotificationSettingsSchema>;
43
+ /**
44
+ * Which kinds of notification a mapped member cares about. `product` people are
45
+ * @-mentioned on requirement-review findings (and otherwise left alone); everyone
46
+ * else is `engineering` and is only @-mentioned when they are the task's creator.
47
+ * Absent on a legacy entry means `engineering` (see {@link resolveMemberRole}).
48
+ */
49
+ export declare const slackMemberRoleSchema: v.PicklistSchema<["product", "engineering"], undefined>;
50
+ export type SlackMemberRole = v.InferOutput<typeof slackMemberRoleSchema>;
51
+ /** One internal user id → Slack member id mapping entry, with the member's role. */
52
+ export declare const slackMemberMappingEntrySchema: v.ObjectSchema<{
53
+ readonly userId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
54
+ readonly slackUserId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 64, undefined>]>;
55
+ /** Notification role (default `engineering` when absent). */
56
+ readonly role: v.OptionalSchema<v.PicklistSchema<["product", "engineering"], undefined>, undefined>;
57
+ }, undefined>;
58
+ export type SlackMemberMappingEntry = v.InferOutput<typeof slackMemberMappingEntrySchema>;
59
+ /** An account's user→Slack member map (opt-in; backs @-mentions). */
60
+ export declare const slackMemberMappingSchema: v.ObjectSchema<{
61
+ readonly entries: v.ArraySchema<v.ObjectSchema<{
62
+ readonly userId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
63
+ readonly slackUserId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 64, undefined>]>;
64
+ /** Notification role (default `engineering` when absent). */
65
+ readonly role: v.OptionalSchema<v.PicklistSchema<["product", "engineering"], undefined>, undefined>;
66
+ }, undefined>, undefined>;
67
+ }, undefined>;
68
+ export type SlackMemberMapping = v.InferOutput<typeof slackMemberMappingSchema>;
69
+ /** A Slack channel option for the routing picker (`conversations.list`). */
70
+ export declare const slackChannelSchema: v.ObjectSchema<{
71
+ readonly id: v.StringSchema<undefined>;
72
+ readonly name: v.StringSchema<undefined>;
73
+ readonly isPrivate: v.BooleanSchema<undefined>;
74
+ }, undefined>;
75
+ export type SlackChannel = v.InferOutput<typeof slackChannelSchema>;
76
+ /**
77
+ * Connect Slack by pasting a bot token (the always-available fallback to OAuth).
78
+ * The token is write-only: validated via `auth.test`, encrypted, never returned.
79
+ */
80
+ export declare const connectSlackByTokenSchema: v.ObjectSchema<{
81
+ readonly token: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>]>;
82
+ }, undefined>;
83
+ export type ConnectSlackByTokenInput = v.InferOutput<typeof connectSlackByTokenSchema>;
84
+ /** Replace a workspace's Slack notification routing. */
85
+ export declare const updateSlackSettingsSchema: v.ObjectSchema<{
86
+ readonly routes: v.RecordSchema<v.PicklistSchema<["merge_review", "pipeline_complete", "ci_failed", "test_failed", "requirement_review", "clarity_review", "release_regression", "decision_required"], undefined>, v.ObjectSchema<{
87
+ readonly enabled: v.BooleanSchema<undefined>;
88
+ /** A channel id (`C0123…`) or name (`#general`); empty = unrouted. */
89
+ readonly channel: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MaxLengthAction<string, 200, undefined>]>;
90
+ }, undefined>, undefined>;
91
+ readonly mentionsEnabled: v.BooleanSchema<undefined>;
92
+ }, undefined>;
93
+ export type UpdateSlackSettingsInput = v.InferOutput<typeof updateSlackSettingsSchema>;
94
+ /** Replace an account's GitHub→Slack member mapping. */
95
+ export declare const updateSlackMemberMappingSchema: v.ObjectSchema<{
96
+ readonly entries: v.ArraySchema<v.ObjectSchema<{
97
+ readonly userId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
98
+ readonly slackUserId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TrimAction, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 64, undefined>]>;
99
+ /** Notification role (default `engineering` when absent). */
100
+ readonly role: v.OptionalSchema<v.PicklistSchema<["product", "engineering"], undefined>, undefined>;
101
+ }, undefined>, undefined>;
102
+ }, undefined>;
103
+ export type UpdateSlackMemberMappingInput = v.InferOutput<typeof updateSlackMemberMappingSchema>;
104
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAwB5B;;;GAGG;AACH,eAAO,MAAM,qBAAqB;IAChC,uDAAuD;;IAEvD,mCAAmC;;IAEnC,8CAA8C;;IAE9C,4EAA4E;;IAE5E,0DAA0D;;;aAG1D,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEzE,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB;;IAE3B,sEAAsE;;aAEtE,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,+BAA+B;;;QAV1C,sEAAsE;;;IAYtE,2EAA2E;;;aAG3E,CAAA;AACF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,+BAA+B,CAAC,CAAA;AAE7F;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,yDAAyC,CAAA;AAC3E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEzE,oFAAoF;AACpF,eAAO,MAAM,6BAA6B;;;IAGxC,6DAA6D;;aAE7D,CAAA;AACF,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,6BAA6B,CAAC,CAAA;AAEzF,qEAAqE;AACrE,eAAO,MAAM,wBAAwB;;;;QANnC,6DAA6D;;;aAQ7D,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAA;AAE/E,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB;;;;aAI7B,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAInE;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;aAEpC,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAEtF,wDAAwD;AACxD,eAAO,MAAM,yBAAyB;;;QA9DpC,sEAAsE;;;;aAiEtE,CAAA;AACF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAEtF,wDAAwD;AACxD,eAAO,MAAM,8BAA8B;;;;QAtCzC,6DAA6D;;;aAwC7D,CAAA;AACF,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAA"}
package/dist/slack.js ADDED
@@ -0,0 +1,98 @@
1
+ import * as v from 'valibot';
2
+ import { notificationTypeSchema } from './notifications.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Slack integration wire contracts.
5
+ //
6
+ // Slack is an additional *delivery transport* for the existing notification
7
+ // mechanism (merge_review / pipeline_complete / ci_failed) — not a parallel
8
+ // system. A `SlackNotificationChannel` implements the same `NotificationChannel`
9
+ // port the in-app channel does, composed in via `CompositeNotificationChannel`,
10
+ // so the call sites that raise notifications are untouched.
11
+ //
12
+ // Two scopes, mirroring the GitHub-App precedent:
13
+ // - The Slack *connection* (a workspace/team install + its bot token) is
14
+ // bound PER-ACCOUNT — an org installs the Slack app once. The bot token is
15
+ // multi-tenant data, so it is encrypted at rest (WebCryptoSecretCipher,
16
+ // `cat-factory:slack`) and NEVER returned on the wire; only safe metadata
17
+ // (team name/icon, bot user, scopes) is exposed.
18
+ // - Notification *routing* (which types post, and to which channel) is
19
+ // configured PER-WORKSPACE.
20
+ // - Optional @-mentions resolve from an opt-in per-account map of GitHub user
21
+ // id → Slack member id (cat-factory has no member emails to look up).
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * A account's Slack connection, as exposed to clients — safe metadata ONLY.
25
+ * The bot token is never part of this shape (it lives encrypted server-side).
26
+ */
27
+ export const slackConnectionSchema = v.object({
28
+ /** The Slack team (workspace) id, e.g. `T012AB3C4`. */
29
+ teamId: v.string(),
30
+ /** The Slack team display name. */
31
+ teamName: v.string(),
32
+ /** Team icon URL, when Slack returned one. */
33
+ teamIconUrl: v.optional(v.nullable(v.string())),
34
+ /** The bot user id the app posts as (`auth.test` `user_id`), when known. */
35
+ botUserId: v.optional(v.nullable(v.string())),
36
+ /** OAuth scopes the bot token was granted, when known. */
37
+ scopes: v.optional(v.array(v.string())),
38
+ connectedAt: v.number(),
39
+ });
40
+ /** Routing for a single notification type: whether it posts, and where. */
41
+ export const slackRouteSchema = v.object({
42
+ enabled: v.boolean(),
43
+ /** A channel id (`C0123…`) or name (`#general`); empty = unrouted. */
44
+ channel: v.pipe(v.string(), v.trim(), v.maxLength(200)),
45
+ });
46
+ /**
47
+ * A workspace's Slack notification settings: a partial map of notification type
48
+ * → route, plus whether to resolve @-mentions from the account member mapping. A
49
+ * type absent from `routes`, disabled, or with an empty channel does not post.
50
+ */
51
+ export const slackNotificationSettingsSchema = v.object({
52
+ routes: v.record(notificationTypeSchema, slackRouteSchema),
53
+ /** Resolve @-mentions from the per-account member mapping when posting. */
54
+ mentionsEnabled: v.boolean(),
55
+ updatedAt: v.number(),
56
+ });
57
+ /**
58
+ * Which kinds of notification a mapped member cares about. `product` people are
59
+ * @-mentioned on requirement-review findings (and otherwise left alone); everyone
60
+ * else is `engineering` and is only @-mentioned when they are the task's creator.
61
+ * Absent on a legacy entry means `engineering` (see {@link resolveMemberRole}).
62
+ */
63
+ export const slackMemberRoleSchema = v.picklist(['product', 'engineering']);
64
+ /** One internal user id → Slack member id mapping entry, with the member's role. */
65
+ export const slackMemberMappingEntrySchema = v.object({
66
+ userId: v.pipe(v.string(), v.minLength(1)),
67
+ slackUserId: v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(64)),
68
+ /** Notification role (default `engineering` when absent). */
69
+ role: v.optional(slackMemberRoleSchema),
70
+ });
71
+ /** An account's user→Slack member map (opt-in; backs @-mentions). */
72
+ export const slackMemberMappingSchema = v.object({
73
+ entries: v.array(slackMemberMappingEntrySchema),
74
+ });
75
+ /** A Slack channel option for the routing picker (`conversations.list`). */
76
+ export const slackChannelSchema = v.object({
77
+ id: v.string(),
78
+ name: v.string(),
79
+ isPrivate: v.boolean(),
80
+ });
81
+ // ---- Request bodies -------------------------------------------------------
82
+ /**
83
+ * Connect Slack by pasting a bot token (the always-available fallback to OAuth).
84
+ * The token is write-only: validated via `auth.test`, encrypted, never returned.
85
+ */
86
+ export const connectSlackByTokenSchema = v.object({
87
+ token: v.pipe(v.string(), v.trim(), v.minLength(1)),
88
+ });
89
+ /** Replace a workspace's Slack notification routing. */
90
+ export const updateSlackSettingsSchema = v.object({
91
+ routes: v.record(notificationTypeSchema, slackRouteSchema),
92
+ mentionsEnabled: v.boolean(),
93
+ });
94
+ /** Replace an account's GitHub→Slack member mapping. */
95
+ export const updateSlackMemberMappingSchema = v.object({
96
+ entries: v.array(slackMemberMappingEntrySchema),
97
+ });
98
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../src/slack.ts"],"names":[],"mappings":"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"}