patchwork-os 0.2.0-alpha.34 → 0.2.0-alpha.35
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/README.md +142 -88
- package/deploy/bootstrap-new-vps.sh +12 -12
- package/deploy/bootstrap-vps.sh +6 -3
- package/deploy/deploy-landing.sh +59 -2
- package/dist/bridge.js +32 -1
- package/dist/bridge.js.map +1 -1
- package/dist/commands/recipe.js +18 -1
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.d.ts +79 -1
- package/dist/commands/recipeInstall.js +241 -13
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/connectors/asana.d.ts +198 -0
- package/dist/connectors/asana.js +680 -0
- package/dist/connectors/asana.js.map +1 -0
- package/dist/connectors/baseConnector.d.ts +16 -0
- package/dist/connectors/baseConnector.js +106 -24
- package/dist/connectors/baseConnector.js.map +1 -1
- package/dist/connectors/discord.d.ts +150 -0
- package/dist/connectors/discord.js +544 -0
- package/dist/connectors/discord.js.map +1 -0
- package/dist/connectors/github.js +11 -4
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gitlab.d.ts +180 -0
- package/dist/connectors/gitlab.js +582 -0
- package/dist/connectors/gitlab.js.map +1 -0
- package/dist/connectors/gmail.js +11 -0
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleDrive.d.ts +34 -0
- package/dist/connectors/googleDrive.js +305 -0
- package/dist/connectors/googleDrive.js.map +1 -0
- package/dist/connectors/linear.js +23 -4
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/pagerduty.d.ts +160 -0
- package/dist/connectors/pagerduty.js +464 -0
- package/dist/connectors/pagerduty.js.map +1 -0
- package/dist/connectors/slack.d.ts +1 -1
- package/dist/connectors/slack.js +3 -1
- package/dist/connectors/slack.js.map +1 -1
- package/dist/featureFlags.d.ts +17 -11
- package/dist/featureFlags.js +52 -47
- package/dist/featureFlags.js.map +1 -1
- package/dist/index.js +255 -127
- package/dist/index.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +7 -0
- package/dist/recipeOrchestration.js +149 -28
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipes/captureForRunlog.d.ts +27 -0
- package/dist/recipes/captureForRunlog.js +128 -0
- package/dist/recipes/captureForRunlog.js.map +1 -0
- package/dist/recipes/chainedRunner.d.ts +39 -3
- package/dist/recipes/chainedRunner.js +183 -28
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/detectSilentFail.d.ts +34 -0
- package/dist/recipes/detectSilentFail.js +105 -0
- package/dist/recipes/detectSilentFail.js.map +1 -0
- package/dist/recipes/manifest.js +21 -6
- package/dist/recipes/manifest.js.map +1 -1
- package/dist/recipes/replayRun.d.ts +62 -0
- package/dist/recipes/replayRun.js +97 -0
- package/dist/recipes/replayRun.js.map +1 -0
- package/dist/recipes/scheduler.js +102 -11
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schemaGenerator.js +3 -3
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/toolRegistry.d.ts +5 -0
- package/dist/recipes/toolRegistry.js +9 -0
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/asana.d.ts +16 -0
- package/dist/recipes/tools/asana.js +524 -0
- package/dist/recipes/tools/asana.js.map +1 -0
- package/dist/recipes/tools/discord.d.ts +18 -0
- package/dist/recipes/tools/discord.js +254 -0
- package/dist/recipes/tools/discord.js.map +1 -0
- package/dist/recipes/tools/github.js +29 -4
- package/dist/recipes/tools/github.js.map +1 -1
- package/dist/recipes/tools/gitlab.d.ts +11 -0
- package/dist/recipes/tools/gitlab.js +285 -0
- package/dist/recipes/tools/gitlab.js.map +1 -0
- package/dist/recipes/tools/gmail.d.ts +1 -1
- package/dist/recipes/tools/gmail.js +230 -6
- package/dist/recipes/tools/gmail.js.map +1 -1
- package/dist/recipes/tools/googleDrive.d.ts +1 -0
- package/dist/recipes/tools/googleDrive.js +55 -0
- package/dist/recipes/tools/googleDrive.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +6 -0
- package/dist/recipes/tools/index.js +6 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/linear.d.ts +2 -1
- package/dist/recipes/tools/linear.js +222 -1
- package/dist/recipes/tools/linear.js.map +1 -1
- package/dist/recipes/tools/meetingNotes.d.ts +21 -0
- package/dist/recipes/tools/meetingNotes.js +701 -0
- package/dist/recipes/tools/meetingNotes.js.map +1 -0
- package/dist/recipes/tools/pagerduty.d.ts +15 -0
- package/dist/recipes/tools/pagerduty.js +451 -0
- package/dist/recipes/tools/pagerduty.js.map +1 -0
- package/dist/recipes/tools/slack.js +8 -2
- package/dist/recipes/tools/slack.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +23 -2
- package/dist/recipes/yamlRunner.js +263 -58
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +32 -0
- package/dist/recipesHttp.js +310 -1
- package/dist/recipesHttp.js.map +1 -1
- package/dist/runLog.d.ts +64 -2
- package/dist/runLog.js +116 -2
- package/dist/runLog.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.js +331 -9
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.d.ts +31 -1
- package/dist/streamableHttp.js +20 -2
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/slackPostMessage.js +1 -1
- package/dist/tools/slackPostMessage.js.map +1 -1
- package/package.json +19 -4
- package/templates/recipes/project-health-check.yaml +1 -1
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitLab connector — read-only: projects, issues, merge requests, current user.
|
|
3
|
+
*
|
|
4
|
+
* OAuth 2.0 Authorization Code Grant. GitLab is a confidential client (bridge
|
|
5
|
+
* holds client secret), so PKCE is not used here. Refresh tokens are issued;
|
|
6
|
+
* access tokens default to 2 hours.
|
|
7
|
+
*
|
|
8
|
+
* Auth: standard OAuth 2.0 with `client_id` + `client_secret` + `redirect_uri`.
|
|
9
|
+
* - Env vars: GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET (mirrors asana/discord)
|
|
10
|
+
* - Optional: GITLAB_BASE_URL — override base for self-hosted GitLab.
|
|
11
|
+
* Default https://gitlab.com. `/api/v4` is appended internally.
|
|
12
|
+
* - Stored: getSecretJsonSync("gitlab") → GitLabTokens
|
|
13
|
+
* - Header: Authorization: Bearer <access_token>
|
|
14
|
+
*
|
|
15
|
+
* Read-only scopes: read_user read_api read_repository.
|
|
16
|
+
*
|
|
17
|
+
* Read tools: getCurrentUser, listProjects, listIssues, getIssue,
|
|
18
|
+
* listMergeRequests.
|
|
19
|
+
* Write methods (createIssue, createMergeRequestNote) are deferred to a
|
|
20
|
+
* follow-up PR.
|
|
21
|
+
*
|
|
22
|
+
* HTTP routes (wired in src/server.ts):
|
|
23
|
+
* GET /connections/gitlab/auth — redirect to GitLab consent
|
|
24
|
+
* GET /connections/gitlab/callback — exchange code for tokens
|
|
25
|
+
* POST /connections/gitlab/test — ping GitLab API
|
|
26
|
+
* DELETE /connections/gitlab — best-effort revoke + clear local
|
|
27
|
+
*
|
|
28
|
+
* Extends BaseConnector for unified auth, retry, rate-limit, error handling.
|
|
29
|
+
* Token refresh is delegated to BaseConnector.refreshToken() via apiCall.
|
|
30
|
+
*/
|
|
31
|
+
import crypto from "node:crypto";
|
|
32
|
+
import { BaseConnector, } from "./baseConnector.js";
|
|
33
|
+
import { escHtml } from "./htmlEscape.js";
|
|
34
|
+
import { deleteSecretJsonSync, getSecretJsonSync, storeSecretJsonSync, } from "./tokenStorage.js";
|
|
35
|
+
const SCOPES = ["read_user", "read_api", "read_repository"];
|
|
36
|
+
// ── Config ───────────────────────────────────────────────────────────────────
|
|
37
|
+
function clientId() {
|
|
38
|
+
return process.env.GITLAB_CLIENT_ID ?? "";
|
|
39
|
+
}
|
|
40
|
+
function clientSecret() {
|
|
41
|
+
return process.env.GITLAB_CLIENT_SECRET ?? "";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Base host for the GitLab instance, e.g. `https://gitlab.com` (default) or
|
|
45
|
+
* `https://gitlab.example.com` for self-hosted. Trailing slash trimmed; the
|
|
46
|
+
* `/api/v4` path is appended internally so users only configure host.
|
|
47
|
+
*/
|
|
48
|
+
export function gitlabBaseUrl() {
|
|
49
|
+
return (process.env.GITLAB_BASE_URL ?? "https://gitlab.com").replace(/\/$/, "");
|
|
50
|
+
}
|
|
51
|
+
function apiBase() {
|
|
52
|
+
return `${gitlabBaseUrl()}/api/v4`;
|
|
53
|
+
}
|
|
54
|
+
function authorizeUrl() {
|
|
55
|
+
return `${gitlabBaseUrl()}/oauth/authorize`;
|
|
56
|
+
}
|
|
57
|
+
function tokenUrl() {
|
|
58
|
+
return `${gitlabBaseUrl()}/oauth/token`;
|
|
59
|
+
}
|
|
60
|
+
function revokeUrl() {
|
|
61
|
+
return `${gitlabBaseUrl()}/oauth/revoke`;
|
|
62
|
+
}
|
|
63
|
+
function redirectUri() {
|
|
64
|
+
const base = (process.env.PATCHWORK_BRIDGE_URL ??
|
|
65
|
+
`http://localhost:${process.env.PATCHWORK_BRIDGE_PORT ?? "3101"}`).replace(/\/$/, "");
|
|
66
|
+
return `${base}/connections/gitlab/callback`;
|
|
67
|
+
}
|
|
68
|
+
function isConfigured() {
|
|
69
|
+
return Boolean(clientId() && clientSecret());
|
|
70
|
+
}
|
|
71
|
+
// ── Token persistence ────────────────────────────────────────────────────────
|
|
72
|
+
export function loadTokens() {
|
|
73
|
+
return getSecretJsonSync("gitlab");
|
|
74
|
+
}
|
|
75
|
+
export function saveTokens(tokens) {
|
|
76
|
+
storeSecretJsonSync("gitlab", tokens);
|
|
77
|
+
}
|
|
78
|
+
export function clearTokens() {
|
|
79
|
+
try {
|
|
80
|
+
deleteSecretJsonSync("gitlab");
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// ignore
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function isConnected() {
|
|
87
|
+
return loadTokens() !== null;
|
|
88
|
+
}
|
|
89
|
+
// ── State (CSRF) ─────────────────────────────────────────────────────────────
|
|
90
|
+
const pendingStates = new Set();
|
|
91
|
+
const STATE_TTL_MS = 5 * 60 * 1000;
|
|
92
|
+
function generateState() {
|
|
93
|
+
const state = crypto.randomBytes(32).toString("hex");
|
|
94
|
+
pendingStates.add(state);
|
|
95
|
+
setTimeout(() => pendingStates.delete(state), STATE_TTL_MS);
|
|
96
|
+
return state;
|
|
97
|
+
}
|
|
98
|
+
function consumeState(state) {
|
|
99
|
+
if (!pendingStates.has(state))
|
|
100
|
+
return false;
|
|
101
|
+
pendingStates.delete(state);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
// ── Connector class ──────────────────────────────────────────────────────────
|
|
105
|
+
export class GitLabConnector extends BaseConnector {
|
|
106
|
+
providerName = "gitlab";
|
|
107
|
+
getOAuthConfig() {
|
|
108
|
+
const tokens = loadTokens();
|
|
109
|
+
const id = clientId() || tokens?._client_id || "";
|
|
110
|
+
const secret = clientSecret() || tokens?._client_secret || "";
|
|
111
|
+
if (!id || !secret)
|
|
112
|
+
return null;
|
|
113
|
+
return {
|
|
114
|
+
clientId: id,
|
|
115
|
+
clientSecret: secret,
|
|
116
|
+
tokenEndpoint: tokenUrl(),
|
|
117
|
+
scopes: SCOPES,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async authenticate() {
|
|
121
|
+
const tokens = loadTokens();
|
|
122
|
+
if (!tokens) {
|
|
123
|
+
throw new Error("GitLab not connected. Visit /connections/gitlab/auth to authorize.");
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
token: tokens.access_token,
|
|
127
|
+
refreshToken: tokens.refresh_token,
|
|
128
|
+
expiresAt: tokens.expires_at ? new Date(tokens.expires_at) : undefined,
|
|
129
|
+
scopes: tokens.scope ? tokens.scope.split(" ") : SCOPES,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Persist refreshed tokens after BaseConnector.refreshToken() updates
|
|
134
|
+
* `this.auth`. Mirror to our GitLab-specific JSON so loadTokens() keeps
|
|
135
|
+
* working for HTTP probes.
|
|
136
|
+
*/
|
|
137
|
+
async saveTokens() {
|
|
138
|
+
await super.saveTokens();
|
|
139
|
+
if (!this.auth)
|
|
140
|
+
return;
|
|
141
|
+
const existing = loadTokens();
|
|
142
|
+
saveTokens({
|
|
143
|
+
access_token: this.auth.token,
|
|
144
|
+
refresh_token: this.auth.refreshToken,
|
|
145
|
+
expires_at: this.auth.expiresAt
|
|
146
|
+
? this.auth.expiresAt.getTime()
|
|
147
|
+
: undefined,
|
|
148
|
+
scope: this.auth.scopes?.join(" "),
|
|
149
|
+
token_type: existing?.token_type ?? "Bearer",
|
|
150
|
+
_client_id: existing?._client_id,
|
|
151
|
+
_client_secret: existing?._client_secret,
|
|
152
|
+
_base_url: existing?._base_url,
|
|
153
|
+
username: existing?.username,
|
|
154
|
+
user_id: existing?.user_id,
|
|
155
|
+
email: existing?.email,
|
|
156
|
+
connected_at: existing?.connected_at ?? new Date().toISOString(),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async healthCheck() {
|
|
160
|
+
try {
|
|
161
|
+
const result = await this.apiCall(async (token) => {
|
|
162
|
+
const res = await fetch(`${apiBase()}/user`, {
|
|
163
|
+
headers: this.buildHeaders(token),
|
|
164
|
+
});
|
|
165
|
+
if (!res.ok)
|
|
166
|
+
throw res;
|
|
167
|
+
return res.json();
|
|
168
|
+
});
|
|
169
|
+
if ("error" in result)
|
|
170
|
+
return { ok: false, error: result.error };
|
|
171
|
+
return { ok: true };
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return { ok: false, error: this.normalizeError(err) };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
normalizeError(error) {
|
|
178
|
+
if (error instanceof Response) {
|
|
179
|
+
const s = error.status;
|
|
180
|
+
if (s === 401)
|
|
181
|
+
return {
|
|
182
|
+
code: "auth_expired",
|
|
183
|
+
message: "GitLab authentication failed — token expired or revoked",
|
|
184
|
+
retryable: true,
|
|
185
|
+
suggestedAction: "Reconnect via /connections/gitlab/auth",
|
|
186
|
+
};
|
|
187
|
+
if (s === 403)
|
|
188
|
+
return {
|
|
189
|
+
code: "permission_denied",
|
|
190
|
+
message: "Insufficient GitLab permissions for this resource",
|
|
191
|
+
retryable: false,
|
|
192
|
+
};
|
|
193
|
+
if (s === 404)
|
|
194
|
+
return {
|
|
195
|
+
code: "not_found",
|
|
196
|
+
message: "GitLab resource not found",
|
|
197
|
+
retryable: false,
|
|
198
|
+
};
|
|
199
|
+
if (s === 429) {
|
|
200
|
+
const reset = error.headers.get("ratelimit-reset");
|
|
201
|
+
const retryAfter = error.headers.get("retry-after");
|
|
202
|
+
return {
|
|
203
|
+
code: "rate_limited",
|
|
204
|
+
message: `GitLab API rate limit exceeded${retryAfter ? ` (retry after ${retryAfter}s)` : ""}`,
|
|
205
|
+
retryable: true,
|
|
206
|
+
suggestedAction: retryAfter
|
|
207
|
+
? `Wait ${retryAfter}s and retry`
|
|
208
|
+
: "Wait and retry",
|
|
209
|
+
providerDetail: {
|
|
210
|
+
...(retryAfter ? { retryAfter } : {}),
|
|
211
|
+
...(reset ? { reset } : {}),
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
code: "provider_error",
|
|
217
|
+
message: `GitLab API error: HTTP ${s}`,
|
|
218
|
+
retryable: s >= 500,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (error instanceof Error) {
|
|
222
|
+
if (error.message.includes("ENOTFOUND") ||
|
|
223
|
+
error.message.includes("ECONNREFUSED")) {
|
|
224
|
+
return {
|
|
225
|
+
code: "network_error",
|
|
226
|
+
message: `Cannot connect to GitLab: ${error.message}`,
|
|
227
|
+
retryable: true,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
code: "provider_error",
|
|
233
|
+
message: error instanceof Error ? error.message : String(error),
|
|
234
|
+
retryable: false,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
getStatus() {
|
|
238
|
+
const tokens = loadTokens();
|
|
239
|
+
return {
|
|
240
|
+
id: "gitlab",
|
|
241
|
+
status: tokens ? "connected" : "disconnected",
|
|
242
|
+
lastSync: tokens?.connected_at,
|
|
243
|
+
workspace: tokens?.username,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// ── API Methods ────────────────────────────────────────────────────────────
|
|
247
|
+
async getCurrentUser() {
|
|
248
|
+
const result = await this.apiCall(async (token) => {
|
|
249
|
+
const res = await fetch(`${apiBase()}/user`, {
|
|
250
|
+
headers: this.buildHeaders(token),
|
|
251
|
+
});
|
|
252
|
+
this.captureRateLimit(res);
|
|
253
|
+
if (!res.ok)
|
|
254
|
+
throw res;
|
|
255
|
+
return res.json();
|
|
256
|
+
});
|
|
257
|
+
if ("error" in result)
|
|
258
|
+
throw new Error(result.error.message);
|
|
259
|
+
return result.data;
|
|
260
|
+
}
|
|
261
|
+
async listProjects(params = {}) {
|
|
262
|
+
const limit = Math.min(Math.max(params.limit ?? 50, 1), 100);
|
|
263
|
+
const result = await this.apiCall(async (token) => {
|
|
264
|
+
const qs = new URLSearchParams({
|
|
265
|
+
per_page: String(limit),
|
|
266
|
+
// Default to membership=true so users only see their projects unless
|
|
267
|
+
// they explicitly opt out (e.g. for public-search use cases).
|
|
268
|
+
membership: String(params.membership ?? true),
|
|
269
|
+
});
|
|
270
|
+
if (params.owned)
|
|
271
|
+
qs.set("owned", "true");
|
|
272
|
+
if (params.search)
|
|
273
|
+
qs.set("search", params.search);
|
|
274
|
+
const res = await fetch(`${apiBase()}/projects?${qs}`, {
|
|
275
|
+
headers: this.buildHeaders(token),
|
|
276
|
+
});
|
|
277
|
+
this.captureRateLimit(res);
|
|
278
|
+
if (!res.ok)
|
|
279
|
+
throw res;
|
|
280
|
+
return res.json();
|
|
281
|
+
});
|
|
282
|
+
if ("error" in result)
|
|
283
|
+
throw new Error(result.error.message);
|
|
284
|
+
return result.data;
|
|
285
|
+
}
|
|
286
|
+
async listIssues(params = {}) {
|
|
287
|
+
if (params.state && !["opened", "closed", "all"].includes(params.state)) {
|
|
288
|
+
throw new Error(`listIssues: invalid state "${params.state}" (expected opened|closed|all)`);
|
|
289
|
+
}
|
|
290
|
+
const limit = Math.min(Math.max(params.limit ?? 50, 1), 100);
|
|
291
|
+
const result = await this.apiCall(async (token) => {
|
|
292
|
+
const qs = new URLSearchParams({ per_page: String(limit) });
|
|
293
|
+
if (params.state)
|
|
294
|
+
qs.set("state", params.state);
|
|
295
|
+
let url;
|
|
296
|
+
if (params.projectId !== undefined && params.projectId !== "") {
|
|
297
|
+
url = `${apiBase()}/projects/${encodeURIComponent(String(params.projectId))}/issues?${qs}`;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
// Per-user issues endpoint. `assigned_to_me` is the default when
|
|
301
|
+
// `assignedToMe: true`; otherwise it returns issues created by user.
|
|
302
|
+
if (params.assignedToMe)
|
|
303
|
+
qs.set("scope", "assigned_to_me");
|
|
304
|
+
url = `${apiBase()}/issues?${qs}`;
|
|
305
|
+
}
|
|
306
|
+
const res = await fetch(url, { headers: this.buildHeaders(token) });
|
|
307
|
+
this.captureRateLimit(res);
|
|
308
|
+
if (!res.ok)
|
|
309
|
+
throw res;
|
|
310
|
+
return res.json();
|
|
311
|
+
});
|
|
312
|
+
if ("error" in result)
|
|
313
|
+
throw new Error(result.error.message);
|
|
314
|
+
return result.data;
|
|
315
|
+
}
|
|
316
|
+
async getIssue(projectId, issueIid) {
|
|
317
|
+
if (projectId === undefined || projectId === "" || !issueIid) {
|
|
318
|
+
throw new Error("getIssue requires projectId and issueIid");
|
|
319
|
+
}
|
|
320
|
+
const result = await this.apiCall(async (token) => {
|
|
321
|
+
const res = await fetch(`${apiBase()}/projects/${encodeURIComponent(String(projectId))}/issues/${issueIid}`, { headers: this.buildHeaders(token) });
|
|
322
|
+
this.captureRateLimit(res);
|
|
323
|
+
if (!res.ok)
|
|
324
|
+
throw res;
|
|
325
|
+
return res.json();
|
|
326
|
+
});
|
|
327
|
+
if ("error" in result)
|
|
328
|
+
throw new Error(result.error.message);
|
|
329
|
+
return result.data;
|
|
330
|
+
}
|
|
331
|
+
async listMergeRequests(params = {}) {
|
|
332
|
+
if (params.state &&
|
|
333
|
+
!["opened", "closed", "merged", "all"].includes(params.state)) {
|
|
334
|
+
throw new Error(`listMergeRequests: invalid state "${params.state}" (expected opened|closed|merged|all)`);
|
|
335
|
+
}
|
|
336
|
+
const limit = Math.min(Math.max(params.limit ?? 50, 1), 100);
|
|
337
|
+
const result = await this.apiCall(async (token) => {
|
|
338
|
+
const qs = new URLSearchParams({ per_page: String(limit) });
|
|
339
|
+
if (params.state)
|
|
340
|
+
qs.set("state", params.state);
|
|
341
|
+
if (params.scope)
|
|
342
|
+
qs.set("scope", params.scope);
|
|
343
|
+
let url;
|
|
344
|
+
if (params.projectId !== undefined && params.projectId !== "") {
|
|
345
|
+
url = `${apiBase()}/projects/${encodeURIComponent(String(params.projectId))}/merge_requests?${qs}`;
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
url = `${apiBase()}/merge_requests?${qs}`;
|
|
349
|
+
}
|
|
350
|
+
const res = await fetch(url, { headers: this.buildHeaders(token) });
|
|
351
|
+
this.captureRateLimit(res);
|
|
352
|
+
if (!res.ok)
|
|
353
|
+
throw res;
|
|
354
|
+
return res.json();
|
|
355
|
+
});
|
|
356
|
+
if ("error" in result)
|
|
357
|
+
throw new Error(result.error.message);
|
|
358
|
+
return result.data;
|
|
359
|
+
}
|
|
360
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
361
|
+
buildHeaders(token) {
|
|
362
|
+
return {
|
|
363
|
+
Authorization: `Bearer ${token}`,
|
|
364
|
+
Accept: "application/json",
|
|
365
|
+
"Content-Type": "application/json",
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
captureRateLimit(res) {
|
|
369
|
+
this.updateRateLimitFromHeaders({
|
|
370
|
+
"x-ratelimit-remaining": res.headers.get("ratelimit-remaining") ??
|
|
371
|
+
res.headers.get("x-ratelimit-remaining") ??
|
|
372
|
+
undefined,
|
|
373
|
+
"x-ratelimit-reset": res.headers.get("ratelimit-reset") ??
|
|
374
|
+
res.headers.get("x-ratelimit-reset") ??
|
|
375
|
+
undefined,
|
|
376
|
+
"retry-after": res.headers.get("retry-after") ?? undefined,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// ── Singleton ────────────────────────────────────────────────────────────────
|
|
381
|
+
let _instance = null;
|
|
382
|
+
function resetGitLabConnector() {
|
|
383
|
+
_instance = null;
|
|
384
|
+
}
|
|
385
|
+
export function getGitLabConnector() {
|
|
386
|
+
if (!_instance) {
|
|
387
|
+
_instance = new GitLabConnector();
|
|
388
|
+
}
|
|
389
|
+
return _instance;
|
|
390
|
+
}
|
|
391
|
+
export { getGitLabConnector as gitlab };
|
|
392
|
+
/**
|
|
393
|
+
* GET /connections/gitlab/auth — redirect to GitLab consent screen.
|
|
394
|
+
*/
|
|
395
|
+
export function handleGitLabAuthorize() {
|
|
396
|
+
if (!isConfigured()) {
|
|
397
|
+
return {
|
|
398
|
+
status: 503,
|
|
399
|
+
contentType: "application/json",
|
|
400
|
+
body: JSON.stringify({
|
|
401
|
+
ok: false,
|
|
402
|
+
error: "GitLab connector not configured. Set GITLAB_CLIENT_ID and GITLAB_CLIENT_SECRET.",
|
|
403
|
+
}),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const state = generateState();
|
|
407
|
+
const params = new URLSearchParams({
|
|
408
|
+
client_id: clientId(),
|
|
409
|
+
redirect_uri: redirectUri(),
|
|
410
|
+
response_type: "code",
|
|
411
|
+
scope: SCOPES.join(" "),
|
|
412
|
+
state,
|
|
413
|
+
});
|
|
414
|
+
return {
|
|
415
|
+
status: 302,
|
|
416
|
+
body: "",
|
|
417
|
+
redirect: `${authorizeUrl()}?${params.toString()}`,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* GET /connections/gitlab/callback — exchange code for tokens.
|
|
422
|
+
*/
|
|
423
|
+
export async function handleGitLabCallback(code, state, error) {
|
|
424
|
+
if (error) {
|
|
425
|
+
return {
|
|
426
|
+
status: 400,
|
|
427
|
+
contentType: "text/html",
|
|
428
|
+
body: `<html><body><h2>GitLab connect failed</h2><pre>${escHtml(error)}</pre></body></html>`,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
if (!code || !state) {
|
|
432
|
+
return {
|
|
433
|
+
status: 400,
|
|
434
|
+
contentType: "text/html",
|
|
435
|
+
body: `<html><body><h2>GitLab connect failed</h2><pre>missing code or state</pre></body></html>`,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
if (!consumeState(state)) {
|
|
439
|
+
return {
|
|
440
|
+
status: 400,
|
|
441
|
+
contentType: "text/html",
|
|
442
|
+
body: `<html><body><h2>GitLab connect failed</h2><pre>invalid or expired state</pre></body></html>`,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const params = new URLSearchParams({
|
|
447
|
+
grant_type: "authorization_code",
|
|
448
|
+
code,
|
|
449
|
+
redirect_uri: redirectUri(),
|
|
450
|
+
client_id: clientId(),
|
|
451
|
+
client_secret: clientSecret(),
|
|
452
|
+
});
|
|
453
|
+
const res = await fetch(tokenUrl(), {
|
|
454
|
+
method: "POST",
|
|
455
|
+
headers: {
|
|
456
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
457
|
+
Accept: "application/json",
|
|
458
|
+
},
|
|
459
|
+
body: params.toString(),
|
|
460
|
+
});
|
|
461
|
+
if (!res.ok) {
|
|
462
|
+
const body = await res.text();
|
|
463
|
+
throw new Error(`Token exchange HTTP ${res.status}: ${body}`);
|
|
464
|
+
}
|
|
465
|
+
const json = (await res.json());
|
|
466
|
+
if (!json.access_token) {
|
|
467
|
+
throw new Error("Token exchange returned no access_token");
|
|
468
|
+
}
|
|
469
|
+
// Best-effort fetch of user info so the dashboard can show "connected as X".
|
|
470
|
+
let username;
|
|
471
|
+
let userId;
|
|
472
|
+
let userEmail;
|
|
473
|
+
try {
|
|
474
|
+
const userRes = await fetch(`${apiBase()}/user`, {
|
|
475
|
+
headers: { Authorization: `Bearer ${json.access_token}` },
|
|
476
|
+
});
|
|
477
|
+
if (userRes.ok) {
|
|
478
|
+
const u = (await userRes.json());
|
|
479
|
+
username = u.name ?? u.username;
|
|
480
|
+
userId = u.id;
|
|
481
|
+
userEmail = u.email;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
// best-effort
|
|
486
|
+
}
|
|
487
|
+
const expiresAt = typeof json.expires_in === "number" && json.expires_in > 0
|
|
488
|
+
? Date.now() + json.expires_in * 1000
|
|
489
|
+
: undefined;
|
|
490
|
+
saveTokens({
|
|
491
|
+
access_token: json.access_token,
|
|
492
|
+
refresh_token: json.refresh_token,
|
|
493
|
+
expires_at: expiresAt,
|
|
494
|
+
scope: json.scope,
|
|
495
|
+
token_type: json.token_type ?? "Bearer",
|
|
496
|
+
_client_id: clientId() || undefined,
|
|
497
|
+
_client_secret: clientSecret() || undefined,
|
|
498
|
+
_base_url: gitlabBaseUrl(),
|
|
499
|
+
username,
|
|
500
|
+
user_id: userId,
|
|
501
|
+
email: userEmail,
|
|
502
|
+
connected_at: new Date().toISOString(),
|
|
503
|
+
});
|
|
504
|
+
resetGitLabConnector();
|
|
505
|
+
return {
|
|
506
|
+
status: 200,
|
|
507
|
+
contentType: "text/html",
|
|
508
|
+
body: `<html><body><h2>GitLab connected${username ? ` as ${escHtml(username)}` : ""}</h2><script>try { window.opener.postMessage('patchwork:gitlab:connected', '*'); } catch(_) {} window.close();</script></body></html>`,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
return {
|
|
513
|
+
status: 400,
|
|
514
|
+
contentType: "text/html",
|
|
515
|
+
body: `<html><body><h2>GitLab connect failed</h2><pre>${escHtml(err instanceof Error ? err.message : String(err))}</pre></body></html>`,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* POST /connections/gitlab/test — verify stored token works.
|
|
521
|
+
*/
|
|
522
|
+
export async function handleGitLabTest() {
|
|
523
|
+
const tokens = loadTokens();
|
|
524
|
+
if (!tokens) {
|
|
525
|
+
return {
|
|
526
|
+
status: 400,
|
|
527
|
+
contentType: "application/json",
|
|
528
|
+
body: JSON.stringify({ ok: false, error: "GitLab not connected" }),
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
const connector = getGitLabConnector();
|
|
533
|
+
const check = await connector.healthCheck();
|
|
534
|
+
return {
|
|
535
|
+
status: check.ok ? 200 : 401,
|
|
536
|
+
contentType: "application/json",
|
|
537
|
+
body: JSON.stringify(check.ok
|
|
538
|
+
? { ok: true, username: tokens.username }
|
|
539
|
+
: { ok: false, error: check.error?.message }),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
catch (err) {
|
|
543
|
+
return {
|
|
544
|
+
status: 500,
|
|
545
|
+
contentType: "application/json",
|
|
546
|
+
body: JSON.stringify({
|
|
547
|
+
ok: false,
|
|
548
|
+
error: err instanceof Error ? err.message : String(err),
|
|
549
|
+
}),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* DELETE /connections/gitlab — best-effort revoke at GitLab + drop locally.
|
|
555
|
+
*/
|
|
556
|
+
export async function handleGitLabDisconnect() {
|
|
557
|
+
const tokens = loadTokens();
|
|
558
|
+
if (tokens?.access_token && isConfigured()) {
|
|
559
|
+
try {
|
|
560
|
+
await fetch(revokeUrl(), {
|
|
561
|
+
method: "POST",
|
|
562
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
563
|
+
body: new URLSearchParams({
|
|
564
|
+
token: tokens.access_token,
|
|
565
|
+
client_id: clientId(),
|
|
566
|
+
client_secret: clientSecret(),
|
|
567
|
+
}).toString(),
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
// ignore — still drop local tokens
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
clearTokens();
|
|
575
|
+
resetGitLabConnector();
|
|
576
|
+
return {
|
|
577
|
+
status: 200,
|
|
578
|
+
contentType: "application/json",
|
|
579
|
+
body: JSON.stringify({ ok: true }),
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
//# sourceMappingURL=gitlab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/connectors/gitlab.ts"],"names":[],"mappings":"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"}
|
package/dist/connectors/gmail.js
CHANGED
|
@@ -188,22 +188,28 @@ export async function handleConnectionsList() {
|
|
|
188
188
|
const { getStatus: getSentryStatus } = await import("./sentry.js");
|
|
189
189
|
const { getStatus: getLinearStatus } = await import("./linear.js");
|
|
190
190
|
const { getStatus: getCalendarStatus } = await import("./googleCalendar.js");
|
|
191
|
+
const { getStatus: getDriveStatus } = await import("./googleDrive.js");
|
|
191
192
|
const { isConnected: isSlackConnected, getProfile: getSlackProfile } = await import("./slack.js");
|
|
192
193
|
const gh = getGitHubStatus();
|
|
193
194
|
const sentry = getSentryStatus();
|
|
194
195
|
const linear = getLinearStatus();
|
|
195
196
|
const calendar = getCalendarStatus();
|
|
197
|
+
const drive = getDriveStatus();
|
|
196
198
|
const slackConnected = isSlackConnected();
|
|
197
199
|
const slackProfile = getSlackProfile();
|
|
198
200
|
// Token-paste connectors expose loadTokens() which returns null when
|
|
199
201
|
// no credentials are stored. Probe each one so the dashboard reflects
|
|
200
202
|
// their actual state instead of always-disconnected.
|
|
201
203
|
const tokenPasteProbes = [
|
|
204
|
+
{ id: "asana", mod: () => import("./asana.js") },
|
|
202
205
|
{ id: "notion", mod: () => import("./notion.js") },
|
|
203
206
|
{ id: "confluence", mod: () => import("./confluence.js") },
|
|
204
207
|
{ id: "datadog", mod: () => import("./datadog.js") },
|
|
208
|
+
{ id: "discord", mod: () => import("./discord.js") },
|
|
209
|
+
{ id: "gitlab", mod: () => import("./gitlab.js") },
|
|
205
210
|
{ id: "hubspot", mod: () => import("./hubspot.js") },
|
|
206
211
|
{ id: "intercom", mod: () => import("./intercom.js") },
|
|
212
|
+
{ id: "pagerduty", mod: () => import("./pagerduty.js") },
|
|
207
213
|
{ id: "stripe", mod: () => import("./stripe.js") },
|
|
208
214
|
{ id: "zendesk", mod: () => import("./zendesk.js") },
|
|
209
215
|
{ id: "jira", mod: () => import("./jira.js") },
|
|
@@ -254,6 +260,11 @@ export async function handleConnectionsList() {
|
|
|
254
260
|
status: calendar.status,
|
|
255
261
|
lastSync: calendar.lastSync,
|
|
256
262
|
},
|
|
263
|
+
{
|
|
264
|
+
id: "google-drive",
|
|
265
|
+
status: drive.status,
|
|
266
|
+
lastSync: drive.lastSync,
|
|
267
|
+
},
|
|
257
268
|
{
|
|
258
269
|
id: "slack",
|
|
259
270
|
status: slackConnected ? "connected" : "disconnected",
|