@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,585 @@
1
+ // src/integrations/platform/github/event-worker.ts
2
+ import { randomUUID } from "crypto";
3
+ import { isLeaseProvider, NoopLeaseProvider } from "@mastra/core/events";
4
+ import { MastraWorker } from "@mastra/core/worker";
5
+
6
+ // src/integrations/github/subscriptions.ts
7
+ function changeRequestTargetKey(input) {
8
+ return `change-request:${input.installationExternalId}:${input.repositoryExternalId}:${input.changeRequestId}`;
9
+ }
10
+ async function listPullRequestSubscriptionsForWebhook(input, options, storage) {
11
+ const rows = await storage.subscriptions.listByTarget(changeRequestTargetKey(input));
12
+ return options?.includeTerminal ? rows : rows.filter((row) => row.status === "open");
13
+ }
14
+ function retirePullRequestSubscription(id, status, storage) {
15
+ return storage.subscriptions.updateStatus(id, status);
16
+ }
17
+
18
+ // src/integrations/github/webhook.ts
19
+ import { createHmac, timingSafeEqual } from "crypto";
20
+ function getObject(value) {
21
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
22
+ }
23
+ function getString(value) {
24
+ return typeof value === "string" && value.length > 0 ? value : void 0;
25
+ }
26
+ function getNumber(value) {
27
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
28
+ }
29
+ function getBoolean(value) {
30
+ return typeof value === "boolean" ? value : void 0;
31
+ }
32
+ function normalizeGithubWebhookMetadata(parsed) {
33
+ const { event, deliveryId, payload } = parsed;
34
+ const repository = getObject(payload.repository);
35
+ const issue = getObject(payload.issue);
36
+ const pullRequest = getObject(payload.pull_request);
37
+ const sender = getObject(payload.sender);
38
+ const installation = getObject(payload.installation);
39
+ const issuePullRequest = getObject(issue?.pull_request);
40
+ return {
41
+ event,
42
+ action: getString(payload.action),
43
+ deliveryId,
44
+ repository: getString(repository?.full_name),
45
+ repositoryId: getNumber(repository?.id),
46
+ issueNumber: getNumber(issue?.number),
47
+ pullRequestNumber: getNumber(pullRequest?.number) ?? (event === "issue_comment" && issuePullRequest ? getNumber(issue?.number) : void 0),
48
+ sender: getString(sender?.login),
49
+ senderType: getString(sender?.type),
50
+ installationId: getNumber(installation?.id)
51
+ };
52
+ }
53
+ function notificationSummary(metadata, label) {
54
+ const actor = metadata.sender ? `${metadata.sender} ` : "";
55
+ return `${actor}${label} on ${metadata.repository}#${metadata.pullRequestNumber}`;
56
+ }
57
+ function notificationTargetUrl(event, payload) {
58
+ if (event === "issue_comment" || event === "pull_request_review_comment") {
59
+ return getString(getObject(payload.comment)?.html_url);
60
+ }
61
+ if (event === "pull_request_review") {
62
+ return getString(getObject(payload.review)?.html_url);
63
+ }
64
+ return getString(getObject(payload.pull_request)?.html_url);
65
+ }
66
+ function classifyGithubWebhook(parsed) {
67
+ const metadata = normalizeGithubWebhookMetadata(parsed);
68
+ const { event, payload } = parsed;
69
+ const action = metadata.action;
70
+ if (!action || !metadata.repositoryId || !metadata.installationId || !metadata.pullRequestNumber || !metadata.repository) {
71
+ return void 0;
72
+ }
73
+ let priority;
74
+ let kind;
75
+ let label;
76
+ let terminal = false;
77
+ if (event === "pull_request_review" && action === "submitted") {
78
+ const state = getString(getObject(payload.review)?.state)?.toLowerCase().replaceAll("_", "-");
79
+ priority = state === "approved" || state === "changes-requested" ? "urgent" : "high";
80
+ kind = state === "approved" ? "review-approved" : state === "changes-requested" ? "review-changes-requested" : "review-submitted";
81
+ label = state === "approved" ? "approved the pull request" : state === "changes-requested" ? "requested changes" : "submitted a review";
82
+ } else if (event === "pull_request" && action === "closed") {
83
+ const merged = getBoolean(getObject(payload.pull_request)?.merged) === true;
84
+ priority = "urgent";
85
+ kind = merged ? "pull-request-merged" : "pull-request-closed";
86
+ label = merged ? "merged the pull request" : "closed the pull request";
87
+ terminal = true;
88
+ } else if (event === "issue_comment" && action === "created") {
89
+ priority = "high";
90
+ kind = "issue-comment-created";
91
+ label = "commented";
92
+ } else if (event === "pull_request_review_comment" && action === "created") {
93
+ priority = "high";
94
+ kind = "review-comment-created";
95
+ label = "left a review comment";
96
+ } else if (event === "pull_request" && action === "reopened") {
97
+ priority = "high";
98
+ kind = "pull-request-reopened";
99
+ label = "reopened the pull request";
100
+ } else if (event === "pull_request_review" && action === "dismissed") {
101
+ priority = "high";
102
+ kind = "review-dismissed";
103
+ label = "dismissed a review";
104
+ } else if (event === "pull_request" && [
105
+ "synchronize",
106
+ "ready_for_review",
107
+ "converted_to_draft",
108
+ "assigned",
109
+ "unassigned",
110
+ "review_requested",
111
+ "review_request_removed"
112
+ ].includes(action)) {
113
+ priority = "medium";
114
+ kind = `pull-request-${action.replaceAll("_", "-")}`;
115
+ label = action.replaceAll("_", " ");
116
+ } else if (event === "pull_request" && ["edited", "labeled", "unlabeled", "milestoned", "demilestoned"].includes(action)) {
117
+ priority = "low";
118
+ kind = `pull-request-${action.replaceAll("_", "-")}`;
119
+ label = action.replaceAll("_", " ");
120
+ } else {
121
+ return void 0;
122
+ }
123
+ return {
124
+ action,
125
+ kind,
126
+ priority,
127
+ summary: notificationSummary(metadata, label),
128
+ terminal,
129
+ metadata: {
130
+ ...metadata,
131
+ pullRequestNumber: metadata.pullRequestNumber,
132
+ repositoryId: metadata.repositoryId,
133
+ installationId: metadata.installationId
134
+ },
135
+ payload
136
+ };
137
+ }
138
+ async function resolveSubscriptionSession(controller, subscription) {
139
+ const { sessionId, resourceId, threadId } = subscription;
140
+ if (!sessionId || !resourceId || !threadId) {
141
+ throw new Error(`GitHub subscription ${subscription.id} is missing its session binding.`);
142
+ }
143
+ const scope = subscription.sessionScope || void 0;
144
+ let session = await controller.getSessionByResource(resourceId, scope);
145
+ if (!session) {
146
+ const tags = {
147
+ factoryProjectId: resourceId,
148
+ projectRepositoryId: subscription.data.projectRepositoryId,
149
+ ...scope ? { worktreePath: scope } : {}
150
+ };
151
+ session = await controller.createSession({
152
+ id: sessionId,
153
+ ownerId: subscription.data.ownerId,
154
+ resourceId,
155
+ scope,
156
+ tags
157
+ });
158
+ }
159
+ if (session.thread.getId() !== threadId) {
160
+ await session.thread.switch({ threadId, emitEvent: false });
161
+ }
162
+ if (session.thread.getId() !== threadId) {
163
+ throw new Error(`Session ${sessionId} did not bind thread ${threadId}.`);
164
+ }
165
+ return session;
166
+ }
167
+ var AUTHORIZED_BOTS = /* @__PURE__ */ new Set(["coderabbitai[bot]", "devin-ai-integration[bot]"]);
168
+ var AUTHORIZED_PERMISSIONS = /* @__PURE__ */ new Set(["admin", "maintain", "write"]);
169
+ var PERMISSION_CHECK_TIMEOUT_MS = 5e3;
170
+ var AUTHOR_GATED_KINDS = /* @__PURE__ */ new Set([
171
+ "issue-comment-created",
172
+ "review-comment-created",
173
+ "review-submitted",
174
+ "review-approved",
175
+ "review-changes-requested",
176
+ "review-dismissed"
177
+ ]);
178
+ async function isAuthorizedGithubSender(notification, github) {
179
+ if (!AUTHOR_GATED_KINDS.has(notification.kind)) return true;
180
+ const sender = notification.metadata.sender;
181
+ const repository = notification.metadata.repository;
182
+ if (!sender || !repository) return false;
183
+ const normalizedSender = sender.toLowerCase();
184
+ if (notification.metadata.senderType?.toLowerCase() === "bot" || normalizedSender.endsWith("[bot]")) {
185
+ return AUTHORIZED_BOTS.has(normalizedSender);
186
+ }
187
+ if (!github) return false;
188
+ const abortController = new AbortController();
189
+ let timeout;
190
+ try {
191
+ const permission = await Promise.race([
192
+ github.getRepositoryCollaboratorPermission(
193
+ notification.metadata.installationId,
194
+ repository,
195
+ sender,
196
+ abortController.signal
197
+ ),
198
+ new Promise((resolve) => {
199
+ timeout = setTimeout(() => {
200
+ abortController.abort();
201
+ resolve(void 0);
202
+ }, PERMISSION_CHECK_TIMEOUT_MS);
203
+ })
204
+ ]);
205
+ return permission !== void 0 && AUTHORIZED_PERMISSIONS.has(permission);
206
+ } catch {
207
+ return false;
208
+ } finally {
209
+ if (timeout) clearTimeout(timeout);
210
+ }
211
+ }
212
+ async function dispatchGithubWebhook(parsed, dependencies) {
213
+ const notification = classifyGithubWebhook(parsed);
214
+ if (!notification) return { delivered: 0, failed: 0, ignored: true };
215
+ const isAuthorizedSender = dependencies.isAuthorizedSender ?? ((n) => isAuthorizedGithubSender(n, dependencies.github));
216
+ if (!await isAuthorizedSender(notification)) {
217
+ return { delivered: 0, failed: 0, ignored: true };
218
+ }
219
+ const target = {
220
+ installationExternalId: notification.metadata.installationId.toString(),
221
+ repositoryExternalId: notification.metadata.repositoryId.toString(),
222
+ changeRequestId: notification.metadata.pullRequestNumber.toString()
223
+ };
224
+ const listSubscriptions = dependencies.listSubscriptions ?? ((subscriptionTarget, options) => {
225
+ if (!dependencies.github) throw new Error("GitHub integration is required to load webhook subscriptions.");
226
+ return listPullRequestSubscriptionsForWebhook(
227
+ subscriptionTarget,
228
+ options,
229
+ dependencies.github.integrationStorage
230
+ );
231
+ });
232
+ const retireSubscription = dependencies.retireSubscription ?? ((id, status) => {
233
+ if (!dependencies.github) throw new Error("GitHub integration is required to retire webhook subscriptions.");
234
+ return retirePullRequestSubscription(id, status, dependencies.github.integrationStorage);
235
+ });
236
+ const subscriptions = await listSubscriptions(target, { includeTerminal: notification.action === "reopened" });
237
+ let delivered = 0;
238
+ let failed = 0;
239
+ for (const subscription of subscriptions) {
240
+ try {
241
+ const session = await resolveSubscriptionSession(dependencies.controller, subscription);
242
+ const result = await session.sendNotificationSignal({
243
+ source: "github",
244
+ kind: notification.kind,
245
+ summary: notification.summary,
246
+ priority: notification.priority,
247
+ payload: notification.payload,
248
+ sourceId: parsed.deliveryId,
249
+ dedupeKey: `${parsed.deliveryId}:${subscription.sessionId}:${subscription.threadId}`,
250
+ coalesceKey: `github:${subscription.data.repositoryExternalId}:pull-request:${subscription.data.changeRequestId}`,
251
+ metadata: {
252
+ event: notification.metadata.event,
253
+ action: notification.action,
254
+ repository: notification.metadata.repository,
255
+ issueNumber: notification.metadata.issueNumber,
256
+ pullRequestNumber: notification.metadata.pullRequestNumber,
257
+ targetUrl: notificationTargetUrl(parsed.event, parsed.payload),
258
+ deliveryId: parsed.deliveryId
259
+ }
260
+ });
261
+ await Promise.all([result.persisted, result.accepted].filter(Boolean));
262
+ if (notification.terminal) {
263
+ await retireSubscription(subscription.id, notification.kind === "pull-request-merged" ? "merged" : "closed");
264
+ } else if (notification.action === "reopened") {
265
+ await retireSubscription(subscription.id, "open");
266
+ }
267
+ delivered += 1;
268
+ } catch (error) {
269
+ failed += 1;
270
+ dependencies.onTargetError?.(subscription, error);
271
+ }
272
+ }
273
+ return { delivered, failed, ignored: false };
274
+ }
275
+
276
+ // src/integrations/platform/api-client.ts
277
+ var PlatformApiError = class extends Error {
278
+ status;
279
+ retryAfterSeconds;
280
+ constructor(message, status, retryAfterSeconds = null) {
281
+ super(message);
282
+ this.name = "PlatformApiError";
283
+ this.status = status;
284
+ this.retryAfterSeconds = retryAfterSeconds;
285
+ }
286
+ };
287
+
288
+ // src/integrations/platform/github/event-worker.ts
289
+ var API_PREFIX = "/v1/server/github-app";
290
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
291
+ var EVENT_PAGE_SIZE = 500;
292
+ var MIN_LEASE_TTL_MS = 3e4;
293
+ var CURSOR_ORG_ID = "__platform_github_event_worker__";
294
+ var CURSOR_USER_ID = "worker";
295
+ var SUPPORTED_EVENTS = /* @__PURE__ */ new Set([
296
+ "issues",
297
+ "issue_comment",
298
+ "pull_request",
299
+ "pull_request_review",
300
+ "pull_request_review_comment"
301
+ ]);
302
+ var AUTHOR_GATED_KINDS2 = /* @__PURE__ */ new Set([
303
+ "issue-comment",
304
+ "pull-request-comment",
305
+ "pull-request-review",
306
+ "pull-request-review-comment"
307
+ ]);
308
+ var AUTHORIZED_BOTS2 = /* @__PURE__ */ new Set(["coderabbitai[bot]", "devin-ai-integration[bot]"]);
309
+ var AUTHORIZED_PERMISSIONS2 = /* @__PURE__ */ new Set(["admin", "maintain", "write"]);
310
+ var PERMISSION_CHECK_TIMEOUT_MS2 = 5e3;
311
+ var PlatformGithubEventWorker = class extends MastraWorker {
312
+ name = "platform-github-events";
313
+ #client;
314
+ #controller;
315
+ #github;
316
+ #storage;
317
+ #ingestFactoryEvent;
318
+ #intervalMs;
319
+ #now;
320
+ #dispatch;
321
+ #leaseOwner = randomUUID();
322
+ #running = false;
323
+ #timer;
324
+ #leaseRenewalTimer;
325
+ #inFlight;
326
+ #leaseProvider = NoopLeaseProvider;
327
+ #leaseTtlMs;
328
+ #hasLease = false;
329
+ #startedAt = 0;
330
+ #settings = { version: 1, repositories: {} };
331
+ constructor(config) {
332
+ super();
333
+ this.#client = config.client;
334
+ this.#controller = config.controller;
335
+ this.#github = config.github;
336
+ this.#storage = config.storage;
337
+ this.#ingestFactoryEvent = config.ingestFactoryEvent;
338
+ this.#intervalMs = config.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
339
+ if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
340
+ throw new Error("Platform GitHub event polling interval must be a positive number.");
341
+ }
342
+ this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);
343
+ this.#now = config.now ?? Date.now;
344
+ this.#dispatch = config.dispatch ?? dispatchGithubWebhook;
345
+ }
346
+ async init(deps) {
347
+ await super.init(deps);
348
+ this.#leaseProvider = getLeaseProvider(deps.pubsub);
349
+ }
350
+ async start() {
351
+ if (this.#running) return;
352
+ if (!this.deps) throw new Error("PlatformGithubEventWorker: call init() before start()");
353
+ this.#startedAt = this.#now() - 1;
354
+ this.#settings = normalizeSettings(await this.#storage.settings.get(CURSOR_ORG_ID, CURSOR_USER_ID));
355
+ this.#running = true;
356
+ this.deps.logger.info("Platform GitHub event polling started", {
357
+ intervalMs: this.#intervalMs,
358
+ leaseTtlMs: this.#leaseTtlMs
359
+ });
360
+ this.#schedule(0);
361
+ }
362
+ async stop() {
363
+ if (!this.#running) return;
364
+ this.#running = false;
365
+ if (this.#timer) clearTimeout(this.#timer);
366
+ this.#timer = void 0;
367
+ this.#stopLeaseRenewal();
368
+ await this.#inFlight;
369
+ if (this.#hasLease) {
370
+ await this.#leaseProvider.releaseLease(this.#leaseKey(), this.#leaseOwner).catch(() => void 0);
371
+ this.#hasLease = false;
372
+ }
373
+ }
374
+ get isRunning() {
375
+ return this.#running;
376
+ }
377
+ #schedule(delayMs) {
378
+ if (!this.#running) return;
379
+ this.#timer = setTimeout(() => {
380
+ this.#timer = void 0;
381
+ const run = this.#tick();
382
+ this.#inFlight = run;
383
+ void run.finally(() => {
384
+ if (this.#inFlight === run) this.#inFlight = void 0;
385
+ });
386
+ }, delayMs);
387
+ this.#timer.unref?.();
388
+ }
389
+ async #tick() {
390
+ let nextDelay = this.#intervalMs;
391
+ try {
392
+ if (!await this.#ensureLease()) return;
393
+ nextDelay = await this.#poll();
394
+ } catch (error) {
395
+ nextDelay = retryDelay(error, this.#intervalMs);
396
+ this.deps?.logger.error("Platform GitHub event polling cycle failed", {
397
+ error: error instanceof Error ? error.message : String(error),
398
+ retryInMs: nextDelay
399
+ });
400
+ } finally {
401
+ this.#schedule(nextDelay);
402
+ }
403
+ }
404
+ async #ensureLease() {
405
+ if (this.#hasLease) return true;
406
+ const result = await this.#leaseProvider.acquireLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs);
407
+ this.#hasLease = result.acquired;
408
+ if (this.#hasLease) this.#startLeaseRenewal();
409
+ return this.#hasLease;
410
+ }
411
+ #startLeaseRenewal() {
412
+ if (this.#leaseRenewalTimer) return;
413
+ this.#leaseRenewalTimer = setInterval(
414
+ () => {
415
+ void this.#leaseProvider.renewLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs).then((renewed) => {
416
+ if (!renewed) {
417
+ this.#hasLease = false;
418
+ this.#stopLeaseRenewal();
419
+ }
420
+ }).catch((error) => {
421
+ this.#hasLease = false;
422
+ this.#stopLeaseRenewal();
423
+ this.deps?.logger.warn("Platform GitHub event polling lease renewal failed", {
424
+ error: error instanceof Error ? error.message : String(error)
425
+ });
426
+ });
427
+ },
428
+ Math.floor(this.#leaseTtlMs / 3)
429
+ );
430
+ this.#leaseRenewalTimer.unref?.();
431
+ }
432
+ #stopLeaseRenewal() {
433
+ if (this.#leaseRenewalTimer) clearInterval(this.#leaseRenewalTimer);
434
+ this.#leaseRenewalTimer = void 0;
435
+ }
436
+ async #poll() {
437
+ const repositories = await this.#discoverRepositories();
438
+ let retryInMs = this.#intervalMs;
439
+ for (const repository of repositories) {
440
+ if (!this.#running || !this.#hasLease) break;
441
+ try {
442
+ await this.#pollRepository(repository.id);
443
+ } catch (error) {
444
+ const delay = retryDelay(error, this.#intervalMs);
445
+ retryInMs = Math.max(retryInMs, delay);
446
+ this.deps?.logger.error("Platform GitHub repository event polling failed", {
447
+ repositoryId: repository.id,
448
+ error: error instanceof Error ? error.message : String(error),
449
+ retryInMs: delay
450
+ });
451
+ if (error instanceof PlatformApiError && error.status === 429) break;
452
+ }
453
+ }
454
+ return retryInMs;
455
+ }
456
+ async #discoverRepositories() {
457
+ const result = await this.#client.request("GET", `${API_PREFIX}/installations`);
458
+ const repositories = /* @__PURE__ */ new Map();
459
+ for (const installation of result.installations) {
460
+ if (!installation.usable || installation.suspendedAt) continue;
461
+ const page = await this.#client.request(
462
+ "GET",
463
+ `${API_PREFIX}/installations/${installation.installationId}/repositories`
464
+ );
465
+ for (const repository of page.repositories) repositories.set(repository.id, repository);
466
+ }
467
+ return [...repositories.values()];
468
+ }
469
+ async #pollRepository(repositoryId) {
470
+ const key = String(repositoryId);
471
+ if (!this.#settings.repositories[key]) {
472
+ this.#settings.repositories[key] = { afterTimestamp: this.#startedAt };
473
+ await this.#saveSettings();
474
+ }
475
+ while (this.#running && this.#hasLease) {
476
+ const cursor = this.#settings.repositories[key];
477
+ const query = new URLSearchParams({ limit: String(EVENT_PAGE_SIZE) });
478
+ if ("afterEventId" in cursor) query.set("afterEventId", cursor.afterEventId);
479
+ else query.set("afterTimestamp", String(cursor.afterTimestamp));
480
+ const page = await this.#client.request(
481
+ "GET",
482
+ `${API_PREFIX}/repositories/${repositoryId}/events?${query}`
483
+ );
484
+ if (page.events.length === 0 || !page.nextCursor) return;
485
+ for (const event of page.events) {
486
+ if (!this.#running || !this.#hasLease) return;
487
+ const parsed = parseEvent(event);
488
+ if (!parsed) {
489
+ this.deps?.logger.warn("Platform GitHub event log returned a malformed event", {
490
+ repositoryId,
491
+ eventId: event.id
492
+ });
493
+ continue;
494
+ }
495
+ if (isFactoryClosureEvent(parsed)) {
496
+ await this.#ingestFactoryEvent?.(parsed);
497
+ }
498
+ const result = await this.#dispatch(parsed, {
499
+ controller: this.#controller,
500
+ listSubscriptions: (target, options) => listPullRequestSubscriptionsForWebhook(target, options, this.#github.integrationStorage),
501
+ retireSubscription: (id, status) => retirePullRequestSubscription(id, status, this.#github.integrationStorage),
502
+ isAuthorizedSender: (notification) => this.#isAuthorizedSender(notification),
503
+ onTargetError: (subscription, error) => {
504
+ this.deps?.logger.error("Platform GitHub event delivery failed for a subscription", {
505
+ subscriptionId: subscription.id,
506
+ resourceId: subscription.resourceId,
507
+ threadId: subscription.threadId,
508
+ error: error instanceof Error ? error.message : String(error)
509
+ });
510
+ }
511
+ });
512
+ if (result.failed > 0) {
513
+ throw new Error(
514
+ `Platform GitHub event ${event.deliveryId} failed for ${result.failed} subscribed target(s).`
515
+ );
516
+ }
517
+ }
518
+ if (page.nextCursor === ("afterEventId" in cursor ? cursor.afterEventId : void 0)) return;
519
+ this.#settings.repositories[key] = { afterEventId: page.nextCursor };
520
+ await this.#saveSettings();
521
+ }
522
+ }
523
+ async #isAuthorizedSender(notification) {
524
+ if (!AUTHOR_GATED_KINDS2.has(notification.kind)) return true;
525
+ const sender = notification.metadata.sender;
526
+ const repository = notification.metadata.repository;
527
+ if (!sender || !repository) return false;
528
+ if (AUTHORIZED_BOTS2.has(sender)) return true;
529
+ const abortController = new AbortController();
530
+ const timeout = setTimeout(() => abortController.abort(), PERMISSION_CHECK_TIMEOUT_MS2);
531
+ try {
532
+ const permission = await this.#github.getRepositoryCollaboratorPermission(
533
+ notification.metadata.installationId,
534
+ repository,
535
+ sender,
536
+ abortController.signal
537
+ );
538
+ return permission !== void 0 && AUTHORIZED_PERMISSIONS2.has(permission);
539
+ } catch {
540
+ return false;
541
+ } finally {
542
+ clearTimeout(timeout);
543
+ }
544
+ }
545
+ async #saveSettings() {
546
+ await this.#storage.settings.save(CURSOR_ORG_ID, CURSOR_USER_ID, this.#settings);
547
+ }
548
+ #leaseKey() {
549
+ return `${this.name}:${this.#storage.integrationId}`;
550
+ }
551
+ };
552
+ function getLeaseProvider(pubsub) {
553
+ const getProvider = pubsub.getLeaseProvider;
554
+ if (typeof getProvider === "function") return getProvider.call(pubsub) ?? NoopLeaseProvider;
555
+ return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;
556
+ }
557
+ function normalizeSettings(value) {
558
+ if (!value || value.version !== 1 || !value.repositories || typeof value.repositories !== "object") {
559
+ return { version: 1, repositories: {} };
560
+ }
561
+ return { version: 1, repositories: { ...value.repositories } };
562
+ }
563
+ function isFactoryClosureEvent(event) {
564
+ return (event.event === "issues" || event.event === "pull_request") && event.payload.action === "closed";
565
+ }
566
+ function parseEvent(event) {
567
+ if (!event.id || !event.deliveryId || !SUPPORTED_EVENTS.has(event.event) || !event.payload || typeof event.payload !== "object" || Array.isArray(event.payload)) {
568
+ return null;
569
+ }
570
+ return {
571
+ event: event.event,
572
+ deliveryId: event.deliveryId,
573
+ payload: event.payload
574
+ };
575
+ }
576
+ function retryDelay(error, fallbackMs) {
577
+ if (error instanceof PlatformApiError && error.status === 429 && error.retryAfterSeconds !== null) {
578
+ return Math.max(fallbackMs, error.retryAfterSeconds * 1e3);
579
+ }
580
+ return fallbackMs;
581
+ }
582
+ export {
583
+ PlatformGithubEventWorker
584
+ };
585
+ //# sourceMappingURL=event-worker.js.map