@mastra/factory 0.2.2-alpha.0 → 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 +36 -0
- package/dist/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +401 -314
- 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.d.ts.map +1 -1
- package/dist/factory.js +441 -39455
- package/dist/factory.js.map +1 -1
- package/dist/index.js +2 -39466
- 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 -3624
- 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.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +1272 -1833
- 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.d.ts +2 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +401 -326
- 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.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +845 -3942
- 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 -915
- 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 -28618
- 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.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +438 -677
- 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.d.ts.map +1 -1
- package/dist/spa-static.js +91 -64
- 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.d.ts +9 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +777 -702
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +322 -344
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +1266 -1132
- 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.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 +2 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +236 -438
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-review/SKILL.md +9 -2
- package/package.json +9 -9
- 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,242 +1,239 @@
|
|
|
1
|
-
|
|
1
|
+
import { LinearReauthRequiredError } from "./integration.js";
|
|
2
2
|
import { registerApiRoute } from "@mastra/core/server";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
|
|
8
|
-
// src/integrations/linear/integration.ts
|
|
9
|
-
var LinearReauthRequiredError = class extends Error {
|
|
10
|
-
constructor() {
|
|
11
|
-
super("Linear authorization expired. Reconnect Linear to keep syncing intake issues.");
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// src/integrations/linear/routes.ts
|
|
16
|
-
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3
|
+
//#region src/integrations/linear/routes.ts
|
|
4
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5
|
+
/** Erase a route handler's path-parameterized context to a plain `Context`. */
|
|
17
6
|
function loose(c) {
|
|
18
|
-
|
|
7
|
+
return c;
|
|
19
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the org-scoped tenant for a Linear request. The connection is
|
|
11
|
+
* org-owned, so it requires both a signed-in user and an organization — same
|
|
12
|
+
* tenancy rules as the GitHub routes.
|
|
13
|
+
*/
|
|
20
14
|
async function resolveOrgTenant(c, auth) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };
|
|
15
|
+
await auth.ensureUser(c);
|
|
16
|
+
const tenant = auth.tenant(c);
|
|
17
|
+
if (!tenant) return { response: c.json({ error: "unauthorized" }, 401) };
|
|
18
|
+
if (!tenant.orgId) return { response: c.json({
|
|
19
|
+
error: "organization_required",
|
|
20
|
+
message: "Linear intake requires an organization. Personal accounts cannot connect Linear."
|
|
21
|
+
}, 403) };
|
|
22
|
+
return { tenant: {
|
|
23
|
+
orgId: tenant.orgId,
|
|
24
|
+
userId: tenant.userId
|
|
25
|
+
} };
|
|
36
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate an opaque Linear pagination cursor from the query string. Cursors
|
|
29
|
+
* are server-issued (`pageInfo.endCursor`), so anything outside a conservative
|
|
30
|
+
* charset/length is rejected rather than forwarded to Linear.
|
|
31
|
+
*/
|
|
37
32
|
function parseAfterCursor(raw) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
34
|
+
if (raw.length > 512 || !/^[\w+/=.:-]+$/.test(raw)) return null;
|
|
35
|
+
return raw;
|
|
41
36
|
}
|
|
37
|
+
/** Map a Linear read failure to the API response for the SPA. */
|
|
42
38
|
function linearFetchError(c, err) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
if (err instanceof LinearReauthRequiredError || err.status === 401) return c.json({
|
|
40
|
+
error: "linear_reauth_required",
|
|
41
|
+
message: new LinearReauthRequiredError().message
|
|
42
|
+
}, 409);
|
|
43
|
+
return c.json({
|
|
44
|
+
error: "linear_fetch_failed",
|
|
45
|
+
message: err instanceof Error ? err.message : String(err)
|
|
46
|
+
}, 502);
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the Linear routes as Mastra `apiRoutes`. When the feature is disabled,
|
|
50
|
+
* returns only the `status` route so the SPA can detect the disabled state.
|
|
51
|
+
*/
|
|
48
52
|
function buildLinearRoutes(options) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
} catch (err) {
|
|
232
|
-
return linearFetchError(loose(c), err);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
})
|
|
236
|
-
);
|
|
237
|
-
return routes;
|
|
53
|
+
const routes = [];
|
|
54
|
+
const { linear, auth, stateSigner, intake } = options;
|
|
55
|
+
const enabled = Boolean(linear) && auth.enabled();
|
|
56
|
+
const diagnostics = () => ({
|
|
57
|
+
linearAppConfigured: Boolean(linear),
|
|
58
|
+
factoryAuthEnabled: auth.enabled(),
|
|
59
|
+
appDbConfigured: true
|
|
60
|
+
});
|
|
61
|
+
routes.push(registerApiRoute("/web/linear/status", {
|
|
62
|
+
method: "GET",
|
|
63
|
+
requiresAuth: false,
|
|
64
|
+
handler: async (c) => {
|
|
65
|
+
if (!enabled || !linear || !stateSigner) return c.json({
|
|
66
|
+
enabled: false,
|
|
67
|
+
connected: false,
|
|
68
|
+
workspace: null,
|
|
69
|
+
reason: "missing_config",
|
|
70
|
+
diagnostics: diagnostics()
|
|
71
|
+
});
|
|
72
|
+
await auth.ensureUser(loose(c));
|
|
73
|
+
const tenant = auth.tenant(loose(c));
|
|
74
|
+
if (!tenant) return c.json({
|
|
75
|
+
error: "unauthorized",
|
|
76
|
+
reason: "auth_required"
|
|
77
|
+
}, 401);
|
|
78
|
+
if (!tenant.orgId) return c.json({
|
|
79
|
+
enabled: true,
|
|
80
|
+
organizationRequired: true,
|
|
81
|
+
connected: false,
|
|
82
|
+
workspace: null,
|
|
83
|
+
reason: "organization_required",
|
|
84
|
+
diagnostics: diagnostics()
|
|
85
|
+
});
|
|
86
|
+
const connection = await linear.loadConnection(tenant.orgId);
|
|
87
|
+
return c.json({
|
|
88
|
+
enabled: true,
|
|
89
|
+
connected: Boolean(connection),
|
|
90
|
+
workspace: connection ? {
|
|
91
|
+
name: connection.workspaceName,
|
|
92
|
+
urlKey: connection.workspaceUrlKey
|
|
93
|
+
} : null,
|
|
94
|
+
reason: connection ? "ready" : "not_connected",
|
|
95
|
+
diagnostics: diagnostics()
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}));
|
|
99
|
+
if (!enabled || !linear || !stateSigner || !intake) return routes;
|
|
100
|
+
const redirectUri = options.redirectUri ?? `${(options.baseUrl ?? "").replace(/\/$/, "")}/auth/linear/callback`;
|
|
101
|
+
routes.push(registerApiRoute("/auth/linear/connect", {
|
|
102
|
+
method: "GET",
|
|
103
|
+
requiresAuth: false,
|
|
104
|
+
handler: async (c) => {
|
|
105
|
+
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
106
|
+
if ("response" in resolved) return resolved.response;
|
|
107
|
+
const state = stateSigner.sign(resolved.tenant.orgId, resolved.tenant.userId);
|
|
108
|
+
return c.redirect(linear.buildAuthorizeUrl(state, redirectUri));
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
routes.push(registerApiRoute("/auth/linear/callback", {
|
|
112
|
+
method: "GET",
|
|
113
|
+
requiresAuth: false,
|
|
114
|
+
handler: async (c) => {
|
|
115
|
+
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
116
|
+
if ("response" in resolved) return resolved.response;
|
|
117
|
+
const { orgId, userId } = resolved.tenant;
|
|
118
|
+
const stateTenant = stateSigner.verify(c.req.query("state"));
|
|
119
|
+
if (!stateTenant || stateTenant.userId !== userId || stateTenant.orgId !== orgId) {
|
|
120
|
+
console.warn("[Linear] OAuth callback rejected: state/tenant mismatch.");
|
|
121
|
+
return c.redirect("/?linear=error");
|
|
122
|
+
}
|
|
123
|
+
const code = c.req.query("code");
|
|
124
|
+
if (!code) return c.redirect("/?linear=error");
|
|
125
|
+
try {
|
|
126
|
+
const tokens = await linear.exchangeOAuthCode(code, redirectUri);
|
|
127
|
+
const workspace = await linear.fetchWorkspace(tokens.accessToken);
|
|
128
|
+
await linear.upsertConnection({
|
|
129
|
+
orgId,
|
|
130
|
+
userId,
|
|
131
|
+
accessToken: tokens.accessToken,
|
|
132
|
+
refreshToken: tokens.refreshToken,
|
|
133
|
+
expiresAt: tokens.expiresAt,
|
|
134
|
+
scope: tokens.scope,
|
|
135
|
+
workspaceName: workspace.name,
|
|
136
|
+
workspaceUrlKey: workspace.urlKey
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn(`[Linear] OAuth callback failed to persist connection for org ${orgId}.`, error);
|
|
140
|
+
return c.redirect("/?linear=error");
|
|
141
|
+
}
|
|
142
|
+
return c.redirect("/?linear=connected");
|
|
143
|
+
}
|
|
144
|
+
}));
|
|
145
|
+
routes.push(registerApiRoute("/web/linear/projects", {
|
|
146
|
+
method: "GET",
|
|
147
|
+
requiresAuth: false,
|
|
148
|
+
handler: async (c) => {
|
|
149
|
+
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
150
|
+
if ("response" in resolved) return resolved.response;
|
|
151
|
+
const connection = await linear.loadConnection(resolved.tenant.orgId);
|
|
152
|
+
if (!connection) return c.json({
|
|
153
|
+
error: "linear_not_connected",
|
|
154
|
+
message: "Connect Linear to list Linear projects."
|
|
155
|
+
}, 409);
|
|
156
|
+
try {
|
|
157
|
+
const accessToken = await linear.getFreshAccessToken(connection);
|
|
158
|
+
const projects = await linear.listProjects(accessToken);
|
|
159
|
+
return c.json({ projects });
|
|
160
|
+
} catch (err) {
|
|
161
|
+
return linearFetchError(loose(c), err);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
routes.push(registerApiRoute("/web/linear/issues", {
|
|
166
|
+
method: "GET",
|
|
167
|
+
requiresAuth: false,
|
|
168
|
+
handler: async (c) => {
|
|
169
|
+
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
170
|
+
if ("response" in resolved) return resolved.response;
|
|
171
|
+
const after = parseAfterCursor(c.req.query("after"));
|
|
172
|
+
if (after === null) return c.json({ error: "invalid_cursor" }, 400);
|
|
173
|
+
const factoryProjectId = c.req.query("factoryProjectId");
|
|
174
|
+
if (factoryProjectId && !UUID_RE.test(factoryProjectId)) return c.json({ error: "invalid_factory_project_id" }, 400);
|
|
175
|
+
const connection = await linear.loadConnection(resolved.tenant.orgId);
|
|
176
|
+
if (!connection) return c.json({
|
|
177
|
+
error: "linear_not_connected",
|
|
178
|
+
message: "Connect Linear to see intake issues."
|
|
179
|
+
}, 409);
|
|
180
|
+
await intake.ensureReady();
|
|
181
|
+
const selection = (await intake.getConfig({
|
|
182
|
+
orgId: resolved.tenant.orgId,
|
|
183
|
+
userId: resolved.tenant.userId,
|
|
184
|
+
integrationIds: ["linear"]
|
|
185
|
+
})).linear;
|
|
186
|
+
if (!selection.enabled) return c.json({
|
|
187
|
+
error: "linear_intake_disabled",
|
|
188
|
+
message: "Linear intake is turned off in Settings."
|
|
189
|
+
}, 404);
|
|
190
|
+
const projectIds = selection.sourceIds ?? [];
|
|
191
|
+
if (projectIds.length === 0) return c.json({
|
|
192
|
+
issues: [],
|
|
193
|
+
nextCursor: null
|
|
194
|
+
});
|
|
195
|
+
try {
|
|
196
|
+
const accessToken = await linear.getFreshAccessToken(connection);
|
|
197
|
+
const { issues, nextCursor } = await linear.intake.listIssues({
|
|
198
|
+
connection: {
|
|
199
|
+
type: "oauth",
|
|
200
|
+
accessToken
|
|
201
|
+
},
|
|
202
|
+
sourceIds: projectIds,
|
|
203
|
+
cursor: after
|
|
204
|
+
});
|
|
205
|
+
const issuePayload = issues.map((issue) => ({
|
|
206
|
+
id: issue.id,
|
|
207
|
+
identifier: issue.identifier,
|
|
208
|
+
title: issue.title,
|
|
209
|
+
url: issue.url,
|
|
210
|
+
state: issue.state ?? "",
|
|
211
|
+
stateType: issue.stateType ?? "",
|
|
212
|
+
priorityLabel: issue.priority ?? "",
|
|
213
|
+
assignee: issue.assignee,
|
|
214
|
+
team: issue.source,
|
|
215
|
+
labels: issue.labels,
|
|
216
|
+
createdAt: issue.createdAt,
|
|
217
|
+
updatedAt: issue.updatedAt
|
|
218
|
+
}));
|
|
219
|
+
if (factoryProjectId && options.ingestFactoryIssues) await options.ingestFactoryIssues({
|
|
220
|
+
orgId: resolved.tenant.orgId,
|
|
221
|
+
userId: resolved.tenant.userId,
|
|
222
|
+
factoryProjectId,
|
|
223
|
+
issues: issuePayload
|
|
224
|
+
});
|
|
225
|
+
return c.json({
|
|
226
|
+
issues: issuePayload,
|
|
227
|
+
nextCursor
|
|
228
|
+
});
|
|
229
|
+
} catch (err) {
|
|
230
|
+
return linearFetchError(loose(c), err);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}));
|
|
234
|
+
return routes;
|
|
238
235
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
236
|
+
//#endregion
|
|
237
|
+
export { buildLinearRoutes };
|
|
238
|
+
|
|
242
239
|
//# sourceMappingURL=routes.js.map
|