@mastra/factory 0.2.2-alpha.1 → 0.2.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/auth.js +401 -334
- package/dist/auth.js.map +1 -1
- package/dist/capabilities/connection.js +1 -1
- package/dist/capabilities/intake.js +1 -1
- package/dist/capabilities/version-control.js +1 -1
- package/dist/factory.js +441 -39622
- package/dist/factory.js.map +1 -1
- package/dist/index.js +2 -39633
- package/dist/integrations/base.js +1 -1
- package/dist/integrations/github/config.js +36 -22
- package/dist/integrations/github/config.js.map +1 -1
- package/dist/integrations/github/factory-session.js +33 -37
- package/dist/integrations/github/factory-session.js.map +1 -1
- package/dist/integrations/github/integration.js +1037 -3672
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/issue-triage.js +71 -71
- package/dist/integrations/github/issue-triage.js.map +1 -1
- package/dist/integrations/github/pat.js +47 -36
- package/dist/integrations/github/pat.js.map +1 -1
- package/dist/integrations/github/provenance.js +72 -101
- package/dist/integrations/github/provenance.js.map +1 -1
- package/dist/integrations/github/routes.js +1272 -1881
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.js +203 -471
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.js +400 -345
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +165 -223
- package/dist/integrations/github/session-subscriptions.js.map +1 -1
- package/dist/integrations/github/subscriptions.js +43 -51
- package/dist/integrations/github/subscriptions.js.map +1 -1
- package/dist/integrations/github/token-refresh.js +15 -18
- package/dist/integrations/github/token-refresh.js.map +1 -1
- package/dist/integrations/github/webhook.js +359 -343
- package/dist/integrations/github/webhook.js.map +1 -1
- package/dist/integrations/linear/agent-tools.js +77 -100
- package/dist/integrations/linear/agent-tools.js.map +1 -1
- package/dist/integrations/linear/integration.js +611 -1309
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/routes.js +227 -230
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/linear/rules.js +126 -346
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/linear/storage.js +1 -1
- package/dist/integrations/platform/api-client.js +131 -135
- package/dist/integrations/platform/api-client.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +275 -573
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.js +845 -4022
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/linear/integration.js +457 -1309
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/integrations/workos/integration.js +80 -85
- package/dist/integrations/workos/integration.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +933 -912
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/custom-provider-source.js +110 -93
- package/dist/routes/custom-provider-source.js.map +1 -1
- package/dist/routes/fs.js +401 -349
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/intake.js +165 -165
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/oauth.js +447 -25166
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/projects.js +437 -376
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/provider-credentials.js +76 -58
- package/dist/routes/provider-credentials.js.map +1 -1
- package/dist/routes/route.js +12 -8
- package/dist/routes/route.js.map +1 -1
- package/dist/routes/skills.js +160 -173
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/surface.js +250 -28615
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/tenant-credentials.js +141 -166
- package/dist/routes/tenant-credentials.js.map +1 -1
- package/dist/routes/work-items.js +654 -862
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.js +23 -35
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/defaults.js +200 -309
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatcher.js +438 -683
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/index.js +5 -599
- package/dist/rules/processor.js +344 -596
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/resolve.js +21 -18
- package/dist/rules/resolve.js.map +1 -1
- package/dist/rules/start-coordinator.js +168 -157
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/tools.js +50 -85
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.js +183 -454
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.js +33 -29
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.js +266 -281
- package/dist/rules/validation.js.map +1 -1
- package/dist/sandbox/fleet.js +272 -250
- package/dist/sandbox/fleet.js.map +1 -1
- package/dist/sandbox/reattach.js +13 -6
- package/dist/sandbox/reattach.js.map +1 -1
- package/dist/server-error.js +12 -16
- package/dist/server-error.js.map +1 -1
- package/dist/skills/service.js +30 -35
- package/dist/skills/service.js.map +1 -1
- package/dist/spa-static.js +91 -65
- package/dist/spa-static.js.map +1 -1
- package/dist/state-signing.js +73 -44
- package/dist/state-signing.js.map +1 -1
- package/dist/storage/domains/audit/agent-audit.js +60 -59
- package/dist/storage/domains/audit/agent-audit.js.map +1 -1
- package/dist/storage/domains/audit/base.js +169 -112
- package/dist/storage/domains/audit/base.js.map +1 -1
- package/dist/storage/domains/audit/domain.js +155 -153
- package/dist/storage/domains/audit/domain.js.map +1 -1
- package/dist/storage/domains/credentials/base.js +259 -243
- package/dist/storage/domains/credentials/base.js.map +1 -1
- package/dist/storage/domains/custom-providers/base.js +138 -143
- package/dist/storage/domains/custom-providers/base.js.map +1 -1
- package/dist/storage/domains/intake/base.js +75 -57
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/integrations/base.js +310 -245
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/memory-settings/base.js +117 -102
- package/dist/storage/domains/memory-settings/base.js.map +1 -1
- package/dist/storage/domains/model-packs/base.js +89 -88
- package/dist/storage/domains/model-packs/base.js.map +1 -1
- package/dist/storage/domains/projects/base.js +97 -92
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/queue-health/base.js +111 -76
- package/dist/storage/domains/queue-health/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.js +777 -706
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +322 -348
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.js +1266 -1148
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/metrics.js +202 -184
- package/dist/storage/domains/work-items/metrics.js.map +1 -1
- package/dist/timing.js +29 -22
- package/dist/timing.js.map +1 -1
- package/dist/workspace.js +236 -477
- package/dist/workspace.js.map +1 -1
- package/package.json +8 -8
- package/dist/capabilities/connection.js.map +0 -1
- package/dist/capabilities/intake.js.map +0 -1
- package/dist/capabilities/version-control.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/base.js.map +0 -1
- package/dist/integrations/linear/storage.js.map +0 -1
- package/dist/rules/index.js.map +0 -1
|
@@ -1,591 +1,293 @@
|
|
|
1
|
-
|
|
1
|
+
import { listPullRequestSubscriptionsForWebhook, retirePullRequestSubscription } from "../../github/subscriptions.js";
|
|
2
|
+
import { dispatchGithubWebhook } from "../../github/webhook.js";
|
|
3
|
+
import { PlatformApiError } from "../api-client.js";
|
|
2
4
|
import { randomUUID } from "crypto";
|
|
3
|
-
import {
|
|
5
|
+
import { NoopLeaseProvider, isLeaseProvider } from "@mastra/core/events";
|
|
4
6
|
import { MastraWorker } from "@mastra/core/worker";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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"
|
|
7
|
+
//#region src/integrations/platform/github/event-worker.ts
|
|
8
|
+
const API_PREFIX = "/v1/server/github-app";
|
|
9
|
+
const DEFAULT_POLL_INTERVAL_MS = 2e4;
|
|
10
|
+
const EVENT_PAGE_SIZE = 500;
|
|
11
|
+
const MIN_LEASE_TTL_MS = 3e4;
|
|
12
|
+
const CURSOR_ORG_ID = "__platform_github_event_worker__";
|
|
13
|
+
const CURSOR_USER_ID = "worker";
|
|
14
|
+
const SUPPORTED_EVENTS = /* @__PURE__ */ new Set([
|
|
15
|
+
"issues",
|
|
16
|
+
"issue_comment",
|
|
17
|
+
"pull_request",
|
|
18
|
+
"pull_request_review",
|
|
19
|
+
"pull_request_review_comment"
|
|
177
20
|
]);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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 = 2e4;
|
|
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"
|
|
21
|
+
const AUTHOR_GATED_KINDS = /* @__PURE__ */ new Set([
|
|
22
|
+
"issue-comment",
|
|
23
|
+
"pull-request-comment",
|
|
24
|
+
"pull-request-review",
|
|
25
|
+
"pull-request-review-comment"
|
|
301
26
|
]);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
27
|
+
const AUTHORIZED_BOTS = /* @__PURE__ */ new Set(["coderabbitai[bot]", "devin-ai-integration[bot]"]);
|
|
28
|
+
const AUTHORIZED_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
29
|
+
"admin",
|
|
30
|
+
"maintain",
|
|
31
|
+
"write"
|
|
307
32
|
]);
|
|
308
|
-
|
|
309
|
-
var AUTHORIZED_PERMISSIONS2 = /* @__PURE__ */ new Set(["admin", "maintain", "write"]);
|
|
310
|
-
var PERMISSION_CHECK_TIMEOUT_MS2 = 5e3;
|
|
33
|
+
const PERMISSION_CHECK_TIMEOUT_MS = 5e3;
|
|
311
34
|
var PlatformGithubEventWorker = class extends MastraWorker {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const timeout = setTimeout(() => abortController.abort(), PERMISSION_CHECK_TIMEOUT_MS2);
|
|
537
|
-
try {
|
|
538
|
-
const permission = await this.#github.getRepositoryCollaboratorPermission(
|
|
539
|
-
notification.metadata.installationId,
|
|
540
|
-
repository,
|
|
541
|
-
sender,
|
|
542
|
-
abortController.signal
|
|
543
|
-
);
|
|
544
|
-
return permission !== void 0 && AUTHORIZED_PERMISSIONS2.has(permission);
|
|
545
|
-
} catch {
|
|
546
|
-
return false;
|
|
547
|
-
} finally {
|
|
548
|
-
clearTimeout(timeout);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
async #saveSettings() {
|
|
552
|
-
await this.#storage.settings.save(CURSOR_ORG_ID, CURSOR_USER_ID, this.#settings);
|
|
553
|
-
}
|
|
554
|
-
#leaseKey() {
|
|
555
|
-
return `${this.name}:${this.#storage.integrationId}`;
|
|
556
|
-
}
|
|
35
|
+
name = "platform-github-events";
|
|
36
|
+
#client;
|
|
37
|
+
#controller;
|
|
38
|
+
#github;
|
|
39
|
+
#storage;
|
|
40
|
+
#ingestFactoryEvent;
|
|
41
|
+
#intervalMs;
|
|
42
|
+
#now;
|
|
43
|
+
#dispatch;
|
|
44
|
+
#leaseOwner = randomUUID();
|
|
45
|
+
#running = false;
|
|
46
|
+
#timer;
|
|
47
|
+
#leaseRenewalTimer;
|
|
48
|
+
#inFlight;
|
|
49
|
+
#leaseProvider = NoopLeaseProvider;
|
|
50
|
+
#leaseTtlMs;
|
|
51
|
+
#hasLease = false;
|
|
52
|
+
#startedAt = 0;
|
|
53
|
+
#settings = {
|
|
54
|
+
version: 1,
|
|
55
|
+
repositories: {}
|
|
56
|
+
};
|
|
57
|
+
constructor(config) {
|
|
58
|
+
super();
|
|
59
|
+
this.#client = config.client;
|
|
60
|
+
this.#controller = config.controller;
|
|
61
|
+
this.#github = config.github;
|
|
62
|
+
this.#storage = config.storage;
|
|
63
|
+
this.#ingestFactoryEvent = config.ingestFactoryEvent;
|
|
64
|
+
this.#intervalMs = config.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
65
|
+
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) throw new Error("Platform GitHub event polling interval must be a positive number.");
|
|
66
|
+
this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);
|
|
67
|
+
this.#now = config.now ?? Date.now;
|
|
68
|
+
this.#dispatch = config.dispatch ?? dispatchGithubWebhook;
|
|
69
|
+
}
|
|
70
|
+
async init(deps) {
|
|
71
|
+
await super.init(deps);
|
|
72
|
+
this.#leaseProvider = getLeaseProvider(deps.pubsub);
|
|
73
|
+
}
|
|
74
|
+
async start() {
|
|
75
|
+
if (this.#running) return;
|
|
76
|
+
if (!this.deps) throw new Error("PlatformGithubEventWorker: call init() before start()");
|
|
77
|
+
this.#startedAt = this.#now() - 1;
|
|
78
|
+
this.#settings = normalizeSettings(await this.#storage.settings.get(CURSOR_ORG_ID, CURSOR_USER_ID));
|
|
79
|
+
this.#running = true;
|
|
80
|
+
this.deps.logger.info("Platform GitHub event polling started", {
|
|
81
|
+
intervalMs: this.#intervalMs,
|
|
82
|
+
leaseTtlMs: this.#leaseTtlMs
|
|
83
|
+
});
|
|
84
|
+
this.#schedule(0);
|
|
85
|
+
}
|
|
86
|
+
async stop() {
|
|
87
|
+
if (!this.#running) return;
|
|
88
|
+
this.#running = false;
|
|
89
|
+
if (this.#timer) clearTimeout(this.#timer);
|
|
90
|
+
this.#timer = void 0;
|
|
91
|
+
this.#stopLeaseRenewal();
|
|
92
|
+
await this.#inFlight;
|
|
93
|
+
if (this.#hasLease) {
|
|
94
|
+
await this.#leaseProvider.releaseLease(this.#leaseKey(), this.#leaseOwner).catch(() => void 0);
|
|
95
|
+
this.#hasLease = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
get isRunning() {
|
|
99
|
+
return this.#running;
|
|
100
|
+
}
|
|
101
|
+
#schedule(delayMs) {
|
|
102
|
+
if (!this.#running) return;
|
|
103
|
+
this.#timer = setTimeout(() => {
|
|
104
|
+
this.#timer = void 0;
|
|
105
|
+
const run = this.#tick();
|
|
106
|
+
this.#inFlight = run;
|
|
107
|
+
run.finally(() => {
|
|
108
|
+
if (this.#inFlight === run) this.#inFlight = void 0;
|
|
109
|
+
});
|
|
110
|
+
}, delayMs);
|
|
111
|
+
this.#timer.unref?.();
|
|
112
|
+
}
|
|
113
|
+
async #tick() {
|
|
114
|
+
let nextDelay = this.#intervalMs;
|
|
115
|
+
try {
|
|
116
|
+
if (!await this.#ensureLease()) return;
|
|
117
|
+
nextDelay = await this.#poll();
|
|
118
|
+
} catch (error) {
|
|
119
|
+
nextDelay = retryDelay(error, this.#intervalMs);
|
|
120
|
+
this.deps?.logger.error("Platform GitHub event polling cycle failed", {
|
|
121
|
+
error: error instanceof Error ? error.message : String(error),
|
|
122
|
+
retryInMs: nextDelay
|
|
123
|
+
});
|
|
124
|
+
} finally {
|
|
125
|
+
this.#schedule(nextDelay);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async #ensureLease() {
|
|
129
|
+
if (this.#hasLease) return true;
|
|
130
|
+
const result = await this.#leaseProvider.acquireLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs);
|
|
131
|
+
this.#hasLease = result.acquired;
|
|
132
|
+
if (this.#hasLease) this.#startLeaseRenewal();
|
|
133
|
+
return this.#hasLease;
|
|
134
|
+
}
|
|
135
|
+
#startLeaseRenewal() {
|
|
136
|
+
if (this.#leaseRenewalTimer) return;
|
|
137
|
+
this.#leaseRenewalTimer = setInterval(() => {
|
|
138
|
+
this.#leaseProvider.renewLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs).then((renewed) => {
|
|
139
|
+
if (!renewed) {
|
|
140
|
+
this.#hasLease = false;
|
|
141
|
+
this.#stopLeaseRenewal();
|
|
142
|
+
}
|
|
143
|
+
}).catch((error) => {
|
|
144
|
+
this.#hasLease = false;
|
|
145
|
+
this.#stopLeaseRenewal();
|
|
146
|
+
this.deps?.logger.warn("Platform GitHub event polling lease renewal failed", { error: error instanceof Error ? error.message : String(error) });
|
|
147
|
+
});
|
|
148
|
+
}, Math.floor(this.#leaseTtlMs / 3));
|
|
149
|
+
this.#leaseRenewalTimer.unref?.();
|
|
150
|
+
}
|
|
151
|
+
#stopLeaseRenewal() {
|
|
152
|
+
if (this.#leaseRenewalTimer) clearInterval(this.#leaseRenewalTimer);
|
|
153
|
+
this.#leaseRenewalTimer = void 0;
|
|
154
|
+
}
|
|
155
|
+
async #poll() {
|
|
156
|
+
const repositories = await this.#discoverRepositories();
|
|
157
|
+
let retryInMs = this.#intervalMs;
|
|
158
|
+
for (const repository of repositories) {
|
|
159
|
+
if (!this.#running || !this.#hasLease) break;
|
|
160
|
+
try {
|
|
161
|
+
await this.#pollRepository(repository.id);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const delay = retryDelay(error, this.#intervalMs);
|
|
164
|
+
retryInMs = Math.max(retryInMs, delay);
|
|
165
|
+
this.deps?.logger.error("Platform GitHub repository event polling failed", {
|
|
166
|
+
repositoryId: repository.id,
|
|
167
|
+
error: error instanceof Error ? error.message : String(error),
|
|
168
|
+
retryInMs: delay
|
|
169
|
+
});
|
|
170
|
+
if (error instanceof PlatformApiError && error.status === 429) break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return retryInMs;
|
|
174
|
+
}
|
|
175
|
+
async #discoverRepositories() {
|
|
176
|
+
const result = await this.#client.request("GET", `${API_PREFIX}/installations`);
|
|
177
|
+
const repositories = /* @__PURE__ */ new Map();
|
|
178
|
+
for (const installation of result.installations) {
|
|
179
|
+
if (!installation.usable || installation.suspendedAt) continue;
|
|
180
|
+
const page = await this.#client.request("GET", `${API_PREFIX}/installations/${installation.installationId}/repositories`);
|
|
181
|
+
for (const repository of page.repositories) repositories.set(repository.id, repository);
|
|
182
|
+
}
|
|
183
|
+
return [...repositories.values()];
|
|
184
|
+
}
|
|
185
|
+
async #pollRepository(repositoryId) {
|
|
186
|
+
const key = String(repositoryId);
|
|
187
|
+
if (!this.#settings.repositories[key]) {
|
|
188
|
+
this.#settings.repositories[key] = { afterTimestamp: this.#startedAt };
|
|
189
|
+
await this.#saveSettings();
|
|
190
|
+
}
|
|
191
|
+
while (this.#running && this.#hasLease) {
|
|
192
|
+
const cursor = this.#settings.repositories[key];
|
|
193
|
+
const query = new URLSearchParams({ limit: String(EVENT_PAGE_SIZE) });
|
|
194
|
+
if ("afterEventId" in cursor) query.set("afterEventId", cursor.afterEventId);
|
|
195
|
+
else query.set("afterTimestamp", String(cursor.afterTimestamp));
|
|
196
|
+
const pollStartedAt = performance.now();
|
|
197
|
+
const page = await this.#client.request("GET", `${API_PREFIX}/repositories/${repositoryId}/events?${query}`);
|
|
198
|
+
this.deps?.logger.info("Platform GitHub repository event poll completed", {
|
|
199
|
+
repositoryId,
|
|
200
|
+
eventCount: page.events.length,
|
|
201
|
+
latencyMs: Math.round(performance.now() - pollStartedAt)
|
|
202
|
+
});
|
|
203
|
+
if (page.events.length === 0 || !page.nextCursor) return;
|
|
204
|
+
for (const event of page.events) {
|
|
205
|
+
if (!this.#running || !this.#hasLease) return;
|
|
206
|
+
const parsed = parseEvent(event);
|
|
207
|
+
if (!parsed) {
|
|
208
|
+
this.deps?.logger.warn("Platform GitHub event log returned a malformed event", {
|
|
209
|
+
repositoryId,
|
|
210
|
+
eventId: event.id
|
|
211
|
+
});
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (isFactoryClosureEvent(parsed)) await this.#ingestFactoryEvent?.(parsed);
|
|
215
|
+
const result = await this.#dispatch(parsed, {
|
|
216
|
+
controller: this.#controller,
|
|
217
|
+
listSubscriptions: (target, options) => listPullRequestSubscriptionsForWebhook(target, options, this.#github.integrationStorage),
|
|
218
|
+
retireSubscription: (id, status) => retirePullRequestSubscription(id, status, this.#github.integrationStorage),
|
|
219
|
+
isAuthorizedSender: (notification) => this.#isAuthorizedSender(notification),
|
|
220
|
+
onTargetError: (subscription, error) => {
|
|
221
|
+
this.deps?.logger.error("Platform GitHub event delivery failed for a subscription", {
|
|
222
|
+
subscriptionId: subscription.id,
|
|
223
|
+
resourceId: subscription.resourceId,
|
|
224
|
+
threadId: subscription.threadId,
|
|
225
|
+
error: error instanceof Error ? error.message : String(error)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
if (result.failed > 0) throw new Error(`Platform GitHub event ${event.deliveryId} failed for ${result.failed} subscribed target(s).`);
|
|
230
|
+
}
|
|
231
|
+
if (page.nextCursor === ("afterEventId" in cursor ? cursor.afterEventId : void 0)) return;
|
|
232
|
+
this.#settings.repositories[key] = { afterEventId: page.nextCursor };
|
|
233
|
+
await this.#saveSettings();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async #isAuthorizedSender(notification) {
|
|
237
|
+
if (!AUTHOR_GATED_KINDS.has(notification.kind)) return true;
|
|
238
|
+
const sender = notification.metadata.sender;
|
|
239
|
+
const repository = notification.metadata.repository;
|
|
240
|
+
if (!sender || !repository) return false;
|
|
241
|
+
if (AUTHORIZED_BOTS.has(sender)) return true;
|
|
242
|
+
const abortController = new AbortController();
|
|
243
|
+
const timeout = setTimeout(() => abortController.abort(), PERMISSION_CHECK_TIMEOUT_MS);
|
|
244
|
+
try {
|
|
245
|
+
const permission = await this.#github.getRepositoryCollaboratorPermission(notification.metadata.installationId, repository, sender, abortController.signal);
|
|
246
|
+
return permission !== void 0 && AUTHORIZED_PERMISSIONS.has(permission);
|
|
247
|
+
} catch {
|
|
248
|
+
return false;
|
|
249
|
+
} finally {
|
|
250
|
+
clearTimeout(timeout);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async #saveSettings() {
|
|
254
|
+
await this.#storage.settings.save(CURSOR_ORG_ID, CURSOR_USER_ID, this.#settings);
|
|
255
|
+
}
|
|
256
|
+
#leaseKey() {
|
|
257
|
+
return `${this.name}:${this.#storage.integrationId}`;
|
|
258
|
+
}
|
|
557
259
|
};
|
|
558
260
|
function getLeaseProvider(pubsub) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
261
|
+
const getProvider = pubsub.getLeaseProvider;
|
|
262
|
+
if (typeof getProvider === "function") return getProvider.call(pubsub) ?? NoopLeaseProvider;
|
|
263
|
+
return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;
|
|
562
264
|
}
|
|
563
265
|
function normalizeSettings(value) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
266
|
+
if (!value || value.version !== 1 || !value.repositories || typeof value.repositories !== "object") return {
|
|
267
|
+
version: 1,
|
|
268
|
+
repositories: {}
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
version: 1,
|
|
272
|
+
repositories: { ...value.repositories }
|
|
273
|
+
};
|
|
568
274
|
}
|
|
569
275
|
function isFactoryClosureEvent(event) {
|
|
570
|
-
|
|
276
|
+
return (event.event === "issues" || event.event === "pull_request") && event.payload.action === "closed";
|
|
571
277
|
}
|
|
572
278
|
function parseEvent(event) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
payload: event.payload
|
|
580
|
-
};
|
|
279
|
+
if (!event.id || !event.deliveryId || !SUPPORTED_EVENTS.has(event.event) || !event.payload || typeof event.payload !== "object" || Array.isArray(event.payload)) return null;
|
|
280
|
+
return {
|
|
281
|
+
event: event.event,
|
|
282
|
+
deliveryId: event.deliveryId,
|
|
283
|
+
payload: event.payload
|
|
284
|
+
};
|
|
581
285
|
}
|
|
582
286
|
function retryDelay(error, fallbackMs) {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
return fallbackMs;
|
|
287
|
+
if (error instanceof PlatformApiError && error.status === 429 && error.retryAfterSeconds !== null) return Math.max(fallbackMs, error.retryAfterSeconds * 1e3);
|
|
288
|
+
return fallbackMs;
|
|
587
289
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
290
|
+
//#endregion
|
|
291
|
+
export { PlatformGithubEventWorker };
|
|
292
|
+
|
|
591
293
|
//# sourceMappingURL=event-worker.js.map
|