@mastra/factory 0.0.0-fix-thread-subscription-multi-instance-redis-streams-20260730204150
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 +695 -0
- package/LICENSE.md +30 -0
- package/README.md +27 -0
- package/dist/auth.d.ts +181 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +505 -0
- package/dist/auth.js.map +1 -0
- package/dist/capabilities/connection.d.ts +9 -0
- package/dist/capabilities/connection.d.ts.map +1 -0
- package/dist/capabilities/connection.js +1 -0
- package/dist/capabilities/intake.d.ts +140 -0
- package/dist/capabilities/intake.d.ts.map +1 -0
- package/dist/capabilities/intake.js +1 -0
- package/dist/capabilities/version-control.d.ts +245 -0
- package/dist/capabilities/version-control.d.ts.map +1 -0
- package/dist/capabilities/version-control.js +1 -0
- package/dist/factory.d.ts +156 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +483 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/integrations/base.d.ts +210 -0
- package/dist/integrations/base.d.ts.map +1 -0
- package/dist/integrations/base.js +1 -0
- package/dist/integrations/github/config.d.ts +60 -0
- package/dist/integrations/github/config.d.ts.map +1 -0
- package/dist/integrations/github/config.js +42 -0
- package/dist/integrations/github/config.js.map +1 -0
- package/dist/integrations/github/factory-session.d.ts +12 -0
- package/dist/integrations/github/factory-session.d.ts.map +1 -0
- package/dist/integrations/github/factory-session.js +37 -0
- package/dist/integrations/github/factory-session.js.map +1 -0
- package/dist/integrations/github/integration.d.ts +191 -0
- package/dist/integrations/github/integration.d.ts.map +1 -0
- package/dist/integrations/github/integration.js +1077 -0
- package/dist/integrations/github/integration.js.map +1 -0
- package/dist/integrations/github/issue-triage.d.ts +27 -0
- package/dist/integrations/github/issue-triage.d.ts.map +1 -0
- package/dist/integrations/github/issue-triage.js +82 -0
- package/dist/integrations/github/issue-triage.js.map +1 -0
- package/dist/integrations/github/pat.d.ts +38 -0
- package/dist/integrations/github/pat.d.ts.map +1 -0
- package/dist/integrations/github/pat.js +59 -0
- package/dist/integrations/github/pat.js.map +1 -0
- package/dist/integrations/github/provenance.d.ts +27 -0
- package/dist/integrations/github/provenance.d.ts.map +1 -0
- package/dist/integrations/github/provenance.js +75 -0
- package/dist/integrations/github/provenance.js.map +1 -0
- package/dist/integrations/github/routes.d.ts +69 -0
- package/dist/integrations/github/routes.d.ts.map +1 -0
- package/dist/integrations/github/routes.js +1324 -0
- package/dist/integrations/github/routes.js.map +1 -0
- package/dist/integrations/github/rules.d.ts +78 -0
- package/dist/integrations/github/rules.d.ts.map +1 -0
- package/dist/integrations/github/rules.js +362 -0
- package/dist/integrations/github/rules.js.map +1 -0
- package/dist/integrations/github/sandbox-release.d.ts +38 -0
- package/dist/integrations/github/sandbox-release.d.ts.map +1 -0
- package/dist/integrations/github/sandbox-release.js +74 -0
- package/dist/integrations/github/sandbox-release.js.map +1 -0
- package/dist/integrations/github/sandbox.d.ts +281 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -0
- package/dist/integrations/github/sandbox.js +547 -0
- package/dist/integrations/github/sandbox.js.map +1 -0
- package/dist/integrations/github/session-subscriptions.d.ts +26 -0
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -0
- package/dist/integrations/github/session-subscriptions.js +192 -0
- package/dist/integrations/github/session-subscriptions.js.map +1 -0
- package/dist/integrations/github/subscriptions.d.ts +54 -0
- package/dist/integrations/github/subscriptions.d.ts.map +1 -0
- package/dist/integrations/github/subscriptions.js +62 -0
- package/dist/integrations/github/subscriptions.js.map +1 -0
- package/dist/integrations/github/token-refresh.d.ts +12 -0
- package/dist/integrations/github/token-refresh.d.ts.map +1 -0
- package/dist/integrations/github/token-refresh.js +24 -0
- package/dist/integrations/github/token-refresh.js.map +1 -0
- package/dist/integrations/github/webhook.d.ts +87 -0
- package/dist/integrations/github/webhook.d.ts.map +1 -0
- package/dist/integrations/github/webhook.js +397 -0
- package/dist/integrations/github/webhook.js.map +1 -0
- package/dist/integrations/linear/agent-tools.d.ts +34 -0
- package/dist/integrations/linear/agent-tools.d.ts.map +1 -0
- package/dist/integrations/linear/agent-tools.js +85 -0
- package/dist/integrations/linear/agent-tools.js.map +1 -0
- package/dist/integrations/linear/integration.d.ts +233 -0
- package/dist/integrations/linear/integration.d.ts.map +1 -0
- package/dist/integrations/linear/integration.js +672 -0
- package/dist/integrations/linear/integration.js.map +1 -0
- package/dist/integrations/linear/routes.d.ts +61 -0
- package/dist/integrations/linear/routes.d.ts.map +1 -0
- package/dist/integrations/linear/routes.js +239 -0
- package/dist/integrations/linear/routes.js.map +1 -0
- package/dist/integrations/linear/rules.d.ts +42 -0
- package/dist/integrations/linear/rules.d.ts.map +1 -0
- package/dist/integrations/linear/rules.js +133 -0
- package/dist/integrations/linear/rules.js.map +1 -0
- package/dist/integrations/linear/storage.d.ts +65 -0
- package/dist/integrations/linear/storage.d.ts.map +1 -0
- package/dist/integrations/linear/storage.js +1 -0
- package/dist/integrations/platform/api-client.d.ts +26 -0
- package/dist/integrations/platform/api-client.d.ts.map +1 -0
- package/dist/integrations/platform/api-client.js +156 -0
- package/dist/integrations/platform/api-client.js.map +1 -0
- package/dist/integrations/platform/github/event-worker.d.ts +49 -0
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -0
- package/dist/integrations/platform/github/event-worker.js +348 -0
- package/dist/integrations/platform/github/event-worker.js.map +1 -0
- package/dist/integrations/platform/github/integration.d.ts +50 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -0
- package/dist/integrations/platform/github/integration.js +961 -0
- package/dist/integrations/platform/github/integration.js.map +1 -0
- package/dist/integrations/platform/linear/integration.d.ts +46 -0
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -0
- package/dist/integrations/platform/linear/integration.js +483 -0
- package/dist/integrations/platform/linear/integration.js.map +1 -0
- package/dist/integrations/workos/integration.d.ts +39 -0
- package/dist/integrations/workos/integration.d.ts.map +1 -0
- package/dist/integrations/workos/integration.js +91 -0
- package/dist/integrations/workos/integration.js.map +1 -0
- package/dist/routes/config.d.ts +235 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +972 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/custom-provider-source.d.ts +52 -0
- package/dist/routes/custom-provider-source.d.ts.map +1 -0
- package/dist/routes/custom-provider-source.js +124 -0
- package/dist/routes/custom-provider-source.js.map +1 -0
- package/dist/routes/fs.d.ts +151 -0
- package/dist/routes/fs.d.ts.map +1 -0
- package/dist/routes/fs.js +708 -0
- package/dist/routes/fs.js.map +1 -0
- package/dist/routes/intake.d.ts +23 -0
- package/dist/routes/intake.d.ts.map +1 -0
- package/dist/routes/intake.js +179 -0
- package/dist/routes/intake.js.map +1 -0
- package/dist/routes/oauth.d.ts +43 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +463 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/projects.d.ts +19 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +461 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/provider-credentials.d.ts +81 -0
- package/dist/routes/provider-credentials.d.ts.map +1 -0
- package/dist/routes/provider-credentials.js +86 -0
- package/dist/routes/provider-credentials.js.map +1 -0
- package/dist/routes/route.d.ts +48 -0
- package/dist/routes/route.d.ts.map +1 -0
- package/dist/routes/route.js +15 -0
- package/dist/routes/route.js.map +1 -0
- package/dist/routes/skills.d.ts +30 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +168 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/routes/surface.d.ts +91 -0
- package/dist/routes/surface.d.ts.map +1 -0
- package/dist/routes/surface.js +260 -0
- package/dist/routes/surface.js.map +1 -0
- package/dist/routes/tenant-credentials.d.ts +74 -0
- package/dist/routes/tenant-credentials.d.ts.map +1 -0
- package/dist/routes/tenant-credentials.js +156 -0
- package/dist/routes/tenant-credentials.js.map +1 -0
- package/dist/routes/work-items.d.ts +40 -0
- package/dist/routes/work-items.d.ts.map +1 -0
- package/dist/routes/work-items.js +695 -0
- package/dist/routes/work-items.js.map +1 -0
- package/dist/rules/binding-context.d.ts +5 -0
- package/dist/rules/binding-context.d.ts.map +1 -0
- package/dist/rules/binding-context.js +28 -0
- package/dist/rules/binding-context.js.map +1 -0
- package/dist/rules/defaults.d.ts +9 -0
- package/dist/rules/defaults.d.ts.map +1 -0
- package/dist/rules/defaults.js +260 -0
- package/dist/rules/defaults.js.map +1 -0
- package/dist/rules/dispatcher.d.ts +42 -0
- package/dist/rules/dispatcher.d.ts.map +1 -0
- package/dist/rules/dispatcher.js +518 -0
- package/dist/rules/dispatcher.js.map +1 -0
- package/dist/rules/index.d.ts +7 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +5 -0
- package/dist/rules/processor.d.ts +54 -0
- package/dist/rules/processor.d.ts.map +1 -0
- package/dist/rules/processor.js +378 -0
- package/dist/rules/processor.js.map +1 -0
- package/dist/rules/resolve.d.ts +17 -0
- package/dist/rules/resolve.d.ts.map +1 -0
- package/dist/rules/resolve.js +30 -0
- package/dist/rules/resolve.js.map +1 -0
- package/dist/rules/start-coordinator.d.ts +60 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -0
- package/dist/rules/start-coordinator.js +194 -0
- package/dist/rules/start-coordinator.js.map +1 -0
- package/dist/rules/tools.d.ts +10 -0
- package/dist/rules/tools.d.ts.map +1 -0
- package/dist/rules/tools.js +58 -0
- package/dist/rules/tools.js.map +1 -0
- package/dist/rules/transition-service.d.ts +49 -0
- package/dist/rules/transition-service.d.ts.map +1 -0
- package/dist/rules/transition-service.js +232 -0
- package/dist/rules/transition-service.js.map +1 -0
- package/dist/rules/types.d.ts +234 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +38 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/validation.d.ts +11 -0
- package/dist/rules/validation.d.ts.map +1 -0
- package/dist/rules/validation.js +308 -0
- package/dist/rules/validation.js.map +1 -0
- package/dist/sandbox/fleet.d.ts +222 -0
- package/dist/sandbox/fleet.d.ts.map +1 -0
- package/dist/sandbox/fleet.js +322 -0
- package/dist/sandbox/fleet.js.map +1 -0
- package/dist/sandbox/reattach.d.ts +3 -0
- package/dist/sandbox/reattach.d.ts.map +1 -0
- package/dist/sandbox/reattach.js +16 -0
- package/dist/sandbox/reattach.js.map +1 -0
- package/dist/server-error.d.ts +12 -0
- package/dist/server-error.d.ts.map +1 -0
- package/dist/server-error.js +16 -0
- package/dist/server-error.js.map +1 -0
- package/dist/skills/service.d.ts +48 -0
- package/dist/skills/service.d.ts.map +1 -0
- package/dist/skills/service.js +40 -0
- package/dist/skills/service.js.map +1 -0
- package/dist/spa-static.d.ts +33 -0
- package/dist/spa-static.d.ts.map +1 -0
- package/dist/spa-static.js +104 -0
- package/dist/spa-static.js.map +1 -0
- package/dist/state-signing.d.ts +59 -0
- package/dist/state-signing.d.ts.map +1 -0
- package/dist/state-signing.js +83 -0
- package/dist/state-signing.js.map +1 -0
- package/dist/storage/domains/audit/agent-audit.d.ts +27 -0
- package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -0
- package/dist/storage/domains/audit/agent-audit.js +66 -0
- package/dist/storage/domains/audit/agent-audit.js.map +1 -0
- package/dist/storage/domains/audit/base.d.ts +140 -0
- package/dist/storage/domains/audit/base.d.ts.map +1 -0
- package/dist/storage/domains/audit/base.js +184 -0
- package/dist/storage/domains/audit/base.js.map +1 -0
- package/dist/storage/domains/audit/domain.d.ts +69 -0
- package/dist/storage/domains/audit/domain.d.ts.map +1 -0
- package/dist/storage/domains/audit/domain.js +167 -0
- package/dist/storage/domains/audit/domain.js.map +1 -0
- package/dist/storage/domains/channel-identity/base.d.ts +96 -0
- package/dist/storage/domains/channel-identity/base.d.ts.map +1 -0
- package/dist/storage/domains/channel-identity/base.js +149 -0
- package/dist/storage/domains/channel-identity/base.js.map +1 -0
- package/dist/storage/domains/credentials/base.d.ts +134 -0
- package/dist/storage/domains/credentials/base.d.ts.map +1 -0
- package/dist/storage/domains/credentials/base.js +273 -0
- package/dist/storage/domains/credentials/base.js.map +1 -0
- package/dist/storage/domains/custom-providers/base.d.ts +57 -0
- package/dist/storage/domains/custom-providers/base.d.ts.map +1 -0
- package/dist/storage/domains/custom-providers/base.js +145 -0
- package/dist/storage/domains/custom-providers/base.js.map +1 -0
- package/dist/storage/domains/intake/base.d.ts +38 -0
- package/dist/storage/domains/intake/base.d.ts.map +1 -0
- package/dist/storage/domains/intake/base.js +80 -0
- package/dist/storage/domains/intake/base.js.map +1 -0
- package/dist/storage/domains/integrations/base.d.ts +126 -0
- package/dist/storage/domains/integrations/base.d.ts.map +1 -0
- package/dist/storage/domains/integrations/base.js +317 -0
- package/dist/storage/domains/integrations/base.js.map +1 -0
- package/dist/storage/domains/memory-settings/base.d.ts +62 -0
- package/dist/storage/domains/memory-settings/base.d.ts.map +1 -0
- package/dist/storage/domains/memory-settings/base.js +126 -0
- package/dist/storage/domains/memory-settings/base.js.map +1 -0
- package/dist/storage/domains/model-packs/base.d.ts +49 -0
- package/dist/storage/domains/model-packs/base.d.ts.map +1 -0
- package/dist/storage/domains/model-packs/base.js +96 -0
- package/dist/storage/domains/model-packs/base.js.map +1 -0
- package/dist/storage/domains/projects/base.d.ts +58 -0
- package/dist/storage/domains/projects/base.d.ts.map +1 -0
- package/dist/storage/domains/projects/base.js +111 -0
- package/dist/storage/domains/projects/base.js.map +1 -0
- package/dist/storage/domains/queue-health/base.d.ts +52 -0
- package/dist/storage/domains/queue-health/base.d.ts.map +1 -0
- package/dist/storage/domains/queue-health/base.js +122 -0
- package/dist/storage/domains/queue-health/base.js.map +1 -0
- package/dist/storage/domains/source-control/base.d.ts +358 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -0
- package/dist/storage/domains/source-control/base.js +908 -0
- package/dist/storage/domains/source-control/base.js.map +1 -0
- package/dist/storage/domains/source-control/inmemory.d.ts +175 -0
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -0
- package/dist/storage/domains/source-control/inmemory.js +377 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -0
- package/dist/storage/domains/work-items/base.d.ts +412 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -0
- package/dist/storage/domains/work-items/base.js +1309 -0
- package/dist/storage/domains/work-items/base.js.map +1 -0
- package/dist/storage/domains/work-items/metrics.d.ts +101 -0
- package/dist/storage/domains/work-items/metrics.d.ts.map +1 -0
- package/dist/storage/domains/work-items/metrics.js +221 -0
- package/dist/storage/domains/work-items/metrics.js.map +1 -0
- package/dist/timing.d.ts +15 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +34 -0
- package/dist/timing.js.map +1 -0
- package/dist/workspace.d.ts +24 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +286 -0
- package/dist/workspace.js.map +1 -0
- package/factory-skills/configure-factory-rules/SKILL.md +67 -0
- package/factory-skills/factory-plan/SKILL.md +61 -0
- package/factory-skills/factory-review/SKILL.md +155 -0
- package/factory-skills/factory-triage/SKILL.md +77 -0
- package/package.json +81 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { listPullRequestSubscriptionsForWebhook, retirePullRequestSubscription } from "../../github/subscriptions.js";
|
|
2
|
+
import { dispatchGithubWebhook } from "../../github/webhook.js";
|
|
3
|
+
import { PlatformApiError } from "../api-client.js";
|
|
4
|
+
import { randomUUID } from "crypto";
|
|
5
|
+
import { NoopLeaseProvider, isLeaseProvider } from "@mastra/core/events";
|
|
6
|
+
import { MastraWorker } from "@mastra/core/worker";
|
|
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 DEFAULT_RECONCILE_INTERVAL_MS = 5 * 6e4;
|
|
11
|
+
const EVENT_PAGE_SIZE = 500;
|
|
12
|
+
const MIN_LEASE_TTL_MS = 3e4;
|
|
13
|
+
const CURSOR_ORG_ID = "__platform_github_event_worker__";
|
|
14
|
+
const CURSOR_USER_ID = "worker";
|
|
15
|
+
const SUPPORTED_EVENTS = /* @__PURE__ */ new Set([
|
|
16
|
+
"issues",
|
|
17
|
+
"issue_comment",
|
|
18
|
+
"pull_request",
|
|
19
|
+
"pull_request_review",
|
|
20
|
+
"pull_request_review_comment"
|
|
21
|
+
]);
|
|
22
|
+
const AUTHOR_GATED_KINDS = /* @__PURE__ */ new Set([
|
|
23
|
+
"issue-comment",
|
|
24
|
+
"pull-request-comment",
|
|
25
|
+
"pull-request-review",
|
|
26
|
+
"pull-request-review-comment"
|
|
27
|
+
]);
|
|
28
|
+
const AUTHORIZED_BOTS = /* @__PURE__ */ new Set(["coderabbitai[bot]", "devin-ai-integration[bot]"]);
|
|
29
|
+
const AUTHORIZED_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
30
|
+
"admin",
|
|
31
|
+
"maintain",
|
|
32
|
+
"write"
|
|
33
|
+
]);
|
|
34
|
+
const PERMISSION_CHECK_TIMEOUT_MS = 5e3;
|
|
35
|
+
var PlatformGithubEventWorker = class extends MastraWorker {
|
|
36
|
+
name = "platform-github-events";
|
|
37
|
+
#client;
|
|
38
|
+
#controller;
|
|
39
|
+
#github;
|
|
40
|
+
#storage;
|
|
41
|
+
#ingestFactoryEvent;
|
|
42
|
+
#reconcileFactoryState;
|
|
43
|
+
#pollEventsEnabled;
|
|
44
|
+
#reconcileIntervalMs;
|
|
45
|
+
#intervalMs;
|
|
46
|
+
#now;
|
|
47
|
+
#dispatch;
|
|
48
|
+
#leaseOwner = randomUUID();
|
|
49
|
+
#running = false;
|
|
50
|
+
#timer;
|
|
51
|
+
#leaseRenewalTimer;
|
|
52
|
+
#inFlight;
|
|
53
|
+
#leaseProvider = NoopLeaseProvider;
|
|
54
|
+
#leaseTtlMs;
|
|
55
|
+
#hasLease = false;
|
|
56
|
+
#startedAt = 0;
|
|
57
|
+
#lastReconcileAt = 0;
|
|
58
|
+
#settings = {
|
|
59
|
+
version: 1,
|
|
60
|
+
repositories: {}
|
|
61
|
+
};
|
|
62
|
+
constructor(config) {
|
|
63
|
+
super();
|
|
64
|
+
this.#client = config.client;
|
|
65
|
+
this.#controller = config.controller;
|
|
66
|
+
this.#github = config.github;
|
|
67
|
+
this.#storage = config.storage;
|
|
68
|
+
this.#ingestFactoryEvent = config.ingestFactoryEvent;
|
|
69
|
+
this.#reconcileFactoryState = config.reconcileFactoryState;
|
|
70
|
+
this.#pollEventsEnabled = config.pollEventsEnabled ?? true;
|
|
71
|
+
this.#reconcileIntervalMs = config.reconcileIntervalMs ?? DEFAULT_RECONCILE_INTERVAL_MS;
|
|
72
|
+
this.#intervalMs = config.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
73
|
+
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) throw new Error("Platform GitHub event polling interval must be a positive number.");
|
|
74
|
+
this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);
|
|
75
|
+
this.#now = config.now ?? Date.now;
|
|
76
|
+
this.#dispatch = config.dispatch ?? dispatchGithubWebhook;
|
|
77
|
+
}
|
|
78
|
+
async init(deps) {
|
|
79
|
+
await super.init(deps);
|
|
80
|
+
this.#leaseProvider = getLeaseProvider(deps.pubsub);
|
|
81
|
+
}
|
|
82
|
+
async start() {
|
|
83
|
+
if (this.#running) return;
|
|
84
|
+
if (!this.deps) throw new Error("PlatformGithubEventWorker: call init() before start()");
|
|
85
|
+
this.#startedAt = this.#now() - 1;
|
|
86
|
+
this.#settings = normalizeSettings(await this.#storage.settings.get(CURSOR_ORG_ID, CURSOR_USER_ID));
|
|
87
|
+
this.#running = true;
|
|
88
|
+
this.deps.logger.info("Platform GitHub event polling started", {
|
|
89
|
+
intervalMs: this.#intervalMs,
|
|
90
|
+
leaseTtlMs: this.#leaseTtlMs
|
|
91
|
+
});
|
|
92
|
+
this.#schedule(0);
|
|
93
|
+
}
|
|
94
|
+
async stop() {
|
|
95
|
+
if (!this.#running) return;
|
|
96
|
+
this.#running = false;
|
|
97
|
+
if (this.#timer) clearTimeout(this.#timer);
|
|
98
|
+
this.#timer = void 0;
|
|
99
|
+
this.#stopLeaseRenewal();
|
|
100
|
+
await this.#inFlight;
|
|
101
|
+
if (this.#hasLease) {
|
|
102
|
+
await this.#leaseProvider.releaseLease(this.#leaseKey(), this.#leaseOwner).catch(() => void 0);
|
|
103
|
+
this.#hasLease = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
get isRunning() {
|
|
107
|
+
return this.#running;
|
|
108
|
+
}
|
|
109
|
+
#schedule(delayMs) {
|
|
110
|
+
if (!this.#running) return;
|
|
111
|
+
this.#timer = setTimeout(() => {
|
|
112
|
+
this.#timer = void 0;
|
|
113
|
+
const run = this.#tick();
|
|
114
|
+
this.#inFlight = run;
|
|
115
|
+
run.finally(() => {
|
|
116
|
+
if (this.#inFlight === run) this.#inFlight = void 0;
|
|
117
|
+
});
|
|
118
|
+
}, delayMs);
|
|
119
|
+
this.#timer.unref?.();
|
|
120
|
+
}
|
|
121
|
+
async #tick() {
|
|
122
|
+
let nextDelay = this.#intervalMs;
|
|
123
|
+
try {
|
|
124
|
+
if (!await this.#ensureLease()) return;
|
|
125
|
+
nextDelay = await this.#poll();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
nextDelay = retryDelay(error, this.#intervalMs);
|
|
128
|
+
this.deps?.logger.error("Platform GitHub event polling cycle failed", {
|
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
130
|
+
retryInMs: nextDelay
|
|
131
|
+
});
|
|
132
|
+
} finally {
|
|
133
|
+
this.#schedule(nextDelay);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async #ensureLease() {
|
|
137
|
+
if (this.#hasLease) return true;
|
|
138
|
+
const result = await this.#leaseProvider.acquireLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs);
|
|
139
|
+
this.#hasLease = result.acquired;
|
|
140
|
+
if (this.#hasLease) this.#startLeaseRenewal();
|
|
141
|
+
return this.#hasLease;
|
|
142
|
+
}
|
|
143
|
+
#startLeaseRenewal() {
|
|
144
|
+
if (this.#leaseRenewalTimer) return;
|
|
145
|
+
this.#leaseRenewalTimer = setInterval(() => {
|
|
146
|
+
this.#leaseProvider.renewLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs).then((renewed) => {
|
|
147
|
+
if (!renewed) {
|
|
148
|
+
this.#hasLease = false;
|
|
149
|
+
this.#stopLeaseRenewal();
|
|
150
|
+
}
|
|
151
|
+
}).catch((error) => {
|
|
152
|
+
this.#hasLease = false;
|
|
153
|
+
this.#stopLeaseRenewal();
|
|
154
|
+
this.deps?.logger.warn("Platform GitHub event polling lease renewal failed", { error: error instanceof Error ? error.message : String(error) });
|
|
155
|
+
});
|
|
156
|
+
}, Math.floor(this.#leaseTtlMs / 3));
|
|
157
|
+
this.#leaseRenewalTimer.unref?.();
|
|
158
|
+
}
|
|
159
|
+
#stopLeaseRenewal() {
|
|
160
|
+
if (this.#leaseRenewalTimer) clearInterval(this.#leaseRenewalTimer);
|
|
161
|
+
this.#leaseRenewalTimer = void 0;
|
|
162
|
+
}
|
|
163
|
+
async #poll() {
|
|
164
|
+
const repositories = await this.#discoverRepositories();
|
|
165
|
+
let retryInMs = this.#pollEventsEnabled ? this.#intervalMs : this.#reconcileIntervalMs;
|
|
166
|
+
if (this.#pollEventsEnabled) for (const repository of repositories) {
|
|
167
|
+
if (!this.#running || !this.#hasLease) break;
|
|
168
|
+
try {
|
|
169
|
+
await this.#pollRepository(repository.id);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
const delay = retryDelay(error, this.#intervalMs);
|
|
172
|
+
retryInMs = Math.max(retryInMs, delay);
|
|
173
|
+
this.deps?.logger.error("Platform GitHub repository event polling failed", {
|
|
174
|
+
repositoryId: repository.id,
|
|
175
|
+
error: error instanceof Error ? error.message : String(error),
|
|
176
|
+
retryInMs: delay
|
|
177
|
+
});
|
|
178
|
+
if (error instanceof PlatformApiError && error.status === 429) break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
await this.#maybeReconcile(repositories);
|
|
182
|
+
return retryInMs;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* State-based safety net: event tailing can miss merges (cursor gaps,
|
|
186
|
+
* downtime, terminally failed decisions), so on a slower cadence we compare
|
|
187
|
+
* still-open PR cards against actual GitHub state and replay missed merges
|
|
188
|
+
* through the normal ingress, which dedupes against the event path.
|
|
189
|
+
*/
|
|
190
|
+
async #maybeReconcile(repositories) {
|
|
191
|
+
if (!this.#reconcileFactoryState || !this.#running || !this.#hasLease) return;
|
|
192
|
+
const now = this.#now();
|
|
193
|
+
if (now - this.#lastReconcileAt < this.#reconcileIntervalMs) return;
|
|
194
|
+
this.#lastReconcileAt = now;
|
|
195
|
+
const targets = repositories.flatMap((repository) => repository.fullName ? [{
|
|
196
|
+
id: repository.id,
|
|
197
|
+
fullName: repository.fullName,
|
|
198
|
+
installationId: repository.installationId
|
|
199
|
+
}] : []);
|
|
200
|
+
if (targets.length === 0) {
|
|
201
|
+
this.deps?.logger.debug("Platform GitHub pull request reconcile skipped: no named repositories");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
this.deps?.logger.debug("Platform GitHub pull request reconcile sweep starting", { candidateRepositories: targets.length });
|
|
205
|
+
const startedAt = Date.now();
|
|
206
|
+
try {
|
|
207
|
+
const { errors, ...counts } = await this.#reconcileFactoryState(targets);
|
|
208
|
+
const context = {
|
|
209
|
+
...counts,
|
|
210
|
+
candidateRepositories: targets.length,
|
|
211
|
+
durationMs: Date.now() - startedAt
|
|
212
|
+
};
|
|
213
|
+
if (counts.failed > 0) this.deps?.logger.warn("Platform GitHub pull request reconcile sweep completed with failures", {
|
|
214
|
+
...context,
|
|
215
|
+
errors
|
|
216
|
+
});
|
|
217
|
+
else if (counts.merged > 0 || counts.closed > 0) this.deps?.logger.info("Platform GitHub pull request reconcile replayed missed merges/closes", context);
|
|
218
|
+
else this.deps?.logger.info("Platform GitHub pull request reconcile sweep completed", context);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
this.deps?.logger.error("Platform GitHub pull request reconcile failed", {
|
|
221
|
+
repositories: targets.length,
|
|
222
|
+
durationMs: Date.now() - startedAt,
|
|
223
|
+
error: error instanceof Error ? error.message : String(error)
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async #discoverRepositories() {
|
|
228
|
+
const result = await this.#client.request("GET", `${API_PREFIX}/installations`);
|
|
229
|
+
const repositories = /* @__PURE__ */ new Map();
|
|
230
|
+
for (const installation of result.installations) {
|
|
231
|
+
if (!installation.usable || installation.suspendedAt) continue;
|
|
232
|
+
const page = await this.#client.request("GET", `${API_PREFIX}/installations/${installation.installationId}/repositories`);
|
|
233
|
+
for (const repository of page.repositories) repositories.set(repository.id, {
|
|
234
|
+
...repository,
|
|
235
|
+
installationId: installation.installationId
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return [...repositories.values()];
|
|
239
|
+
}
|
|
240
|
+
async #pollRepository(repositoryId) {
|
|
241
|
+
const key = String(repositoryId);
|
|
242
|
+
if (!this.#settings.repositories[key]) {
|
|
243
|
+
this.#settings.repositories[key] = { afterTimestamp: this.#startedAt };
|
|
244
|
+
await this.#saveSettings();
|
|
245
|
+
}
|
|
246
|
+
while (this.#running && this.#hasLease) {
|
|
247
|
+
const cursor = this.#settings.repositories[key];
|
|
248
|
+
const query = new URLSearchParams({ limit: String(EVENT_PAGE_SIZE) });
|
|
249
|
+
if ("afterEventId" in cursor) query.set("afterEventId", cursor.afterEventId);
|
|
250
|
+
else query.set("afterTimestamp", String(cursor.afterTimestamp));
|
|
251
|
+
const pollStartedAt = performance.now();
|
|
252
|
+
const page = await this.#client.request("GET", `${API_PREFIX}/repositories/${repositoryId}/events?${query}`);
|
|
253
|
+
this.deps?.logger.debug("Platform GitHub repository event poll completed", {
|
|
254
|
+
repositoryId,
|
|
255
|
+
eventCount: page.events.length,
|
|
256
|
+
latencyMs: Math.round(performance.now() - pollStartedAt)
|
|
257
|
+
});
|
|
258
|
+
if (page.events.length === 0 || !page.nextCursor) return;
|
|
259
|
+
for (const event of page.events) {
|
|
260
|
+
if (!this.#running || !this.#hasLease) return;
|
|
261
|
+
const parsed = parseEvent(event);
|
|
262
|
+
if (!parsed) {
|
|
263
|
+
this.deps?.logger.warn("Platform GitHub event log returned a malformed event", {
|
|
264
|
+
repositoryId,
|
|
265
|
+
eventId: event.id
|
|
266
|
+
});
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (isFactoryClosureEvent(parsed)) await this.#ingestFactoryEvent?.(parsed);
|
|
270
|
+
const result = await this.#dispatch(parsed, {
|
|
271
|
+
controller: this.#controller,
|
|
272
|
+
listSubscriptions: (target, options) => listPullRequestSubscriptionsForWebhook(target, options, this.#github.integrationStorage),
|
|
273
|
+
retireSubscription: (id, status) => retirePullRequestSubscription(id, status, this.#github.integrationStorage),
|
|
274
|
+
isAuthorizedSender: (notification) => this.#isAuthorizedSender(notification),
|
|
275
|
+
onTargetError: (subscription, error) => {
|
|
276
|
+
this.deps?.logger.error("Platform GitHub event delivery failed for a subscription", {
|
|
277
|
+
subscriptionId: subscription.id,
|
|
278
|
+
resourceId: subscription.resourceId,
|
|
279
|
+
threadId: subscription.threadId,
|
|
280
|
+
error: error instanceof Error ? error.message : String(error)
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
if (result.failed > 0) throw new Error(`Platform GitHub event ${event.deliveryId} failed for ${result.failed} subscribed target(s).`);
|
|
285
|
+
}
|
|
286
|
+
if (page.nextCursor === ("afterEventId" in cursor ? cursor.afterEventId : void 0)) return;
|
|
287
|
+
this.#settings.repositories[key] = { afterEventId: page.nextCursor };
|
|
288
|
+
await this.#saveSettings();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async #isAuthorizedSender(notification) {
|
|
292
|
+
if (!AUTHOR_GATED_KINDS.has(notification.kind)) return true;
|
|
293
|
+
const sender = notification.metadata.sender;
|
|
294
|
+
const repository = notification.metadata.repository;
|
|
295
|
+
if (!sender || !repository) return false;
|
|
296
|
+
if (AUTHORIZED_BOTS.has(sender)) return true;
|
|
297
|
+
const abortController = new AbortController();
|
|
298
|
+
const timeout = setTimeout(() => abortController.abort(), PERMISSION_CHECK_TIMEOUT_MS);
|
|
299
|
+
try {
|
|
300
|
+
const permission = await this.#github.getRepositoryCollaboratorPermission(notification.metadata.installationId, repository, sender, abortController.signal);
|
|
301
|
+
return permission !== void 0 && AUTHORIZED_PERMISSIONS.has(permission);
|
|
302
|
+
} catch {
|
|
303
|
+
return false;
|
|
304
|
+
} finally {
|
|
305
|
+
clearTimeout(timeout);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async #saveSettings() {
|
|
309
|
+
await this.#storage.settings.save(CURSOR_ORG_ID, CURSOR_USER_ID, this.#settings);
|
|
310
|
+
}
|
|
311
|
+
#leaseKey() {
|
|
312
|
+
return `${this.name}:${this.#storage.integrationId}`;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
function getLeaseProvider(pubsub) {
|
|
316
|
+
const getProvider = pubsub.getLeaseProvider;
|
|
317
|
+
if (typeof getProvider === "function") return getProvider.call(pubsub) ?? NoopLeaseProvider;
|
|
318
|
+
return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;
|
|
319
|
+
}
|
|
320
|
+
function normalizeSettings(value) {
|
|
321
|
+
if (!value || value.version !== 1 || !value.repositories || typeof value.repositories !== "object") return {
|
|
322
|
+
version: 1,
|
|
323
|
+
repositories: {}
|
|
324
|
+
};
|
|
325
|
+
return {
|
|
326
|
+
version: 1,
|
|
327
|
+
repositories: { ...value.repositories }
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function isFactoryClosureEvent(event) {
|
|
331
|
+
return (event.event === "issues" || event.event === "pull_request") && event.payload.action === "closed";
|
|
332
|
+
}
|
|
333
|
+
function parseEvent(event) {
|
|
334
|
+
if (!event.id || !event.deliveryId || !SUPPORTED_EVENTS.has(event.event) || !event.payload || typeof event.payload !== "object" || Array.isArray(event.payload)) return null;
|
|
335
|
+
return {
|
|
336
|
+
event: event.event,
|
|
337
|
+
deliveryId: event.deliveryId,
|
|
338
|
+
payload: event.payload
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function retryDelay(error, fallbackMs) {
|
|
342
|
+
if (error instanceof PlatformApiError && error.status === 429 && error.retryAfterSeconds !== null) return Math.max(fallbackMs, error.retryAfterSeconds * 1e3);
|
|
343
|
+
return fallbackMs;
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
export { PlatformGithubEventWorker };
|
|
347
|
+
|
|
348
|
+
//# sourceMappingURL=event-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-worker.js","names":["#client","#controller","#github","#storage","#ingestFactoryEvent","#reconcileFactoryState","#pollEventsEnabled","#reconcileIntervalMs","#intervalMs","#now","#dispatch","#leaseOwner","#leaseTtlMs","#leaseProvider","#running","#startedAt","#settings","#schedule","#timer","#stopLeaseRenewal","#inFlight","#hasLease","#leaseKey","#tick","#ensureLease","#poll","#startLeaseRenewal","#leaseRenewalTimer","#discoverRepositories","#pollRepository","#maybeReconcile","#lastReconcileAt","#saveSettings","#isAuthorizedSender"],"sources":["../../../../src/integrations/platform/github/event-worker.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { MountedMastraCode } from '@mastra/code-sdk';\nimport { isLeaseProvider, NoopLeaseProvider } from '@mastra/core/events';\nimport type { LeaseProvider, PubSub } from '@mastra/core/events';\nimport { MastraWorker } from '@mastra/core/worker';\nimport type { WorkerDeps } from '@mastra/core/worker';\n\nimport type { IntegrationStorageHandle } from '../../../storage/domains/integrations/base.js';\nimport type { GithubRepositoryPermission } from '../../github/integration.js';\nimport type { GithubPullRequestReconciler, ReconcileRepository } from '../../github/rules.js';\nimport { listPullRequestSubscriptionsForWebhook, retirePullRequestSubscription } from '../../github/subscriptions.js';\nimport type { GithubSubscriptionStorage } from '../../github/subscriptions.js';\nimport { dispatchGithubWebhook } from '../../github/webhook.js';\nimport type { GithubWebhookNotification, ParsedGithubWebhook } from '../../github/webhook.js';\nimport type { PlatformApiClient } from '../api-client.js';\nimport { PlatformApiError } from '../api-client.js';\n\nconst API_PREFIX = '/v1/server/github-app';\nconst DEFAULT_POLL_INTERVAL_MS = 20_000;\nconst DEFAULT_RECONCILE_INTERVAL_MS = 5 * 60_000;\nconst EVENT_PAGE_SIZE = 500;\nconst MIN_LEASE_TTL_MS = 30_000;\nconst CURSOR_ORG_ID = '__platform_github_event_worker__';\nconst CURSOR_USER_ID = 'worker';\nconst SUPPORTED_EVENTS = new Set([\n 'issues',\n 'issue_comment',\n 'pull_request',\n 'pull_request_review',\n 'pull_request_review_comment',\n]);\nconst AUTHOR_GATED_KINDS = new Set([\n 'issue-comment',\n 'pull-request-comment',\n 'pull-request-review',\n 'pull-request-review-comment',\n]);\nconst AUTHORIZED_BOTS = new Set(['coderabbitai[bot]', 'devin-ai-integration[bot]']);\nconst AUTHORIZED_PERMISSIONS = new Set<GithubRepositoryPermission>(['admin', 'maintain', 'write']);\nconst PERMISSION_CHECK_TIMEOUT_MS = 5_000;\n\ntype EventCursor = { afterEventId: string } | { afterTimestamp: number };\ntype PlatformGithubEventWorkerSettings = {\n version: 1;\n repositories: Record<string, EventCursor>;\n};\n\nexport type PlatformGithubEventStorage = IntegrationStorageHandle<\n Record<string, unknown>,\n PlatformGithubEventWorkerSettings,\n Record<string, unknown>\n>;\n\ntype EventLogEntry = {\n id: string;\n deliveryId: string;\n event: string;\n payload: unknown;\n};\n\ntype Repository = { id: number; fullName?: string; installationId: number };\n\nexport interface PlatformGithubEventDispatchIntegration {\n readonly integrationStorage: GithubSubscriptionStorage;\n getRepositoryCollaboratorPermission(\n installationId: number,\n repoFullName: string,\n username: string,\n signal?: AbortSignal,\n ): Promise<GithubRepositoryPermission | undefined>;\n}\n\nexport interface PlatformGithubEventWorkerConfig {\n client: PlatformApiClient;\n controller: MountedMastraCode['controller'];\n github: PlatformGithubEventDispatchIntegration;\n storage: PlatformGithubEventStorage;\n ingestFactoryEvent?: (event: ParsedGithubWebhook) => Promise<unknown>;\n reconcileFactoryState?: GithubPullRequestReconciler;\n /** When false the worker skips event tailing and only runs the reconcile sweep. */\n pollEventsEnabled?: boolean;\n intervalMs?: number;\n reconcileIntervalMs?: number;\n now?: () => number;\n dispatch?: typeof dispatchGithubWebhook;\n}\n\nexport class PlatformGithubEventWorker extends MastraWorker {\n readonly name = 'platform-github-events';\n\n readonly #client: PlatformApiClient;\n readonly #controller: MountedMastraCode['controller'];\n readonly #github: PlatformGithubEventDispatchIntegration;\n readonly #storage: PlatformGithubEventStorage;\n readonly #ingestFactoryEvent: ((event: ParsedGithubWebhook) => Promise<unknown>) | undefined;\n readonly #reconcileFactoryState: GithubPullRequestReconciler | undefined;\n readonly #pollEventsEnabled: boolean;\n readonly #reconcileIntervalMs: number;\n readonly #intervalMs: number;\n readonly #now: () => number;\n readonly #dispatch: typeof dispatchGithubWebhook;\n readonly #leaseOwner = randomUUID();\n\n #running = false;\n #timer: ReturnType<typeof setTimeout> | undefined;\n #leaseRenewalTimer: ReturnType<typeof setInterval> | undefined;\n #inFlight: Promise<void> | undefined;\n #leaseProvider: LeaseProvider = NoopLeaseProvider;\n #leaseTtlMs: number;\n #hasLease = false;\n #startedAt = 0;\n #lastReconcileAt = 0;\n #settings: PlatformGithubEventWorkerSettings = { version: 1, repositories: {} };\n\n constructor(config: PlatformGithubEventWorkerConfig) {\n super();\n this.#client = config.client;\n this.#controller = config.controller;\n this.#github = config.github;\n this.#storage = config.storage;\n this.#ingestFactoryEvent = config.ingestFactoryEvent;\n this.#reconcileFactoryState = config.reconcileFactoryState;\n this.#pollEventsEnabled = config.pollEventsEnabled ?? true;\n this.#reconcileIntervalMs = config.reconcileIntervalMs ?? DEFAULT_RECONCILE_INTERVAL_MS;\n this.#intervalMs = config.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n throw new Error('Platform GitHub event polling interval must be a positive number.');\n }\n this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);\n this.#now = config.now ?? Date.now;\n this.#dispatch = config.dispatch ?? dispatchGithubWebhook;\n }\n\n async init(deps: WorkerDeps): Promise<void> {\n await super.init(deps);\n this.#leaseProvider = getLeaseProvider(deps.pubsub);\n }\n\n async start(): Promise<void> {\n if (this.#running) return;\n if (!this.deps) throw new Error('PlatformGithubEventWorker: call init() before start()');\n\n this.#startedAt = this.#now() - 1;\n this.#settings = normalizeSettings(await this.#storage.settings.get(CURSOR_ORG_ID, CURSOR_USER_ID));\n this.#running = true;\n this.deps.logger.info('Platform GitHub event polling started', {\n intervalMs: this.#intervalMs,\n leaseTtlMs: this.#leaseTtlMs,\n });\n this.#schedule(0);\n }\n\n async stop(): Promise<void> {\n if (!this.#running) return;\n this.#running = false;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n this.#stopLeaseRenewal();\n await this.#inFlight;\n if (this.#hasLease) {\n await this.#leaseProvider.releaseLease(this.#leaseKey(), this.#leaseOwner).catch(() => undefined);\n this.#hasLease = false;\n }\n }\n\n get isRunning(): boolean {\n return this.#running;\n }\n\n #schedule(delayMs: number): void {\n if (!this.#running) return;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n const run = this.#tick();\n this.#inFlight = run;\n void run.finally(() => {\n if (this.#inFlight === run) this.#inFlight = undefined;\n });\n }, delayMs);\n this.#timer.unref?.();\n }\n\n async #tick(): Promise<void> {\n let nextDelay = this.#intervalMs;\n try {\n if (!(await this.#ensureLease())) return;\n nextDelay = await this.#poll();\n } catch (error) {\n nextDelay = retryDelay(error, this.#intervalMs);\n this.deps?.logger.error('Platform GitHub event polling cycle failed', {\n error: error instanceof Error ? error.message : String(error),\n retryInMs: nextDelay,\n });\n } finally {\n this.#schedule(nextDelay);\n }\n }\n\n async #ensureLease(): Promise<boolean> {\n if (this.#hasLease) return true;\n const result = await this.#leaseProvider.acquireLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs);\n this.#hasLease = result.acquired;\n if (this.#hasLease) this.#startLeaseRenewal();\n return this.#hasLease;\n }\n\n #startLeaseRenewal(): void {\n if (this.#leaseRenewalTimer) return;\n this.#leaseRenewalTimer = setInterval(\n () => {\n void this.#leaseProvider\n .renewLease(this.#leaseKey(), this.#leaseOwner, this.#leaseTtlMs)\n .then(renewed => {\n if (!renewed) {\n this.#hasLease = false;\n this.#stopLeaseRenewal();\n }\n })\n .catch(error => {\n this.#hasLease = false;\n this.#stopLeaseRenewal();\n this.deps?.logger.warn('Platform GitHub event polling lease renewal failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n },\n Math.floor(this.#leaseTtlMs / 3),\n );\n this.#leaseRenewalTimer.unref?.();\n }\n\n #stopLeaseRenewal(): void {\n if (this.#leaseRenewalTimer) clearInterval(this.#leaseRenewalTimer);\n this.#leaseRenewalTimer = undefined;\n }\n\n async #poll(): Promise<number> {\n const repositories = await this.#discoverRepositories();\n // Reconcile-only mode has no event tail to keep fresh, so tick on the\n // slower reconcile cadence instead of the polling interval.\n let retryInMs = this.#pollEventsEnabled ? this.#intervalMs : this.#reconcileIntervalMs;\n\n if (this.#pollEventsEnabled) {\n for (const repository of repositories) {\n if (!this.#running || !this.#hasLease) break;\n try {\n await this.#pollRepository(repository.id);\n } catch (error) {\n const delay = retryDelay(error, this.#intervalMs);\n retryInMs = Math.max(retryInMs, delay);\n this.deps?.logger.error('Platform GitHub repository event polling failed', {\n repositoryId: repository.id,\n error: error instanceof Error ? error.message : String(error),\n retryInMs: delay,\n });\n if (error instanceof PlatformApiError && error.status === 429) break;\n }\n }\n }\n\n await this.#maybeReconcile(repositories);\n\n return retryInMs;\n }\n\n /**\n * State-based safety net: event tailing can miss merges (cursor gaps,\n * downtime, terminally failed decisions), so on a slower cadence we compare\n * still-open PR cards against actual GitHub state and replay missed merges\n * through the normal ingress, which dedupes against the event path.\n */\n async #maybeReconcile(repositories: Repository[]): Promise<void> {\n if (!this.#reconcileFactoryState || !this.#running || !this.#hasLease) return;\n const now = this.#now();\n if (now - this.#lastReconcileAt < this.#reconcileIntervalMs) return;\n // Advance the clock before sweeping so a persistently failing sweep stays\n // on cadence instead of retrying every poll tick.\n this.#lastReconcileAt = now;\n const targets: ReconcileRepository[] = repositories.flatMap(repository =>\n repository.fullName\n ? [{ id: repository.id, fullName: repository.fullName, installationId: repository.installationId }]\n : [],\n );\n if (targets.length === 0) {\n this.deps?.logger.debug('Platform GitHub pull request reconcile skipped: no named repositories');\n return;\n }\n this.deps?.logger.debug('Platform GitHub pull request reconcile sweep starting', {\n candidateRepositories: targets.length,\n });\n const startedAt = Date.now();\n try {\n // `counts.repositories` is the factory-configured subset actually swept;\n // `candidateRepositories` is everything the installations exposed.\n const { errors, ...counts } = await this.#reconcileFactoryState(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('Platform GitHub pull request reconcile sweep completed with failures', {\n ...context,\n errors,\n });\n } else if (counts.merged > 0 || counts.closed > 0) {\n this.deps?.logger.info('Platform GitHub pull request reconcile replayed missed merges/closes', context);\n } else {\n this.deps?.logger.info('Platform GitHub pull request reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.error('Platform GitHub pull request reconcile failed', {\n repositories: targets.length,\n durationMs: Date.now() - startedAt,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n async #discoverRepositories(): Promise<Repository[]> {\n const result = await this.#client.request<{\n installations: Array<{\n installationId: number;\n usable: boolean;\n suspendedAt: string | null;\n }>;\n }>('GET', `${API_PREFIX}/installations`);\n const repositories = new Map<number, Repository>();\n\n for (const installation of result.installations) {\n if (!installation.usable || installation.suspendedAt) continue;\n const page = await this.#client.request<{ repositories: Array<{ id: number; fullName?: string }> }>(\n 'GET',\n `${API_PREFIX}/installations/${installation.installationId}/repositories`,\n );\n for (const repository of page.repositories) {\n repositories.set(repository.id, { ...repository, installationId: installation.installationId });\n }\n }\n\n return [...repositories.values()];\n }\n\n async #pollRepository(repositoryId: number): Promise<void> {\n const key = String(repositoryId);\n if (!this.#settings.repositories[key]) {\n this.#settings.repositories[key] = { afterTimestamp: this.#startedAt };\n await this.#saveSettings();\n }\n\n while (this.#running && this.#hasLease) {\n const cursor: EventCursor = this.#settings.repositories[key]!;\n const query = new URLSearchParams({ limit: String(EVENT_PAGE_SIZE) });\n if ('afterEventId' in cursor) query.set('afterEventId', cursor.afterEventId);\n else query.set('afterTimestamp', String(cursor.afterTimestamp));\n\n const pollStartedAt = performance.now();\n const page = await this.#client.request<{ events: EventLogEntry[]; nextCursor: string | null }>(\n 'GET',\n `${API_PREFIX}/repositories/${repositoryId}/events?${query}`,\n );\n this.deps?.logger.debug('Platform GitHub repository event poll completed', {\n repositoryId,\n eventCount: page.events.length,\n latencyMs: Math.round(performance.now() - pollStartedAt),\n });\n if (page.events.length === 0 || !page.nextCursor) return;\n\n for (const event of page.events) {\n if (!this.#running || !this.#hasLease) return;\n const parsed = parseEvent(event);\n if (!parsed) {\n this.deps?.logger.warn('Platform GitHub event log returned a malformed event', {\n repositoryId,\n eventId: event.id,\n });\n continue;\n }\n if (isFactoryClosureEvent(parsed)) {\n await this.#ingestFactoryEvent?.(parsed);\n }\n const result = await this.#dispatch(parsed, {\n controller: this.#controller,\n listSubscriptions: (target, options) =>\n listPullRequestSubscriptionsForWebhook(target, options, this.#github.integrationStorage),\n retireSubscription: (id, status) =>\n retirePullRequestSubscription(id, status, this.#github.integrationStorage),\n isAuthorizedSender: notification => this.#isAuthorizedSender(notification),\n onTargetError: (subscription, error) => {\n this.deps?.logger.error('Platform GitHub event delivery failed for a subscription', {\n subscriptionId: subscription.id,\n resourceId: subscription.resourceId,\n threadId: subscription.threadId,\n error: error instanceof Error ? error.message : String(error),\n });\n },\n });\n if (result.failed > 0) {\n throw new Error(\n `Platform GitHub event ${event.deliveryId} failed for ${result.failed} subscribed target(s).`,\n );\n }\n }\n\n if (page.nextCursor === ('afterEventId' in cursor ? cursor.afterEventId : undefined)) return;\n this.#settings.repositories[key] = { afterEventId: page.nextCursor };\n await this.#saveSettings();\n }\n }\n\n async #isAuthorizedSender(notification: GithubWebhookNotification): Promise<boolean> {\n if (!AUTHOR_GATED_KINDS.has(notification.kind)) return true;\n const sender = notification.metadata.sender;\n const repository = notification.metadata.repository;\n if (!sender || !repository) return false;\n if (AUTHORIZED_BOTS.has(sender)) return true;\n\n const abortController = new AbortController();\n const timeout = setTimeout(() => abortController.abort(), PERMISSION_CHECK_TIMEOUT_MS);\n try {\n const permission = await this.#github.getRepositoryCollaboratorPermission(\n notification.metadata.installationId,\n repository,\n sender,\n abortController.signal,\n );\n return permission !== undefined && AUTHORIZED_PERMISSIONS.has(permission);\n } catch {\n return false;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n async #saveSettings(): Promise<void> {\n await this.#storage.settings.save(CURSOR_ORG_ID, CURSOR_USER_ID, this.#settings);\n }\n\n #leaseKey(): string {\n return `${this.name}:${this.#storage.integrationId}`;\n }\n}\n\nfunction getLeaseProvider(pubsub: PubSub): LeaseProvider {\n const getProvider = (pubsub as PubSub & { getLeaseProvider?: () => LeaseProvider | undefined }).getLeaseProvider;\n if (typeof getProvider === 'function') return getProvider.call(pubsub) ?? NoopLeaseProvider;\n return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;\n}\n\nfunction normalizeSettings(value: PlatformGithubEventWorkerSettings | null): PlatformGithubEventWorkerSettings {\n if (!value || value.version !== 1 || !value.repositories || typeof value.repositories !== 'object') {\n return { version: 1, repositories: {} };\n }\n return { version: 1, repositories: { ...value.repositories } };\n}\n\nfunction isFactoryClosureEvent(event: ParsedGithubWebhook): boolean {\n return (event.event === 'issues' || event.event === 'pull_request') && event.payload.action === 'closed';\n}\n\nfunction parseEvent(event: EventLogEntry): ParsedGithubWebhook | null {\n if (\n !event.id ||\n !event.deliveryId ||\n !SUPPORTED_EVENTS.has(event.event) ||\n !event.payload ||\n typeof event.payload !== 'object' ||\n Array.isArray(event.payload)\n ) {\n return null;\n }\n return {\n event: event.event,\n deliveryId: event.deliveryId,\n payload: event.payload as Record<string, unknown>,\n };\n}\n\nfunction retryDelay(error: unknown, fallbackMs: number): number {\n if (error instanceof PlatformApiError && error.status === 429 && error.retryAfterSeconds !== null) {\n return Math.max(fallbackMs, error.retryAfterSeconds * 1_000);\n }\n return fallbackMs;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { RequestContext } from '@mastra/core/request-context';
|
|
2
|
+
import type { ApiRoute } from '@mastra/core/server';
|
|
3
|
+
import type { Intake } from '../../../capabilities/intake.js';
|
|
4
|
+
import type { VersionControl } from '../../../capabilities/version-control.js';
|
|
5
|
+
import type { IntegrationStorageHandle } from '../../../storage/domains/integrations/base.js';
|
|
6
|
+
import type { SourceControlStorageHandle } from '../../../storage/domains/source-control/base.js';
|
|
7
|
+
import type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';
|
|
8
|
+
import type { GithubIntegration, GithubRepositoryPermission, RepoSummary } from '../../github/integration.js';
|
|
9
|
+
import type { GithubIssueTriageInput, GithubIssueTriageResult } from '../../github/issue-triage.js';
|
|
10
|
+
import type { ReconcilePullRequestState } from '../../github/rules.js';
|
|
11
|
+
import type { GithubSubscriptionStorage } from '../../github/subscriptions.js';
|
|
12
|
+
import { PlatformGithubEventWorker } from './event-worker.js';
|
|
13
|
+
export declare class PlatformGithubIntegration implements FactoryIntegration {
|
|
14
|
+
#private;
|
|
15
|
+
readonly id = "github";
|
|
16
|
+
readonly intake: Intake;
|
|
17
|
+
readonly versionControl: VersionControl;
|
|
18
|
+
constructor(options?: {
|
|
19
|
+
runIssueTriage?: (input: GithubIssueTriageInput) => Promise<GithubIssueTriageResult>;
|
|
20
|
+
});
|
|
21
|
+
get storage(): SourceControlStorageHandle;
|
|
22
|
+
get sourceControlStorage(): SourceControlStorageHandle;
|
|
23
|
+
get integrationStorage(): GithubSubscriptionStorage;
|
|
24
|
+
initialize({ storage }: {
|
|
25
|
+
storage: IntegrationStorageHandle;
|
|
26
|
+
}): void;
|
|
27
|
+
routes(ctx: IntegrationContext): ApiRoute[];
|
|
28
|
+
workers(ctx: IntegrationContext): PlatformGithubEventWorker[];
|
|
29
|
+
/**
|
|
30
|
+
* Reads live PR state through the Platform GitHub proxy for the merge
|
|
31
|
+
* reconciler. Returns undefined when the PR cannot be resolved (missing,
|
|
32
|
+
* proxy error) so a sweep never fabricates a merge.
|
|
33
|
+
*/
|
|
34
|
+
fetchPullRequestState(input: {
|
|
35
|
+
installationId: number;
|
|
36
|
+
repository: string;
|
|
37
|
+
number: number;
|
|
38
|
+
}): Promise<ReconcilePullRequestState | undefined>;
|
|
39
|
+
sessionTools({ requestContext }: {
|
|
40
|
+
requestContext: RequestContext;
|
|
41
|
+
}): IntegrationTools;
|
|
42
|
+
postToolObserver({ toolContext, requestContext, }: Parameters<NonNullable<FactoryIntegration['postToolObserver']>>[0]): Promise<void>;
|
|
43
|
+
diagnostics(): Record<string, unknown>;
|
|
44
|
+
getRepositoryCollaboratorPermission(_installationId: number, repoFullName: string, username: string, signal?: AbortSignal): Promise<GithubRepositoryPermission | undefined>;
|
|
45
|
+
listInstallationRepos(installationId: number): Promise<RepoSummary[]>;
|
|
46
|
+
mintInstallationToken(installationId: number): Promise<string>;
|
|
47
|
+
addIssueLabels(_installationId: number, sourceId: string, issueNumber: number, labels: string[]): Promise<string[]>;
|
|
48
|
+
getInstallationOctokit(_installationId: number): ReturnType<GithubIntegration['getInstallationOctokit']>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=integration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAwBV,cAAc,EACf,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAC9F,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,iDAAiD,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAIpG,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAMvE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAQ/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAyH9D,qBAAa,yBAA0B,YAAW,kBAAkB;;IAClE,QAAQ,CAAC,EAAE,YAAY;IAcvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAsHrB;IAEF,QAAQ,CAAC,cAAc,EAAE,cAAc,CA2HrC;gBAGA,OAAO,GAAE;QACP,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;KACjF;IAWR,IAAI,OAAO,IAAI,0BAA0B,CAGxC;IAED,IAAI,oBAAoB,IAAI,0BAA0B,CAErD;IAED,IAAI,kBAAkB,IAAI,yBAAyB,CAKlD;IAuBD,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,wBAAwB,CAAA;KAAE,GAAG,IAAI;IAUpE,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAkL3C,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,yBAAyB,EAAE;IAqB7D;;;;OAIG;IACG,qBAAqB,CAAC,KAAK,EAAE;QACjC,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAoClD,YAAY,CAAC,EAAE,cAAc,EAAE,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,gBAAgB;IAIhF,gBAAgB,CAAC,EACrB,WAAW,EACX,cAAc,GACf,EAAE,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrF,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYhC,mCAAmC,CACvC,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAoB5C,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BrE,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa9D,cAAc,CAClB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,MAAM,EAAE,CAAC;IASpB,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CA6WzG"}
|