@mastra/factory 0.0.0 → 0.1.0-alpha.3

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 (287) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE.md +30 -0
  3. package/dist/auth.d.ts +181 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +370 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/capabilities/connection.d.ts +9 -0
  8. package/dist/capabilities/connection.d.ts.map +1 -0
  9. package/dist/capabilities/connection.js +1 -0
  10. package/dist/capabilities/connection.js.map +1 -0
  11. package/dist/capabilities/intake.d.ts +93 -0
  12. package/dist/capabilities/intake.d.ts.map +1 -0
  13. package/dist/capabilities/intake.js +1 -0
  14. package/dist/capabilities/intake.js.map +1 -0
  15. package/dist/capabilities/version-control.d.ts +239 -0
  16. package/dist/capabilities/version-control.d.ts.map +1 -0
  17. package/dist/capabilities/version-control.js +1 -0
  18. package/dist/capabilities/version-control.js.map +1 -0
  19. package/dist/factory.d.ts +145 -0
  20. package/dist/factory.d.ts.map +1 -0
  21. package/dist/factory.js +38245 -0
  22. package/dist/factory.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +38245 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/integrations/base.d.ts +197 -0
  28. package/dist/integrations/base.d.ts.map +1 -0
  29. package/dist/integrations/base.js +1 -0
  30. package/dist/integrations/base.js.map +1 -0
  31. package/dist/integrations/github/config.d.ts +60 -0
  32. package/dist/integrations/github/config.d.ts.map +1 -0
  33. package/dist/integrations/github/config.js +28 -0
  34. package/dist/integrations/github/config.js.map +1 -0
  35. package/dist/integrations/github/factory-session.d.ts +12 -0
  36. package/dist/integrations/github/factory-session.d.ts.map +1 -0
  37. package/dist/integrations/github/factory-session.js +41 -0
  38. package/dist/integrations/github/factory-session.js.map +1 -0
  39. package/dist/integrations/github/integration.d.ts +191 -0
  40. package/dist/integrations/github/integration.d.ts.map +1 -0
  41. package/dist/integrations/github/integration.js +3001 -0
  42. package/dist/integrations/github/integration.js.map +1 -0
  43. package/dist/integrations/github/issue-triage.d.ts +27 -0
  44. package/dist/integrations/github/issue-triage.d.ts.map +1 -0
  45. package/dist/integrations/github/issue-triage.js +82 -0
  46. package/dist/integrations/github/issue-triage.js.map +1 -0
  47. package/dist/integrations/github/project-lock.d.ts +78 -0
  48. package/dist/integrations/github/project-lock.d.ts.map +1 -0
  49. package/dist/integrations/github/project-lock.js +70 -0
  50. package/dist/integrations/github/project-lock.js.map +1 -0
  51. package/dist/integrations/github/provenance.d.ts +27 -0
  52. package/dist/integrations/github/provenance.d.ts.map +1 -0
  53. package/dist/integrations/github/provenance.js +104 -0
  54. package/dist/integrations/github/provenance.js.map +1 -0
  55. package/dist/integrations/github/routes.d.ts +72 -0
  56. package/dist/integrations/github/routes.d.ts.map +1 -0
  57. package/dist/integrations/github/routes.js +1834 -0
  58. package/dist/integrations/github/routes.js.map +1 -0
  59. package/dist/integrations/github/sandbox.d.ts +268 -0
  60. package/dist/integrations/github/sandbox.d.ts.map +1 -0
  61. package/dist/integrations/github/sandbox.js +381 -0
  62. package/dist/integrations/github/sandbox.js.map +1 -0
  63. package/dist/integrations/github/session-subscriptions.d.ts +23 -0
  64. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -0
  65. package/dist/integrations/github/session-subscriptions.js +190 -0
  66. package/dist/integrations/github/session-subscriptions.js.map +1 -0
  67. package/dist/integrations/github/subscriptions.d.ts +54 -0
  68. package/dist/integrations/github/subscriptions.d.ts.map +1 -0
  69. package/dist/integrations/github/subscriptions.js +70 -0
  70. package/dist/integrations/github/subscriptions.js.map +1 -0
  71. package/dist/integrations/github/webhook.d.ts +87 -0
  72. package/dist/integrations/github/webhook.d.ts.map +1 -0
  73. package/dist/integrations/github/webhook.js +381 -0
  74. package/dist/integrations/github/webhook.js.map +1 -0
  75. package/dist/integrations/linear/agent-tools.d.ts +34 -0
  76. package/dist/integrations/linear/agent-tools.d.ts.map +1 -0
  77. package/dist/integrations/linear/agent-tools.js +108 -0
  78. package/dist/integrations/linear/agent-tools.js.map +1 -0
  79. package/dist/integrations/linear/integration.d.ts +233 -0
  80. package/dist/integrations/linear/integration.d.ts.map +1 -0
  81. package/dist/integrations/linear/integration.js +962 -0
  82. package/dist/integrations/linear/integration.js.map +1 -0
  83. package/dist/integrations/linear/routes.d.ts +61 -0
  84. package/dist/integrations/linear/routes.d.ts.map +1 -0
  85. package/dist/integrations/linear/routes.js +242 -0
  86. package/dist/integrations/linear/routes.js.map +1 -0
  87. package/dist/integrations/linear/storage.d.ts +65 -0
  88. package/dist/integrations/linear/storage.d.ts.map +1 -0
  89. package/dist/integrations/linear/storage.js +1 -0
  90. package/dist/integrations/linear/storage.js.map +1 -0
  91. package/dist/integrations/platform/api-client.d.ts +24 -0
  92. package/dist/integrations/platform/api-client.d.ts.map +1 -0
  93. package/dist/integrations/platform/api-client.js +153 -0
  94. package/dist/integrations/platform/api-client.js.map +1 -0
  95. package/dist/integrations/platform/github/event-worker.d.ts +44 -0
  96. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -0
  97. package/dist/integrations/platform/github/event-worker.js +585 -0
  98. package/dist/integrations/platform/github/event-worker.js.map +1 -0
  99. package/dist/integrations/platform/github/integration.d.ts +36 -0
  100. package/dist/integrations/platform/github/integration.d.ts.map +1 -0
  101. package/dist/integrations/platform/github/integration.js +3253 -0
  102. package/dist/integrations/platform/github/integration.js.map +1 -0
  103. package/dist/integrations/platform/linear/integration.d.ts +46 -0
  104. package/dist/integrations/platform/linear/integration.d.ts.map +1 -0
  105. package/dist/integrations/platform/linear/integration.js +891 -0
  106. package/dist/integrations/platform/linear/integration.js.map +1 -0
  107. package/dist/integrations/workos/integration.d.ts +39 -0
  108. package/dist/integrations/workos/integration.d.ts.map +1 -0
  109. package/dist/integrations/workos/integration.js +96 -0
  110. package/dist/integrations/workos/integration.js.map +1 -0
  111. package/dist/routes/config.d.ts +220 -0
  112. package/dist/routes/config.d.ts.map +1 -0
  113. package/dist/routes/config.js +770 -0
  114. package/dist/routes/config.js.map +1 -0
  115. package/dist/routes/fs.d.ts +105 -0
  116. package/dist/routes/fs.d.ts.map +1 -0
  117. package/dist/routes/fs.js +294 -0
  118. package/dist/routes/fs.js.map +1 -0
  119. package/dist/routes/intake.d.ts +23 -0
  120. package/dist/routes/intake.d.ts.map +1 -0
  121. package/dist/routes/intake.js +179 -0
  122. package/dist/routes/intake.js.map +1 -0
  123. package/dist/routes/oauth.d.ts +43 -0
  124. package/dist/routes/oauth.d.ts.map +1 -0
  125. package/dist/routes/oauth.js +25058 -0
  126. package/dist/routes/oauth.js.map +1 -0
  127. package/dist/routes/projects.d.ts +19 -0
  128. package/dist/routes/projects.d.ts.map +1 -0
  129. package/dist/routes/projects.js +395 -0
  130. package/dist/routes/projects.js.map +1 -0
  131. package/dist/routes/provider-credentials.d.ts +81 -0
  132. package/dist/routes/provider-credentials.d.ts.map +1 -0
  133. package/dist/routes/provider-credentials.js +68 -0
  134. package/dist/routes/provider-credentials.js.map +1 -0
  135. package/dist/routes/route.d.ts +48 -0
  136. package/dist/routes/route.d.ts.map +1 -0
  137. package/dist/routes/route.js +11 -0
  138. package/dist/routes/route.js.map +1 -0
  139. package/dist/routes/skills.d.ts +30 -0
  140. package/dist/routes/skills.d.ts.map +1 -0
  141. package/dist/routes/skills.js +181 -0
  142. package/dist/routes/skills.js.map +1 -0
  143. package/dist/routes/surface.d.ts +83 -0
  144. package/dist/routes/surface.d.ts.map +1 -0
  145. package/dist/routes/surface.js +28519 -0
  146. package/dist/routes/surface.js.map +1 -0
  147. package/dist/routes/tenant-credentials.d.ts +74 -0
  148. package/dist/routes/tenant-credentials.d.ts.map +1 -0
  149. package/dist/routes/tenant-credentials.js +181 -0
  150. package/dist/routes/tenant-credentials.js.map +1 -0
  151. package/dist/routes/work-items.d.ts +40 -0
  152. package/dist/routes/work-items.d.ts.map +1 -0
  153. package/dist/routes/work-items.js +902 -0
  154. package/dist/routes/work-items.js.map +1 -0
  155. package/dist/rules/binding-context.d.ts +5 -0
  156. package/dist/rules/binding-context.d.ts.map +1 -0
  157. package/dist/rules/binding-context.js +40 -0
  158. package/dist/rules/binding-context.js.map +1 -0
  159. package/dist/rules/defaults.d.ts +9 -0
  160. package/dist/rules/defaults.d.ts.map +1 -0
  161. package/dist/rules/defaults.js +334 -0
  162. package/dist/rules/defaults.js.map +1 -0
  163. package/dist/rules/dispatcher.d.ts +40 -0
  164. package/dist/rules/dispatcher.d.ts.map +1 -0
  165. package/dist/rules/dispatcher.js +695 -0
  166. package/dist/rules/dispatcher.js.map +1 -0
  167. package/dist/rules/github-service.d.ts +29 -0
  168. package/dist/rules/github-service.d.ts.map +1 -0
  169. package/dist/rules/github-service.js +474 -0
  170. package/dist/rules/github-service.js.map +1 -0
  171. package/dist/rules/index.d.ts +7 -0
  172. package/dist/rules/index.d.ts.map +1 -0
  173. package/dist/rules/index.js +583 -0
  174. package/dist/rules/index.js.map +1 -0
  175. package/dist/rules/linear-service.d.ts +27 -0
  176. package/dist/rules/linear-service.d.ts.map +1 -0
  177. package/dist/rules/linear-service.js +343 -0
  178. package/dist/rules/linear-service.js.map +1 -0
  179. package/dist/rules/processor.d.ts +54 -0
  180. package/dist/rules/processor.d.ts.map +1 -0
  181. package/dist/rules/processor.js +629 -0
  182. package/dist/rules/processor.js.map +1 -0
  183. package/dist/rules/resolve.d.ts +17 -0
  184. package/dist/rules/resolve.d.ts.map +1 -0
  185. package/dist/rules/resolve.js +27 -0
  186. package/dist/rules/resolve.js.map +1 -0
  187. package/dist/rules/start-coordinator.d.ts +58 -0
  188. package/dist/rules/start-coordinator.d.ts.map +1 -0
  189. package/dist/rules/start-coordinator.js +136 -0
  190. package/dist/rules/start-coordinator.js.map +1 -0
  191. package/dist/rules/tools.d.ts +10 -0
  192. package/dist/rules/tools.d.ts.map +1 -0
  193. package/dist/rules/tools.js +93 -0
  194. package/dist/rules/tools.js.map +1 -0
  195. package/dist/rules/transition-service.d.ts +32 -0
  196. package/dist/rules/transition-service.d.ts.map +1 -0
  197. package/dist/rules/transition-service.js +474 -0
  198. package/dist/rules/transition-service.js.map +1 -0
  199. package/dist/rules/types.d.ts +225 -0
  200. package/dist/rules/types.d.ts.map +1 -0
  201. package/dist/rules/types.js +33 -0
  202. package/dist/rules/types.js.map +1 -0
  203. package/dist/rules/validation.d.ts +11 -0
  204. package/dist/rules/validation.d.ts.map +1 -0
  205. package/dist/rules/validation.js +310 -0
  206. package/dist/rules/validation.js.map +1 -0
  207. package/dist/sandbox/fleet.d.ts +208 -0
  208. package/dist/sandbox/fleet.d.ts.map +1 -0
  209. package/dist/sandbox/fleet.js +259 -0
  210. package/dist/sandbox/fleet.js.map +1 -0
  211. package/dist/sandbox/reattach.d.ts +3 -0
  212. package/dist/sandbox/reattach.d.ts.map +1 -0
  213. package/dist/sandbox/reattach.js +9 -0
  214. package/dist/sandbox/reattach.js.map +1 -0
  215. package/dist/server-error.d.ts +12 -0
  216. package/dist/server-error.d.ts.map +1 -0
  217. package/dist/server-error.js +20 -0
  218. package/dist/server-error.js.map +1 -0
  219. package/dist/skills/service.d.ts +48 -0
  220. package/dist/skills/service.d.ts.map +1 -0
  221. package/dist/skills/service.js +45 -0
  222. package/dist/skills/service.js.map +1 -0
  223. package/dist/spa-static.d.ts +34 -0
  224. package/dist/spa-static.d.ts.map +1 -0
  225. package/dist/spa-static.js +73 -0
  226. package/dist/spa-static.js.map +1 -0
  227. package/dist/state-signing.d.ts +48 -0
  228. package/dist/state-signing.d.ts.map +1 -0
  229. package/dist/state-signing.js +48 -0
  230. package/dist/state-signing.js.map +1 -0
  231. package/dist/storage/domains/audit/agent-audit.d.ts +27 -0
  232. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -0
  233. package/dist/storage/domains/audit/agent-audit.js +65 -0
  234. package/dist/storage/domains/audit/agent-audit.js.map +1 -0
  235. package/dist/storage/domains/audit/base.d.ts +140 -0
  236. package/dist/storage/domains/audit/base.d.ts.map +1 -0
  237. package/dist/storage/domains/audit/base.js +127 -0
  238. package/dist/storage/domains/audit/base.js.map +1 -0
  239. package/dist/storage/domains/audit/domain.d.ts +69 -0
  240. package/dist/storage/domains/audit/domain.d.ts.map +1 -0
  241. package/dist/storage/domains/audit/domain.js +165 -0
  242. package/dist/storage/domains/audit/domain.js.map +1 -0
  243. package/dist/storage/domains/credentials/base.d.ts +134 -0
  244. package/dist/storage/domains/credentials/base.d.ts.map +1 -0
  245. package/dist/storage/domains/credentials/base.js +257 -0
  246. package/dist/storage/domains/credentials/base.js.map +1 -0
  247. package/dist/storage/domains/intake/base.d.ts +38 -0
  248. package/dist/storage/domains/intake/base.d.ts.map +1 -0
  249. package/dist/storage/domains/intake/base.js +62 -0
  250. package/dist/storage/domains/intake/base.js.map +1 -0
  251. package/dist/storage/domains/integrations/base.d.ts +126 -0
  252. package/dist/storage/domains/integrations/base.d.ts.map +1 -0
  253. package/dist/storage/domains/integrations/base.js +252 -0
  254. package/dist/storage/domains/integrations/base.js.map +1 -0
  255. package/dist/storage/domains/model-packs/base.d.ts +49 -0
  256. package/dist/storage/domains/model-packs/base.d.ts.map +1 -0
  257. package/dist/storage/domains/model-packs/base.js +95 -0
  258. package/dist/storage/domains/model-packs/base.js.map +1 -0
  259. package/dist/storage/domains/projects/base.d.ts +55 -0
  260. package/dist/storage/domains/projects/base.d.ts.map +1 -0
  261. package/dist/storage/domains/projects/base.js +99 -0
  262. package/dist/storage/domains/projects/base.js.map +1 -0
  263. package/dist/storage/domains/queue-health/base.d.ts +52 -0
  264. package/dist/storage/domains/queue-health/base.d.ts.map +1 -0
  265. package/dist/storage/domains/queue-health/base.js +87 -0
  266. package/dist/storage/domains/queue-health/base.js.map +1 -0
  267. package/dist/storage/domains/source-control/base.d.ts +288 -0
  268. package/dist/storage/domains/source-control/base.d.ts.map +1 -0
  269. package/dist/storage/domains/source-control/base.js +722 -0
  270. package/dist/storage/domains/source-control/base.js.map +1 -0
  271. package/dist/storage/domains/source-control/inmemory.d.ts +158 -0
  272. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -0
  273. package/dist/storage/domains/source-control/inmemory.js +348 -0
  274. package/dist/storage/domains/source-control/inmemory.js.map +1 -0
  275. package/dist/storage/domains/work-items/base.d.ts +412 -0
  276. package/dist/storage/domains/work-items/base.d.ts.map +1 -0
  277. package/dist/storage/domains/work-items/base.js +1174 -0
  278. package/dist/storage/domains/work-items/base.js.map +1 -0
  279. package/dist/storage/domains/work-items/metrics.d.ts +101 -0
  280. package/dist/storage/domains/work-items/metrics.d.ts.map +1 -0
  281. package/dist/storage/domains/work-items/metrics.js +203 -0
  282. package/dist/storage/domains/work-items/metrics.js.map +1 -0
  283. package/dist/workspace.d.ts +20 -0
  284. package/dist/workspace.d.ts.map +1 -0
  285. package/dist/workspace.js +364 -0
  286. package/dist/workspace.js.map +1 -0
  287. package/package.json +19 -19
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared OAuth/install `state` signing for web integrations.
3
+ *
4
+ * Both the GitHub and Linear OAuth flows round-trip a signed `state` value
5
+ * through the third party to bind the callback to the `(orgId, userId)` tenant
6
+ * that initiated it (CSRF protection + tenant routing). The signer is a system
7
+ * facility: `MastraFactory` creates ONE signer at boot and hands it to every
8
+ * registered integration through `IntegrationContext` (see
9
+ * `./factory-integration.ts`), so all integrations sign and verify with the
10
+ * same secret.
11
+ *
12
+ * Secret resolution happens in the factory, not here: explicit
13
+ * `config.stateSecret` → the GitHub integration's webhook secret → a
14
+ * per-process random secret. A random secret is NOT stable across replicas —
15
+ * a `state` signed by one replica cannot be verified by another — which is
16
+ * what the `stable` flag reports. The factory fails loud at boot when a
17
+ * registered integration requires a stable signer but only a random one is
18
+ * available.
19
+ *
20
+ * The wire format (base64url JSON payload + `.` + HMAC-SHA256 base64url
21
+ * signature) is unchanged from the previous `github/config.ts` implementation
22
+ * so in-flight OAuth states survive a deploy.
23
+ */
24
+ /** Verified `(orgId, userId)` tenant carried by a signed `state`. */
25
+ export interface StateTenant {
26
+ orgId: string;
27
+ userId: string;
28
+ }
29
+ /** Signs and verifies OAuth `state` values bound to a `(orgId, userId)` tenant. */
30
+ export interface StateSigner {
31
+ /** Build a signed `state` bound to the tenant. */
32
+ sign(orgId: string, userId: string): string;
33
+ /** Verify a signed `state`; returns the bound tenant, or `null` if invalid. */
34
+ verify(state: string | undefined): StateTenant | null;
35
+ /**
36
+ * True when the signer was built from an explicit deployment-stable secret.
37
+ * False means a per-process random secret: fine for single-process/local
38
+ * dev, broken for multi-replica deploys (see module docs).
39
+ */
40
+ readonly stable: boolean;
41
+ }
42
+ /**
43
+ * Create a state signer. With a `secret`, the signer is deployment-stable
44
+ * (`stable: true`); without one it falls back to a per-process random secret
45
+ * (`stable: false`).
46
+ */
47
+ export declare function createStateSigner(secret?: string): StateSigner;
48
+ //# sourceMappingURL=state-signing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-signing.d.ts","sourceRoot":"","sources":["../src/state-signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C,+EAA+E;IAC/E,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAAC;IACtD;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAYD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAwC9D"}
@@ -0,0 +1,48 @@
1
+ // src/state-signing.ts
2
+ import { createHmac, randomBytes, timingSafeEqual } from "crypto";
3
+ var STATE_MAX_AGE_MS = 10 * 60 * 1e3;
4
+ function createStateSigner(secret) {
5
+ const stable = typeof secret === "string" && secret.length > 0;
6
+ const key = stable ? secret : randomBytes(32).toString("hex");
7
+ return {
8
+ stable,
9
+ sign(orgId, userId) {
10
+ const payload = {
11
+ orgId,
12
+ userId,
13
+ nonce: randomBytes(8).toString("hex"),
14
+ issuedAt: Date.now()
15
+ };
16
+ const body = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
17
+ const sig = createHmac("sha256", key).update(body).digest("base64url");
18
+ return `${body}.${sig}`;
19
+ },
20
+ verify(state) {
21
+ if (!state) return null;
22
+ const dot = state.lastIndexOf(".");
23
+ if (dot <= 0) return null;
24
+ const body = state.slice(0, dot);
25
+ const sig = state.slice(dot + 1);
26
+ const expected = createHmac("sha256", key).update(body).digest("base64url");
27
+ const sigBuf = Buffer.from(sig);
28
+ const expectedBuf = Buffer.from(expected);
29
+ if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {
30
+ return null;
31
+ }
32
+ try {
33
+ const parsed = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
34
+ if (typeof parsed.orgId !== "string" || typeof parsed.userId !== "string") return null;
35
+ if (typeof parsed.issuedAt !== "number" || !Number.isFinite(parsed.issuedAt)) return null;
36
+ const age = Date.now() - parsed.issuedAt;
37
+ if (age < 0 || age > STATE_MAX_AGE_MS) return null;
38
+ return { orgId: parsed.orgId, userId: parsed.userId };
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+ };
44
+ }
45
+ export {
46
+ createStateSigner
47
+ };
48
+ //# sourceMappingURL=state-signing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/state-signing.ts"],"sourcesContent":["/**\n * Shared OAuth/install `state` signing for web integrations.\n *\n * Both the GitHub and Linear OAuth flows round-trip a signed `state` value\n * through the third party to bind the callback to the `(orgId, userId)` tenant\n * that initiated it (CSRF protection + tenant routing). The signer is a system\n * facility: `MastraFactory` creates ONE signer at boot and hands it to every\n * registered integration through `IntegrationContext` (see\n * `./factory-integration.ts`), so all integrations sign and verify with the\n * same secret.\n *\n * Secret resolution happens in the factory, not here: explicit\n * `config.stateSecret` → the GitHub integration's webhook secret → a\n * per-process random secret. A random secret is NOT stable across replicas —\n * a `state` signed by one replica cannot be verified by another — which is\n * what the `stable` flag reports. The factory fails loud at boot when a\n * registered integration requires a stable signer but only a random one is\n * available.\n *\n * The wire format (base64url JSON payload + `.` + HMAC-SHA256 base64url\n * signature) is unchanged from the previous `github/config.ts` implementation\n * so in-flight OAuth states survive a deploy.\n */\n\nimport { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\n\n/** Verified `(orgId, userId)` tenant carried by a signed `state`. */\nexport interface StateTenant {\n orgId: string;\n userId: string;\n}\n\n/** Signs and verifies OAuth `state` values bound to a `(orgId, userId)` tenant. */\nexport interface StateSigner {\n /** Build a signed `state` bound to the tenant. */\n sign(orgId: string, userId: string): string;\n /** Verify a signed `state`; returns the bound tenant, or `null` if invalid. */\n verify(state: string | undefined): StateTenant | null;\n /**\n * True when the signer was built from an explicit deployment-stable secret.\n * False means a per-process random secret: fine for single-process/local\n * dev, broken for multi-replica deploys (see module docs).\n */\n readonly stable: boolean;\n}\n\ninterface StatePayload {\n orgId: string;\n userId: string;\n nonce: string;\n issuedAt: number;\n}\n\n/** Signed `state` values expire after this window to bound the CSRF token. */\nconst STATE_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * Create a state signer. With a `secret`, the signer is deployment-stable\n * (`stable: true`); without one it falls back to a per-process random secret\n * (`stable: false`).\n */\nexport function createStateSigner(secret?: string): StateSigner {\n const stable = typeof secret === 'string' && secret.length > 0;\n const key = stable ? secret : randomBytes(32).toString('hex');\n return {\n stable,\n sign(orgId: string, userId: string): string {\n const payload: StatePayload = {\n orgId,\n userId,\n nonce: randomBytes(8).toString('hex'),\n issuedAt: Date.now(),\n };\n const body = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');\n const sig = createHmac('sha256', key).update(body).digest('base64url');\n return `${body}.${sig}`;\n },\n verify(state: string | undefined): StateTenant | null {\n if (!state) return null;\n const dot = state.lastIndexOf('.');\n if (dot <= 0) return null;\n const body = state.slice(0, dot);\n const sig = state.slice(dot + 1);\n const expected = createHmac('sha256', key).update(body).digest('base64url');\n const sigBuf = Buffer.from(sig);\n const expectedBuf = Buffer.from(expected);\n if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {\n return null;\n }\n try {\n const parsed = JSON.parse(Buffer.from(body, 'base64url').toString('utf8')) as StatePayload;\n if (typeof parsed.orgId !== 'string' || typeof parsed.userId !== 'string') return null;\n if (typeof parsed.issuedAt !== 'number' || !Number.isFinite(parsed.issuedAt)) return null;\n const age = Date.now() - parsed.issuedAt;\n if (age < 0 || age > STATE_MAX_AGE_MS) return null;\n return { orgId: parsed.orgId, userId: parsed.userId };\n } catch {\n return null;\n }\n },\n };\n}\n"],"mappings":";AAwBA,SAAS,YAAY,aAAa,uBAAuB;AA8BzD,IAAM,mBAAmB,KAAK,KAAK;AAO5B,SAAS,kBAAkB,QAA8B;AAC9D,QAAM,SAAS,OAAO,WAAW,YAAY,OAAO,SAAS;AAC7D,QAAM,MAAM,SAAS,SAAS,YAAY,EAAE,EAAE,SAAS,KAAK;AAC5D,SAAO;AAAA,IACL;AAAA,IACA,KAAK,OAAe,QAAwB;AAC1C,YAAM,UAAwB;AAAA,QAC5B;AAAA,QACA;AAAA,QACA,OAAO,YAAY,CAAC,EAAE,SAAS,KAAK;AAAA,QACpC,UAAU,KAAK,IAAI;AAAA,MACrB;AACA,YAAM,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,GAAG,MAAM,EAAE,SAAS,WAAW;AAC9E,YAAM,MAAM,WAAW,UAAU,GAAG,EAAE,OAAO,IAAI,EAAE,OAAO,WAAW;AACrE,aAAO,GAAG,IAAI,IAAI,GAAG;AAAA,IACvB;AAAA,IACA,OAAO,OAA+C;AACpD,UAAI,CAAC,MAAO,QAAO;AACnB,YAAM,MAAM,MAAM,YAAY,GAAG;AACjC,UAAI,OAAO,EAAG,QAAO;AACrB,YAAM,OAAO,MAAM,MAAM,GAAG,GAAG;AAC/B,YAAM,MAAM,MAAM,MAAM,MAAM,CAAC;AAC/B,YAAM,WAAW,WAAW,UAAU,GAAG,EAAE,OAAO,IAAI,EAAE,OAAO,WAAW;AAC1E,YAAM,SAAS,OAAO,KAAK,GAAG;AAC9B,YAAM,cAAc,OAAO,KAAK,QAAQ;AACxC,UAAI,OAAO,WAAW,YAAY,UAAU,CAAC,gBAAgB,QAAQ,WAAW,GAAG;AACjF,eAAO;AAAA,MACT;AACA,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,WAAW,EAAE,SAAS,MAAM,CAAC;AACzE,YAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,WAAW,SAAU,QAAO;AAClF,YAAI,OAAO,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,OAAO,QAAQ,EAAG,QAAO;AACrF,cAAM,MAAM,KAAK,IAAI,IAAI,OAAO;AAChC,YAAI,MAAM,KAAK,MAAM,iBAAkB,QAAO;AAC9C,eAAO,EAAE,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;AAAA,MACtD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Agent-level audit event detection (Audit v1.1).
3
+ *
4
+ * Git actions performed by agents inside runs never touch web routes, so this
5
+ * observer detects externally-visible git side effects and delegates recording
6
+ * to the factory-owned audit domain.
7
+ */
8
+ import type { RequestContext } from '@mastra/core/request-context';
9
+ import type { AuditAgentEmitter } from './domain.js';
10
+ interface ToolObserverContext {
11
+ toolName: string;
12
+ input: unknown;
13
+ output?: unknown;
14
+ error?: unknown;
15
+ context: RequestContext;
16
+ }
17
+ /**
18
+ * Detect externally-visible git side effects in a completed tool call and
19
+ * record `factory.agent.*` audit events for them. One command can emit
20
+ * multiple events (`git commit && git push` emits both). Never throws.
21
+ */
22
+ export declare function observeAgentGitAction({ audit, toolContext, }: {
23
+ audit: AuditAgentEmitter;
24
+ toolContext: ToolObserverContext;
25
+ }): Promise<void>;
26
+ export {};
27
+ //# sourceMappingURL=agent-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-audit.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/agent-audit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;CACzB;AAgCD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,KAAK,EACL,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,WAAW,EAAE,mBAAmB,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqChB"}
@@ -0,0 +1,65 @@
1
+ // src/storage/domains/audit/agent-audit.ts
2
+ var GIT_COMMIT_RE = /(?:^|\n|;|&&|\|\|)\s*git\s+commit(?:\s|$)/;
3
+ var GIT_PUSH_RE = /(?:^|\n|;|&&|\|\|)\s*git\s+push(?:\s|$)/;
4
+ function stripHeredocBodies(command) {
5
+ const lines = command.split("\n");
6
+ const executableLines = [];
7
+ let delimiter;
8
+ for (const line of lines) {
9
+ if (delimiter) {
10
+ if (line.trim() === delimiter) delimiter = void 0;
11
+ continue;
12
+ }
13
+ executableLines.push(line);
14
+ const heredoc = line.match(/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/);
15
+ delimiter = heredoc?.[2];
16
+ }
17
+ return executableLines.join("\n");
18
+ }
19
+ function parsePushedBranch(command) {
20
+ const match = command.match(
21
+ /(?:^|\n|;|&&|\|\|)\s*git\s+push\s+(?:-[^\s]+\s+)*([^\s;&|-][^\s;&|]*)\s+([^\s;&|-][^\s;&|]*)/
22
+ );
23
+ return match?.[2];
24
+ }
25
+ async function observeAgentGitAction({
26
+ audit,
27
+ toolContext
28
+ }) {
29
+ try {
30
+ if (toolContext.toolName !== "execute_command" || toolContext.error) return;
31
+ const rawCommand = toolContext.input?.command;
32
+ if (typeof rawCommand !== "string") return;
33
+ const command = stripHeredocBodies(rawCommand);
34
+ const controller = toolContext.context.get("controller");
35
+ const worktreePath = controller?.scope;
36
+ if (GIT_COMMIT_RE.test(command)) {
37
+ await audit.emitAgent({
38
+ requestContext: toolContext.context,
39
+ input: {
40
+ action: "factory.agent.commit",
41
+ targets: worktreePath ? [{ type: "worktree", id: worktreePath }] : []
42
+ }
43
+ });
44
+ }
45
+ if (GIT_PUSH_RE.test(command)) {
46
+ const branch = parsePushedBranch(command);
47
+ await audit.emitAgent({
48
+ requestContext: toolContext.context,
49
+ input: {
50
+ action: "factory.agent.push",
51
+ targets: worktreePath ? [{ type: "worktree", id: worktreePath }] : [],
52
+ ...branch ? { metadata: { branch } } : {}
53
+ }
54
+ });
55
+ }
56
+ } catch (err) {
57
+ console.warn("[Audit] Failed to observe agent git action", {
58
+ error: err instanceof Error ? err.message : String(err)
59
+ });
60
+ }
61
+ }
62
+ export {
63
+ observeAgentGitAction
64
+ };
65
+ //# sourceMappingURL=agent-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/storage/domains/audit/agent-audit.ts"],"sourcesContent":["/**\n * Agent-level audit event detection (Audit v1.1).\n *\n * Git actions performed by agents inside runs never touch web routes, so this\n * observer detects externally-visible git side effects and delegates recording\n * to the factory-owned audit domain.\n */\n\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\n\nimport type { AuditAgentEmitter } from './domain.js';\n\ntype FactorySessionState = { factoryProjectId?: string; projectRepositoryId?: string };\n\ninterface ToolObserverContext {\n toolName: string;\n input: unknown;\n output?: unknown;\n error?: unknown;\n context: RequestContext;\n}\n\n/** Match command-start positions while ignoring command text embedded in heredoc bodies. */\nconst GIT_COMMIT_RE = /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+commit(?:\\s|$)/;\nconst GIT_PUSH_RE = /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+push(?:\\s|$)/;\n\nfunction stripHeredocBodies(command: string): string {\n const lines = command.split('\\n');\n const executableLines: string[] = [];\n let delimiter: string | undefined;\n\n for (const line of lines) {\n if (delimiter) {\n if (line.trim() === delimiter) delimiter = undefined;\n continue;\n }\n executableLines.push(line);\n const heredoc = line.match(/<<-?\\s*(['\"]?)([A-Za-z_][A-Za-z0-9_]*)\\1/);\n delimiter = heredoc?.[2];\n }\n\n return executableLines.join('\\n');\n}\n\n/** Parse the branch from a plain `git push <remote> <branch>` invocation. */\nfunction parsePushedBranch(command: string): string | undefined {\n const match = command.match(\n /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+push\\s+(?:-[^\\s]+\\s+)*([^\\s;&|-][^\\s;&|]*)\\s+([^\\s;&|-][^\\s;&|]*)/,\n );\n return match?.[2];\n}\n\n/**\n * Detect externally-visible git side effects in a completed tool call and\n * record `factory.agent.*` audit events for them. One command can emit\n * multiple events (`git commit && git push` emits both). Never throws.\n */\nexport async function observeAgentGitAction({\n audit,\n toolContext,\n}: {\n audit: AuditAgentEmitter;\n toolContext: ToolObserverContext;\n}): Promise<void> {\n try {\n if (toolContext.toolName !== 'execute_command' || toolContext.error) return;\n const rawCommand = (toolContext.input as { command?: unknown } | undefined)?.command;\n if (typeof rawCommand !== 'string') return;\n const command = stripHeredocBodies(rawCommand);\n\n const controller = toolContext.context.get('controller') as\n AgentControllerRequestContext<FactorySessionState> | undefined;\n const worktreePath = controller?.scope;\n\n if (GIT_COMMIT_RE.test(command)) {\n await audit.emitAgent({\n requestContext: toolContext.context,\n input: {\n action: 'factory.agent.commit',\n targets: worktreePath ? [{ type: 'worktree', id: worktreePath }] : [],\n },\n });\n }\n\n if (GIT_PUSH_RE.test(command)) {\n const branch = parsePushedBranch(command);\n await audit.emitAgent({\n requestContext: toolContext.context,\n input: {\n action: 'factory.agent.push',\n targets: worktreePath ? [{ type: 'worktree', id: worktreePath }] : [],\n ...(branch ? { metadata: { branch } } : {}),\n },\n });\n }\n } catch (err) {\n console.warn('[Audit] Failed to observe agent git action', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n"],"mappings":";AAwBA,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEpB,SAAS,mBAAmB,SAAyB;AACnD,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,kBAA4B,CAAC;AACnC,MAAI;AAEJ,aAAW,QAAQ,OAAO;AACxB,QAAI,WAAW;AACb,UAAI,KAAK,KAAK,MAAM,UAAW,aAAY;AAC3C;AAAA,IACF;AACA,oBAAgB,KAAK,IAAI;AACzB,UAAM,UAAU,KAAK,MAAM,0CAA0C;AACrE,gBAAY,UAAU,CAAC;AAAA,EACzB;AAEA,SAAO,gBAAgB,KAAK,IAAI;AAClC;AAGA,SAAS,kBAAkB,SAAqC;AAC9D,QAAM,QAAQ,QAAQ;AAAA,IACpB;AAAA,EACF;AACA,SAAO,QAAQ,CAAC;AAClB;AAOA,eAAsB,sBAAsB;AAAA,EAC1C;AAAA,EACA;AACF,GAGkB;AAChB,MAAI;AACF,QAAI,YAAY,aAAa,qBAAqB,YAAY,MAAO;AACrE,UAAM,aAAc,YAAY,OAA6C;AAC7E,QAAI,OAAO,eAAe,SAAU;AACpC,UAAM,UAAU,mBAAmB,UAAU;AAE7C,UAAM,aAAa,YAAY,QAAQ,IAAI,YAAY;AAEvD,UAAM,eAAe,YAAY;AAEjC,QAAI,cAAc,KAAK,OAAO,GAAG;AAC/B,YAAM,MAAM,UAAU;AAAA,QACpB,gBAAgB,YAAY;AAAA,QAC5B,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS,eAAe,CAAC,EAAE,MAAM,YAAY,IAAI,aAAa,CAAC,IAAI,CAAC;AAAA,QACtE;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,YAAY,KAAK,OAAO,GAAG;AAC7B,YAAM,SAAS,kBAAkB,OAAO;AACxC,YAAM,MAAM,UAAU;AAAA,QACpB,gBAAgB,YAAY;AAAA,QAC5B,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS,eAAe,CAAC,EAAE,MAAM,YAAY,IAAI,aAAa,CAAC,IAAI,CAAC;AAAA,UACpE,GAAI,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,QAC3C;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,KAAK,8CAA8C;AAAA,MACzD,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Factory audit events domain — the append-only "who did what, when" trail
3
+ * behind the software factory.
4
+ *
5
+ * One `audit_events` row records a single audited mutation (work-item change,
6
+ * stage move, run start, worktree create/delete, git action, intake config
7
+ * change). Rows are append-only: there is no update/delete API, and the table
8
+ * is the local source of truth even when the WorkOS Audit Logs mirror is
9
+ * unavailable.
10
+ *
11
+ * Tenancy is **org-first**, like `work_items`: events are scoped by `org_id`
12
+ * and (usually) `factory_project_id`; `actor_id` records who acted but never
13
+ * scopes reads.
14
+ *
15
+ * v1 action taxonomy (register these in the WorkOS dashboard under
16
+ * Audit Logs → Events for the export mirror to accept them):
17
+ * - factory.work_item.created
18
+ * - factory.work_item.updated
19
+ * - factory.work_item.stage_moved
20
+ * - factory.work_item.deleted
21
+ * - factory.run.started
22
+ * - factory.worktree.created
23
+ * - factory.worktree.deleted
24
+ * - factory.triage.started
25
+ * - factory.git.commit
26
+ * - factory.git.push
27
+ * - factory.git.pr_opened
28
+ * - factory.intake.config_updated
29
+ *
30
+ * v1.1 adds agent-level actions (also register these in WorkOS):
31
+ * - factory.agent.commit
32
+ * - factory.agent.push
33
+ * - factory.agent.pr_opened
34
+ *
35
+ * Agent events carry `actor_type = 'agent'` with `actor_id = 'agent:<threadId>'`
36
+ * and `metadata.startedBy = <userId>` chaining accountability back to the human
37
+ * whose message drove the run.
38
+ */
39
+ import { FactoryStorageDomain } from '@mastra/core/storage';
40
+ import type { CollectionSchema } from '@mastra/core/storage';
41
+ /** What an audit event acted on (WorkOS Audit Logs target shape). */
42
+ export interface AuditTarget {
43
+ /** Target kind, e.g. 'work_item', 'worktree', 'issue', 'pull_request'. */
44
+ type: string;
45
+ /** Stable identifier of the target (row id, branch name, issue number...). */
46
+ id: string;
47
+ /** Human-readable label (work-item title, branch name...). */
48
+ name?: string;
49
+ }
50
+ /** Who performed the audited action. */
51
+ export type AuditActorType = 'human' | 'agent';
52
+ /** Request context captured alongside the event. */
53
+ export interface AuditContext {
54
+ /** Client IP (first hop of `x-forwarded-for`) when available. */
55
+ location?: string;
56
+ /** Request `user-agent` header when available. */
57
+ userAgent?: string;
58
+ }
59
+ /** One persisted audit event. */
60
+ export interface AuditEventRow {
61
+ id: string;
62
+ /** Owning WorkOS organization id — the trail is org-wide. */
63
+ orgId: string;
64
+ /** WorkOS user id of whoever performed the action, or `agent:<threadId>`. */
65
+ actorId: string;
66
+ /** Whether a human or an agent (inside a run) performed the action. */
67
+ actorType: AuditActorType;
68
+ /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */
69
+ action: string;
70
+ /** What was acted on. */
71
+ targets: AuditTarget[];
72
+ /** Bounded event summary — never full payloads, never secrets. */
73
+ metadata: Record<string, unknown>;
74
+ /** Factory project the event is scoped to; null for org-level events. */
75
+ factoryProjectId: string | null;
76
+ /** Project-repository link affected by a repository-specific action. */
77
+ projectRepositoryId: string | null;
78
+ /** Request context (`x-forwarded-for` / `user-agent`). */
79
+ context: AuditContext;
80
+ occurredAt: Date;
81
+ }
82
+ export interface RecordAuditEventInput {
83
+ orgId: string;
84
+ actorId: string;
85
+ /** Who performed the action; defaults to 'human'. */
86
+ actorType?: AuditActorType;
87
+ /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */
88
+ action: string;
89
+ targets: AuditTarget[];
90
+ metadata?: Record<string, unknown>;
91
+ factoryProjectId?: string;
92
+ projectRepositoryId?: string;
93
+ context?: AuditContext;
94
+ occurredAt?: Date;
95
+ }
96
+ /** A fully-normalized event ready to persist (id assigned on insert). */
97
+ export type AuditEventInsert = Omit<AuditEventRow, 'id'>;
98
+ export interface ListAuditEventsInput {
99
+ orgId: string;
100
+ factoryProjectId?: string;
101
+ /** Restrict to these actions (exact match). */
102
+ actions?: string[];
103
+ actorId?: string;
104
+ /** Opaque cursor from a previous page (`nextCursor`). */
105
+ before?: string;
106
+ limit?: number;
107
+ }
108
+ export interface AuditEventPage {
109
+ events: AuditEventRow[];
110
+ /** Pass back as `before` to fetch the next (older) page; absent at the end. */
111
+ nextCursor?: string;
112
+ }
113
+ /** Truncate oversized metadata rather than dropping the whole event. */
114
+ export declare function boundAuditMetadata(metadata: Record<string, unknown> | undefined): Record<string, unknown>;
115
+ /** Normalize a requested page size to a finite integer in `[1, MAX_PAGE_SIZE]`. */
116
+ export declare function clampAuditLimit(limit: number | undefined): number;
117
+ /** Encode the `(occurredAt, id)` keyset cursor of a row. */
118
+ export declare function encodeAuditCursor(row: AuditEventRow): string;
119
+ /** Decode a cursor back into its `(occurredAt, id)` parts, or `undefined`. */
120
+ export declare function decodeAuditCursor(cursor: string): {
121
+ occurredAt: Date;
122
+ id: string;
123
+ } | undefined;
124
+ export declare const AUDIT_EVENTS_SCHEMA: CollectionSchema;
125
+ /**
126
+ * Audit event storage, written once against the generic `FactoryStorageOps`
127
+ * surface. `record()` normalizes inputs (defaults, metadata bounding);
128
+ * `list()` is keyset-paginated on `(occurred_at, id)` newest-first.
129
+ */
130
+ export declare class AuditStorage extends FactoryStorageDomain {
131
+ #private;
132
+ constructor();
133
+ init(): Promise<void>;
134
+ dangerouslyClearAll(): Promise<void>;
135
+ /** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */
136
+ record(input: RecordAuditEventInput): Promise<AuditEventRow>;
137
+ /** List an org's audit events newest-first with keyset pagination. */
138
+ list(input: ListAuditEventsInput): Promise<AuditEventPage>;
139
+ }
140
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAsC,MAAM,sBAAsB,CAAC;AAEjG,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wCAAwC;AACxC,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/C,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,SAAS,EAAE,cAAc,CAAC;IAC1B,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,0DAA0D;IAC1D,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,UAAU,CAAC,EAAE,IAAI,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzG;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGjE;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAO9F;AAED,eAAO,MAAM,mBAAmB,EAAE,gBAmBjC,CAAC;AAiCF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,oBAAoB;;;IAK9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ1C,0FAA0F;IACpF,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC;IAgBlE,sEAAsE;IAChE,IAAI,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;CA2BjE"}
@@ -0,0 +1,127 @@
1
+ // src/storage/domains/audit/base.ts
2
+ import { FactoryStorageDomain } from "@mastra/core/storage";
3
+ var MAX_METADATA_JSON_LENGTH = 4096;
4
+ var DEFAULT_PAGE_SIZE = 50;
5
+ var MAX_PAGE_SIZE = 200;
6
+ function boundAuditMetadata(metadata) {
7
+ if (!metadata) return {};
8
+ try {
9
+ if (JSON.stringify(metadata).length <= MAX_METADATA_JSON_LENGTH) return metadata;
10
+ } catch {
11
+ return { truncated: true };
12
+ }
13
+ return { truncated: true };
14
+ }
15
+ function clampAuditLimit(limit) {
16
+ const normalized = typeof limit === "number" && Number.isFinite(limit) ? Math.trunc(limit) : DEFAULT_PAGE_SIZE;
17
+ return Math.min(Math.max(normalized, 1), MAX_PAGE_SIZE);
18
+ }
19
+ function encodeAuditCursor(row) {
20
+ return `${row.occurredAt.toISOString()}_${row.id}`;
21
+ }
22
+ function decodeAuditCursor(cursor) {
23
+ const sep = cursor.lastIndexOf("_");
24
+ if (sep <= 0) return void 0;
25
+ const occurredAt = new Date(cursor.slice(0, sep));
26
+ const id = cursor.slice(sep + 1);
27
+ if (Number.isNaN(occurredAt.getTime()) || !id) return void 0;
28
+ return { occurredAt, id };
29
+ }
30
+ var AUDIT_EVENTS_SCHEMA = {
31
+ name: "audit_events",
32
+ columns: {
33
+ id: { type: "uuid-pk" },
34
+ org_id: { type: "text" },
35
+ actor_id: { type: "text" },
36
+ actor_type: { type: "text", default: "human" },
37
+ action: { type: "text" },
38
+ targets: { type: "json" },
39
+ metadata: { type: "json" },
40
+ factory_project_id: { type: "text", nullable: true },
41
+ project_repository_id: { type: "text", nullable: true },
42
+ context: { type: "json" },
43
+ occurred_at: { type: "timestamp" }
44
+ },
45
+ indexes: [
46
+ { name: "audit_events_org_occurred_idx", columns: ["org_id", "occurred_at"] },
47
+ { name: "audit_events_org_project_occurred_idx", columns: ["org_id", "factory_project_id", "occurred_at"] }
48
+ ]
49
+ };
50
+ function toRow(db) {
51
+ return {
52
+ id: db.id,
53
+ orgId: db.org_id,
54
+ actorId: db.actor_id,
55
+ actorType: db.actor_type,
56
+ action: db.action,
57
+ targets: db.targets,
58
+ metadata: db.metadata,
59
+ factoryProjectId: db.factory_project_id,
60
+ projectRepositoryId: db.project_repository_id,
61
+ context: db.context,
62
+ occurredAt: db.occurred_at
63
+ };
64
+ }
65
+ var AuditStorage = class extends FactoryStorageDomain {
66
+ constructor() {
67
+ super("audit");
68
+ }
69
+ async init() {
70
+ await this.ensureCollections([AUDIT_EVENTS_SCHEMA]);
71
+ }
72
+ async dangerouslyClearAll() {
73
+ await this.ops.deleteMany("audit_events", {});
74
+ }
75
+ get #db() {
76
+ return this.ops;
77
+ }
78
+ /** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */
79
+ async record(input) {
80
+ const inserted = await this.#db.insertOne("audit_events", {
81
+ org_id: input.orgId,
82
+ actor_id: input.actorId,
83
+ actor_type: input.actorType ?? "human",
84
+ action: input.action,
85
+ targets: input.targets,
86
+ metadata: boundAuditMetadata(input.metadata),
87
+ factory_project_id: input.factoryProjectId ?? null,
88
+ project_repository_id: input.projectRepositoryId ?? null,
89
+ context: input.context ?? {},
90
+ occurred_at: input.occurredAt ?? /* @__PURE__ */ new Date()
91
+ });
92
+ return toRow(inserted);
93
+ }
94
+ /** List an org's audit events newest-first with keyset pagination. */
95
+ async list(input) {
96
+ const limit = clampAuditLimit(input.limit);
97
+ const where = { org_id: input.orgId };
98
+ if (input.factoryProjectId) where.factory_project_id = input.factoryProjectId;
99
+ if (input.actions && input.actions.length > 0) where.action = { in: input.actions };
100
+ if (input.actorId) where.actor_id = input.actorId;
101
+ const cursor = input.before ? decodeAuditCursor(input.before) : void 0;
102
+ const rows = await this.#db.findMany("audit_events", where, {
103
+ orderBy: [
104
+ ["occurred_at", "desc"],
105
+ ["id", "desc"]
106
+ ],
107
+ limit: limit + 1,
108
+ ...cursor ? { cursor: { values: [cursor.occurredAt, cursor.id] } } : {}
109
+ });
110
+ const events = rows.slice(0, limit).map(toRow);
111
+ const hasMore = rows.length > limit;
112
+ const last = events[events.length - 1];
113
+ return {
114
+ events,
115
+ ...hasMore && last ? { nextCursor: encodeAuditCursor(last) } : {}
116
+ };
117
+ }
118
+ };
119
+ export {
120
+ AUDIT_EVENTS_SCHEMA,
121
+ AuditStorage,
122
+ boundAuditMetadata,
123
+ clampAuditLimit,
124
+ decodeAuditCursor,
125
+ encodeAuditCursor
126
+ };
127
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/storage/domains/audit/base.ts"],"sourcesContent":["/**\n * Factory audit events domain — the append-only \"who did what, when\" trail\n * behind the software factory.\n *\n * One `audit_events` row records a single audited mutation (work-item change,\n * stage move, run start, worktree create/delete, git action, intake config\n * change). Rows are append-only: there is no update/delete API, and the table\n * is the local source of truth even when the WorkOS Audit Logs mirror is\n * unavailable.\n *\n * Tenancy is **org-first**, like `work_items`: events are scoped by `org_id`\n * and (usually) `factory_project_id`; `actor_id` records who acted but never\n * scopes reads.\n *\n * v1 action taxonomy (register these in the WorkOS dashboard under\n * Audit Logs → Events for the export mirror to accept them):\n * - factory.work_item.created\n * - factory.work_item.updated\n * - factory.work_item.stage_moved\n * - factory.work_item.deleted\n * - factory.run.started\n * - factory.worktree.created\n * - factory.worktree.deleted\n * - factory.triage.started\n * - factory.git.commit\n * - factory.git.push\n * - factory.git.pr_opened\n * - factory.intake.config_updated\n *\n * v1.1 adds agent-level actions (also register these in WorkOS):\n * - factory.agent.commit\n * - factory.agent.push\n * - factory.agent.pr_opened\n *\n * Agent events carry `actor_type = 'agent'` with `actor_id = 'agent:<threadId>'`\n * and `metadata.startedBy = <userId>` chaining accountability back to the human\n * whose message drove the run.\n */\n\nimport { FactoryStorageDomain } from '@mastra/core/storage';\nimport type { CollectionSchema, CollectionWhere, FactoryStorageOps } from '@mastra/core/storage';\n\n/** What an audit event acted on (WorkOS Audit Logs target shape). */\nexport interface AuditTarget {\n /** Target kind, e.g. 'work_item', 'worktree', 'issue', 'pull_request'. */\n type: string;\n /** Stable identifier of the target (row id, branch name, issue number...). */\n id: string;\n /** Human-readable label (work-item title, branch name...). */\n name?: string;\n}\n\n/** Who performed the audited action. */\nexport type AuditActorType = 'human' | 'agent';\n\n/** Request context captured alongside the event. */\nexport interface AuditContext {\n /** Client IP (first hop of `x-forwarded-for`) when available. */\n location?: string;\n /** Request `user-agent` header when available. */\n userAgent?: string;\n}\n\n/** One persisted audit event. */\nexport interface AuditEventRow {\n id: string;\n /** Owning WorkOS organization id — the trail is org-wide. */\n orgId: string;\n /** WorkOS user id of whoever performed the action, or `agent:<threadId>`. */\n actorId: string;\n /** Whether a human or an agent (inside a run) performed the action. */\n actorType: AuditActorType;\n /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */\n action: string;\n /** What was acted on. */\n targets: AuditTarget[];\n /** Bounded event summary — never full payloads, never secrets. */\n metadata: Record<string, unknown>;\n /** Factory project the event is scoped to; null for org-level events. */\n factoryProjectId: string | null;\n /** Project-repository link affected by a repository-specific action. */\n projectRepositoryId: string | null;\n /** Request context (`x-forwarded-for` / `user-agent`). */\n context: AuditContext;\n occurredAt: Date;\n}\n\nexport interface RecordAuditEventInput {\n orgId: string;\n actorId: string;\n /** Who performed the action; defaults to 'human'. */\n actorType?: AuditActorType;\n /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */\n action: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n factoryProjectId?: string;\n projectRepositoryId?: string;\n context?: AuditContext;\n occurredAt?: Date;\n}\n\n/** A fully-normalized event ready to persist (id assigned on insert). */\nexport type AuditEventInsert = Omit<AuditEventRow, 'id'>;\n\nexport interface ListAuditEventsInput {\n orgId: string;\n factoryProjectId?: string;\n /** Restrict to these actions (exact match). */\n actions?: string[];\n actorId?: string;\n /** Opaque cursor from a previous page (`nextCursor`). */\n before?: string;\n limit?: number;\n}\n\nexport interface AuditEventPage {\n events: AuditEventRow[];\n /** Pass back as `before` to fetch the next (older) page; absent at the end. */\n nextCursor?: string;\n}\n\n/** Metadata is a bounded summary — never full payloads, never secrets. */\nconst MAX_METADATA_JSON_LENGTH = 4096;\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst MAX_PAGE_SIZE = 200;\n\n/** Truncate oversized metadata rather than dropping the whole event. */\nexport function boundAuditMetadata(metadata: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!metadata) return {};\n try {\n if (JSON.stringify(metadata).length <= MAX_METADATA_JSON_LENGTH) return metadata;\n } catch {\n return { truncated: true };\n }\n return { truncated: true };\n}\n\n/** Normalize a requested page size to a finite integer in `[1, MAX_PAGE_SIZE]`. */\nexport function clampAuditLimit(limit: number | undefined): number {\n const normalized = typeof limit === 'number' && Number.isFinite(limit) ? Math.trunc(limit) : DEFAULT_PAGE_SIZE;\n return Math.min(Math.max(normalized, 1), MAX_PAGE_SIZE);\n}\n\n/** Encode the `(occurredAt, id)` keyset cursor of a row. */\nexport function encodeAuditCursor(row: AuditEventRow): string {\n return `${row.occurredAt.toISOString()}_${row.id}`;\n}\n\n/** Decode a cursor back into its `(occurredAt, id)` parts, or `undefined`. */\nexport function decodeAuditCursor(cursor: string): { occurredAt: Date; id: string } | undefined {\n const sep = cursor.lastIndexOf('_');\n if (sep <= 0) return undefined;\n const occurredAt = new Date(cursor.slice(0, sep));\n const id = cursor.slice(sep + 1);\n if (Number.isNaN(occurredAt.getTime()) || !id) return undefined;\n return { occurredAt, id };\n}\n\nexport const AUDIT_EVENTS_SCHEMA: CollectionSchema = {\n name: 'audit_events',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n actor_id: { type: 'text' },\n actor_type: { type: 'text', default: 'human' },\n action: { type: 'text' },\n targets: { type: 'json' },\n metadata: { type: 'json' },\n factory_project_id: { type: 'text', nullable: true },\n project_repository_id: { type: 'text', nullable: true },\n context: { type: 'json' },\n occurred_at: { type: 'timestamp' },\n },\n indexes: [\n { name: 'audit_events_org_occurred_idx', columns: ['org_id', 'occurred_at'] },\n { name: 'audit_events_org_project_occurred_idx', columns: ['org_id', 'factory_project_id', 'occurred_at'] },\n ],\n};\n\n/** Column shape of one `audit_events` row as returned by ops. */\ninterface AuditEventDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n actor_id: string;\n actor_type: AuditActorType;\n action: string;\n targets: AuditTarget[];\n metadata: Record<string, unknown>;\n factory_project_id: string | null;\n project_repository_id: string | null;\n context: AuditContext;\n occurred_at: Date;\n}\n\nfunction toRow(db: AuditEventDbRow): AuditEventRow {\n return {\n id: db.id,\n orgId: db.org_id,\n actorId: db.actor_id,\n actorType: db.actor_type,\n action: db.action,\n targets: db.targets,\n metadata: db.metadata,\n factoryProjectId: db.factory_project_id,\n projectRepositoryId: db.project_repository_id,\n context: db.context,\n occurredAt: db.occurred_at,\n };\n}\n\n/**\n * Audit event storage, written once against the generic `FactoryStorageOps`\n * surface. `record()` normalizes inputs (defaults, metadata bounding);\n * `list()` is keyset-paginated on `(occurred_at, id)` newest-first.\n */\nexport class AuditStorage extends FactoryStorageDomain {\n constructor() {\n super('audit');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([AUDIT_EVENTS_SCHEMA]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('audit_events', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n /** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */\n async record(input: RecordAuditEventInput): Promise<AuditEventRow> {\n const inserted = await this.#db.insertOne<AuditEventDbRow>('audit_events', {\n org_id: input.orgId,\n actor_id: input.actorId,\n actor_type: input.actorType ?? 'human',\n action: input.action,\n targets: input.targets,\n metadata: boundAuditMetadata(input.metadata),\n factory_project_id: input.factoryProjectId ?? null,\n project_repository_id: input.projectRepositoryId ?? null,\n context: input.context ?? {},\n occurred_at: input.occurredAt ?? new Date(),\n });\n return toRow(inserted);\n }\n\n /** List an org's audit events newest-first with keyset pagination. */\n async list(input: ListAuditEventsInput): Promise<AuditEventPage> {\n const limit = clampAuditLimit(input.limit);\n\n const where: CollectionWhere = { org_id: input.orgId };\n if (input.factoryProjectId) where.factory_project_id = input.factoryProjectId;\n if (input.actions && input.actions.length > 0) where.action = { in: input.actions };\n if (input.actorId) where.actor_id = input.actorId;\n\n const cursor = input.before ? decodeAuditCursor(input.before) : undefined;\n\n const rows = await this.#db.findMany<AuditEventDbRow>('audit_events', where, {\n orderBy: [\n ['occurred_at', 'desc'],\n ['id', 'desc'],\n ],\n limit: limit + 1,\n ...(cursor ? { cursor: { values: [cursor.occurredAt, cursor.id] } } : {}),\n });\n\n const events = rows.slice(0, limit).map(toRow);\n const hasMore = rows.length > limit;\n const last = events[events.length - 1];\n return {\n events,\n ...(hasMore && last ? { nextCursor: encodeAuditCursor(last) } : {}),\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,69 @@
1
+ import type { RequestContext } from '@mastra/core/request-context';
2
+ import type { ApiRoute } from '@mastra/core/server';
3
+ import type { Context } from 'hono';
4
+ import type { RouteAuth } from '../../../routes/route.js';
5
+ import type { FactoryProjectsStorage } from '../projects/base.js';
6
+ import type { AuditContext, AuditEventPage, AuditEventRow, AuditStorage, AuditTarget, ListAuditEventsInput, RecordAuditEventInput } from './base.js';
7
+ export interface EmitAuditInput {
8
+ action: string;
9
+ factoryProjectId?: string;
10
+ projectRepositoryId?: string;
11
+ targets: AuditTarget[];
12
+ metadata?: Record<string, unknown>;
13
+ }
14
+ export interface EmitAgentAuditInput {
15
+ action: string;
16
+ targets: AuditTarget[];
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export interface AuditEmitter {
20
+ emit(args: {
21
+ context: Context;
22
+ input: EmitAuditInput;
23
+ }): Promise<void>;
24
+ }
25
+ export interface AuditAgentEmitter {
26
+ emitAgent(args: {
27
+ requestContext: RequestContext;
28
+ input: EmitAgentAuditInput;
29
+ }): Promise<void>;
30
+ }
31
+ /** Best-effort destination for locally persisted audit events (e.g. an integration's audit log). */
32
+ export interface AuditSink {
33
+ id: string;
34
+ audit?(args: {
35
+ event: AuditEventRow;
36
+ }): Promise<void>;
37
+ }
38
+ export interface AuditDomainOptions {
39
+ auth: RouteAuth;
40
+ /** Audit storage domain handle. */
41
+ audit: AuditStorage;
42
+ /** Projects domain handle, used to scope the audit trail route. */
43
+ projects: FactoryProjectsStorage;
44
+ /** Best-effort fan-out destinations notified after each recorded event. */
45
+ sinks?: AuditSink[];
46
+ /** Resolve the acting tenant for agent-emitted events from the request context. */
47
+ agentTenant?: (requestContext: RequestContext) => {
48
+ orgId?: string;
49
+ userId?: string;
50
+ } | undefined;
51
+ }
52
+ export declare function auditRequestContext(c: Context): AuditContext;
53
+ /** Factory-owned audit behavior backed by the audit storage domain. */
54
+ export declare class AuditDomain implements AuditEmitter, AuditAgentEmitter {
55
+ #private;
56
+ constructor({ auth, audit, projects, sinks, agentTenant }: AuditDomainOptions);
57
+ record(input: RecordAuditEventInput): Promise<AuditEventRow | null>;
58
+ list(input: ListAuditEventsInput): Promise<AuditEventPage>;
59
+ emit({ context, input }: {
60
+ context: Context;
61
+ input: EmitAuditInput;
62
+ }): Promise<void>;
63
+ emitAgent({ requestContext, input, }: {
64
+ requestContext: RequestContext;
65
+ input: EmitAgentAuditInput;
66
+ }): Promise<void>;
67
+ routes(): ApiRoute[];
68
+ }
69
+ //# sourceMappingURL=domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/domain.ts"],"names":[],"mappings":"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"}