@mastra/factory 0.2.0 → 0.2.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/capabilities/intake.d.ts +45 -0
- package/dist/capabilities/intake.d.ts.map +1 -1
- package/dist/factory.js +920 -549
- package/dist/factory.js.map +1 -1
- package/dist/index.js +920 -549
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +126 -11
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/project-lock.d.ts +24 -2
- package/dist/integrations/github/project-lock.d.ts.map +1 -1
- package/dist/integrations/github/project-lock.js +43 -10
- package/dist/integrations/github/project-lock.js.map +1 -1
- package/dist/integrations/github/routes.js +41 -10
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/linear/agent-tools.js.map +1 -1
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/integration.js +60 -1
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +7 -1
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +104 -12
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
- package/dist/integrations/platform/linear/integration.js +91 -0
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/routes/fs.d.ts +16 -0
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +103 -3
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/oauth.js +564 -478
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +1 -0
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +717 -526
- package/dist/routes/surface.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +0 -1
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +6 -7
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,EAGV,MAAM,
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"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"}
|
|
@@ -175,6 +175,34 @@ async function clearGithubPat(storage, orgId, kind = "default") {
|
|
|
175
175
|
// src/integrations/github/project-lock.ts
|
|
176
176
|
import { createHash } from "crypto";
|
|
177
177
|
var inProcessLocks = /* @__PURE__ */ new Map();
|
|
178
|
+
var DEFAULT_PROJECT_LOCK_TIMEOUT_MS = 6e4;
|
|
179
|
+
var ProjectLockTimeoutError = class extends Error {
|
|
180
|
+
key;
|
|
181
|
+
timeoutMs;
|
|
182
|
+
constructor(key, timeoutMs) {
|
|
183
|
+
super(`Project lock critical section for "${key}" exceeded ${timeoutMs}ms`);
|
|
184
|
+
this.name = "ProjectLockTimeoutError";
|
|
185
|
+
this.key = key;
|
|
186
|
+
this.timeoutMs = timeoutMs;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
async function runWithTimeout(key, timeoutMs, fn) {
|
|
190
|
+
const controller = new AbortController();
|
|
191
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
192
|
+
const abortError = new Promise((_, reject) => {
|
|
193
|
+
controller.signal.addEventListener("abort", () => reject(new ProjectLockTimeoutError(key, timeoutMs)), {
|
|
194
|
+
once: true
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
const work = fn(controller.signal);
|
|
198
|
+
work.catch(() => {
|
|
199
|
+
});
|
|
200
|
+
try {
|
|
201
|
+
return await Promise.race([work, abortError]);
|
|
202
|
+
} finally {
|
|
203
|
+
clearTimeout(timer);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
178
206
|
function hashKey(key) {
|
|
179
207
|
const digest = createHash("sha256").update(key).digest();
|
|
180
208
|
const a = digest.readInt32BE(0);
|
|
@@ -182,9 +210,9 @@ function hashKey(key) {
|
|
|
182
210
|
return [a, b];
|
|
183
211
|
}
|
|
184
212
|
function withProjectLock(options) {
|
|
185
|
-
const { key, storage, fn, pool } = options;
|
|
213
|
+
const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;
|
|
186
214
|
const prev = inProcessLocks.get(key) ?? Promise.resolve();
|
|
187
|
-
const run = () => withDbAdvisoryLock({ key, storage, fn, pool });
|
|
215
|
+
const run = () => withDbAdvisoryLock({ key, storage, fn, pool, timeoutMs });
|
|
188
216
|
const next = prev.then(run, run);
|
|
189
217
|
const tail = next.then(
|
|
190
218
|
() => void 0,
|
|
@@ -199,28 +227,31 @@ function withProjectLock(options) {
|
|
|
199
227
|
return next;
|
|
200
228
|
}
|
|
201
229
|
async function withDbAdvisoryLock(options) {
|
|
202
|
-
const { key, storage, fn, pool } = options;
|
|
230
|
+
const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;
|
|
203
231
|
if (process.env.MASTRACODE_DISTRIBUTED_LOCK === "0") {
|
|
204
|
-
return fn
|
|
232
|
+
return runWithTimeout(key, timeoutMs, fn);
|
|
205
233
|
}
|
|
206
|
-
if (pool) return advisoryLockOver(pool, key, fn);
|
|
234
|
+
if (pool) return advisoryLockOver(pool, key, timeoutMs, fn);
|
|
207
235
|
if (typeof storage?.withDistributedLock !== "function") {
|
|
208
|
-
return fn
|
|
236
|
+
return runWithTimeout(key, timeoutMs, fn);
|
|
209
237
|
}
|
|
210
|
-
return storage.withDistributedLock(key, fn);
|
|
238
|
+
return storage.withDistributedLock(key, () => runWithTimeout(key, timeoutMs, fn));
|
|
211
239
|
}
|
|
212
|
-
async function advisoryLockOver(pool, key, fn) {
|
|
240
|
+
async function advisoryLockOver(pool, key, timeoutMs, fn) {
|
|
213
241
|
const [k1, k2] = hashKey(key);
|
|
214
242
|
const client = await pool.connect();
|
|
215
243
|
try {
|
|
216
244
|
await client.query("BEGIN");
|
|
217
245
|
await client.query("SELECT pg_advisory_xact_lock($1, $2)", [k1, k2]);
|
|
218
246
|
try {
|
|
219
|
-
const result = await fn
|
|
247
|
+
const result = await runWithTimeout(key, timeoutMs, fn);
|
|
220
248
|
await client.query("COMMIT");
|
|
221
249
|
return result;
|
|
222
250
|
} catch (err) {
|
|
223
|
-
|
|
251
|
+
try {
|
|
252
|
+
await client.query("ROLLBACK");
|
|
253
|
+
} catch {
|
|
254
|
+
}
|
|
224
255
|
throw err;
|
|
225
256
|
}
|
|
226
257
|
} finally {
|
|
@@ -2215,6 +2246,7 @@ var GithubIntegration = class {
|
|
|
2215
2246
|
/** Stable integration identifier (see `../factory-integration.ts`). */
|
|
2216
2247
|
id = "github";
|
|
2217
2248
|
intake = {
|
|
2249
|
+
resolveIntakeDispatch: (input) => this.#resolveIntakeDispatch(input),
|
|
2218
2250
|
listSources: async ({ orgId }) => {
|
|
2219
2251
|
const installations = await this.sourceControlStorage.installations.list({ orgId });
|
|
2220
2252
|
const repositories = await Promise.all(
|
|
@@ -2295,7 +2327,8 @@ var GithubIntegration = class {
|
|
|
2295
2327
|
},
|
|
2296
2328
|
listIssues: (input) => this.#listIntakeIssues(input),
|
|
2297
2329
|
getIssue: (input) => this.#getIntakeIssue(input),
|
|
2298
|
-
createComment: (input) => this.#createIntakeComment(input)
|
|
2330
|
+
createComment: (input) => this.#createIntakeComment(input),
|
|
2331
|
+
updateIssue: (input) => this.#updateIntakeIssue(input)
|
|
2299
2332
|
};
|
|
2300
2333
|
versionControl = {
|
|
2301
2334
|
initialize: ({ storage }) => {
|
|
@@ -2407,6 +2440,28 @@ var GithubIntegration = class {
|
|
|
2407
2440
|
if (!this.#storage) throw new Error("GithubIntegration storage has not been initialized.");
|
|
2408
2441
|
return this.#storage.generic;
|
|
2409
2442
|
}
|
|
2443
|
+
/** Resolve a stored GitHub locator without scanning installations or repositories. */
|
|
2444
|
+
async #resolveIntakeDispatch({
|
|
2445
|
+
orgId,
|
|
2446
|
+
externalSource
|
|
2447
|
+
}) {
|
|
2448
|
+
const target = parseGithubExternalTarget(externalSource.externalId);
|
|
2449
|
+
if (!target) return null;
|
|
2450
|
+
const repository = await this.sourceControlStorage.repositories.findByExternalId({
|
|
2451
|
+
orgId,
|
|
2452
|
+
externalId: target.repositoryId
|
|
2453
|
+
});
|
|
2454
|
+
if (!repository) return null;
|
|
2455
|
+
const installation = await this.sourceControlStorage.installations.get({ orgId, id: repository.installationId });
|
|
2456
|
+
if (!installation) return null;
|
|
2457
|
+
const installationId = Number.parseInt(installation.externalId, 10);
|
|
2458
|
+
if (!Number.isSafeInteger(installationId)) return null;
|
|
2459
|
+
return {
|
|
2460
|
+
connection: { type: "app-installation", installationId },
|
|
2461
|
+
sourceId: repository.slug,
|
|
2462
|
+
issueId: target.issueId
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2410
2465
|
/** Secret GitHub uses to sign webhook deliveries, when configured. */
|
|
2411
2466
|
get webhookSecret() {
|
|
2412
2467
|
return this.#webhookSecret;
|
|
@@ -2593,6 +2648,59 @@ var GithubIntegration = class {
|
|
|
2593
2648
|
throw err;
|
|
2594
2649
|
}
|
|
2595
2650
|
}
|
|
2651
|
+
async #updateIntakeIssue(input) {
|
|
2652
|
+
const installationId = getGithubInstallationId(input.connection);
|
|
2653
|
+
const repoFullName = requireSourceId(input.sourceId, "GitHub Intake requires a repository source.");
|
|
2654
|
+
const parts = splitRepoFullName(repoFullName);
|
|
2655
|
+
const issueNumber = parsePositiveInteger(input.issueId);
|
|
2656
|
+
if (!parts || issueNumber === null) return null;
|
|
2657
|
+
if (input.state.kind === "byName") {
|
|
2658
|
+
console.warn(`GitHub integration: updateIssue byName is not supported (name=${input.state.name}); ignoring.`);
|
|
2659
|
+
return null;
|
|
2660
|
+
}
|
|
2661
|
+
const targetState = input.state.stateType === "unstarted" || input.state.stateType === "started" ? "open" : "closed";
|
|
2662
|
+
const stateReason = targetState === "closed" ? input.state.stateType === "canceled" ? "not_planned" : "completed" : null;
|
|
2663
|
+
const octokit = this.getInstallationOctokit(installationId);
|
|
2664
|
+
try {
|
|
2665
|
+
const { data: current } = await octokit.issues.get({
|
|
2666
|
+
owner: parts.owner,
|
|
2667
|
+
repo: parts.repo,
|
|
2668
|
+
issue_number: issueNumber
|
|
2669
|
+
});
|
|
2670
|
+
if (current.pull_request) {
|
|
2671
|
+
console.warn(
|
|
2672
|
+
`GitHub integration: updateIssue rejected \u2014 target ${repoFullName}#${issueNumber} is a pull request.`
|
|
2673
|
+
);
|
|
2674
|
+
return null;
|
|
2675
|
+
}
|
|
2676
|
+
const { data: issue } = await octokit.issues.update({
|
|
2677
|
+
owner: parts.owner,
|
|
2678
|
+
repo: parts.repo,
|
|
2679
|
+
issue_number: issueNumber,
|
|
2680
|
+
state: targetState,
|
|
2681
|
+
...stateReason ? { state_reason: stateReason } : {}
|
|
2682
|
+
});
|
|
2683
|
+
return {
|
|
2684
|
+
id: String(issue.number),
|
|
2685
|
+
identifier: `#${issue.number}`,
|
|
2686
|
+
title: issue.title,
|
|
2687
|
+
url: issue.html_url,
|
|
2688
|
+
author: issue.user?.login ?? null,
|
|
2689
|
+
state: issue.state,
|
|
2690
|
+
stateType: issue.state,
|
|
2691
|
+
priority: null,
|
|
2692
|
+
assignee: issue.assignee?.login ?? null,
|
|
2693
|
+
source: repoFullName,
|
|
2694
|
+
labels: issue.labels.map((label) => typeof label === "string" ? label : label.name ?? "").filter(Boolean),
|
|
2695
|
+
commentCount: issue.comments,
|
|
2696
|
+
createdAt: issue.created_at,
|
|
2697
|
+
updatedAt: issue.updated_at
|
|
2698
|
+
};
|
|
2699
|
+
} catch (err) {
|
|
2700
|
+
if (isNotFoundError(err)) return null;
|
|
2701
|
+
throw err;
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2596
2704
|
async #createIntakeComment(input) {
|
|
2597
2705
|
const installationId = getGithubInstallationId(input.connection);
|
|
2598
2706
|
const repoFullName = requireSourceId(input.sourceId, "GitHub Intake requires a repository source.");
|
|
@@ -3133,6 +3241,13 @@ function splitRepoFullName(repoFullName) {
|
|
|
3133
3241
|
if (slash <= 0 || slash === repoFullName.length - 1) return null;
|
|
3134
3242
|
return { owner: repoFullName.slice(0, slash), repo: repoFullName.slice(slash + 1) };
|
|
3135
3243
|
}
|
|
3244
|
+
function parseGithubExternalTarget(externalId) {
|
|
3245
|
+
const match = externalId.match(/^github:(\d+):(?:issue|pull-request):(\d+)$/) ?? externalId.match(/^(\d+):(\d+)$/);
|
|
3246
|
+
if (!match?.[1] || !match[2]) return null;
|
|
3247
|
+
const repositoryId = parsePositiveInteger(match[1]);
|
|
3248
|
+
const issueId = parsePositiveInteger(match[2]);
|
|
3249
|
+
return repositoryId && issueId ? { repositoryId: String(repositoryId), issueId: String(issueId) } : null;
|
|
3250
|
+
}
|
|
3136
3251
|
export {
|
|
3137
3252
|
GithubIntegration,
|
|
3138
3253
|
LIST_PAGE_SIZE,
|