@rawdash/connector-github 0.10.1 → 0.11.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/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ declare class GitHubActionsConnector extends BaseConnector<GitHubActionsSettings
30
30
  };
31
31
  };
32
32
  private buildHeaders;
33
- private get;
33
+ private fetch;
34
34
  private allowedPageBasePath;
35
35
  private sanitizePageUrl;
36
36
  private resolveCursor;
package/dist/index.js CHANGED
@@ -1,296 +1,6 @@
1
1
  // ../../connector-shared/dist/index.js
2
- var HttpClientError = class extends Error {
3
- response;
4
- constructor(message, response) {
5
- super(message);
6
- this.name = new.target.name;
7
- this.response = response;
8
- }
9
- };
10
- var TransientError = class extends HttpClientError {
11
- kind = "transient";
12
- };
13
- var RateLimitError = class extends HttpClientError {
14
- kind = "rate_limit";
15
- retryAfter;
16
- constructor(message, response, retryAfter) {
17
- super(message, response);
18
- this.retryAfter = retryAfter;
19
- }
20
- };
21
- var AuthError = class extends HttpClientError {
22
- kind = "auth";
23
- };
24
- var UpstreamBugError = class extends HttpClientError {
25
- kind = "upstream_bug";
26
- };
27
- var ClientBugError = class extends HttpClientError {
28
- kind = "client_bug";
29
- };
30
- function classifyStatus(status) {
31
- if (status === 429) {
32
- return "rate_limit";
33
- }
34
- if (status === 401 || status === 403) {
35
- return "auth";
36
- }
37
- if (status === 408) {
38
- return "transient";
39
- }
40
- if (status >= 500) {
41
- return "upstream_bug";
42
- }
43
- if (status >= 400) {
44
- return "client_bug";
45
- }
46
- return "client_bug";
47
- }
48
- function errorForStatus(message, response, retryAfter) {
49
- const kind = classifyStatus(response.status);
50
- switch (kind) {
51
- case "rate_limit":
52
- return new RateLimitError(message, response, retryAfter);
53
- case "auth":
54
- return new AuthError(message, response);
55
- case "transient":
56
- return new TransientError(message, response);
57
- case "upstream_bug":
58
- return new UpstreamBugError(message, response);
59
- case "client_bug":
60
- return new ClientBugError(message, response);
61
- }
62
- }
63
- var defaultRetryOn = (status, err) => {
64
- if (err instanceof RateLimitError) {
65
- return true;
66
- }
67
- if (err instanceof TransientError) {
68
- return true;
69
- }
70
- if (status === null) {
71
- return err instanceof Error && !(err instanceof HttpClientError);
72
- }
73
- if (status === 408 || status === 429) {
74
- return true;
75
- }
76
- if (status >= 500) {
77
- return true;
78
- }
79
- return false;
80
- };
81
- function parseRetryAfter(headerValue, now = /* @__PURE__ */ new Date()) {
82
- if (!headerValue) {
83
- return void 0;
84
- }
85
- const trimmed = headerValue.trim();
86
- if (/^\d+$/.test(trimmed)) {
87
- return new Date(now.getTime() + Number(trimmed) * 1e3);
88
- }
89
- const parsed = Date.parse(trimmed);
90
- if (Number.isNaN(parsed)) {
91
- return void 0;
92
- }
93
- return new Date(parsed);
94
- }
95
- function sleep(ms, signal) {
96
- if (signal?.aborted) {
97
- return Promise.reject(signal.reason ?? new Error("Aborted"));
98
- }
99
- return new Promise((resolve, reject) => {
100
- const onAbort = () => {
101
- clearTimeout(timer);
102
- reject(signal.reason ?? new Error("Aborted"));
103
- };
104
- const timer = setTimeout(() => {
105
- signal?.removeEventListener("abort", onAbort);
106
- resolve();
107
- }, ms);
108
- signal?.addEventListener("abort", onAbort, { once: true });
109
- });
110
- }
111
2
  var HTTP_CLIENT_VERSION = "0.0.0";
112
3
  var DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;
113
- var DEFAULT_TIMEOUT_MS = 1e4;
114
- var DEFAULT_MAX_ATTEMPTS = 3;
115
- var DEFAULT_INITIAL_DELAY_MS = 1e3;
116
- var DEFAULT_MAX_DELAY_MS = 6e4;
117
- var OBSERVER_TIMEOUT_MS = 250;
118
- async function notifyObserver(observer, event) {
119
- let result;
120
- try {
121
- result = observer(event);
122
- } catch (err) {
123
- console.warn("[connector-shared] request observer threw:", err);
124
- return;
125
- }
126
- if (!(result instanceof Promise)) {
127
- return;
128
- }
129
- const guarded = result.catch((err) => {
130
- console.warn("[connector-shared] request observer rejected:", err);
131
- });
132
- let timer;
133
- const timeout = new Promise((resolve) => {
134
- timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);
135
- });
136
- try {
137
- await Promise.race([guarded, timeout]);
138
- } finally {
139
- if (timer) {
140
- clearTimeout(timer);
141
- }
142
- }
143
- }
144
- function newRequestId() {
145
- const c = globalThis.crypto;
146
- if (c?.randomUUID) {
147
- return c.randomUUID();
148
- }
149
- return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
150
- }
151
- function mergeHeaders(defaults, overrides) {
152
- const merged = {};
153
- for (const [k, v] of Object.entries(defaults)) {
154
- merged[k.toLowerCase()] = v;
155
- }
156
- if (overrides) {
157
- for (const [k, v] of Object.entries(overrides)) {
158
- merged[k.toLowerCase()] = v;
159
- }
160
- }
161
- return merged;
162
- }
163
- function linkTimeoutSignal(parent, timeoutMs) {
164
- const controller = new AbortController();
165
- const onParentAbort = () => {
166
- controller.abort(parent?.reason);
167
- };
168
- if (parent) {
169
- if (parent.aborted) {
170
- controller.abort(parent.reason);
171
- } else {
172
- parent.addEventListener("abort", onParentAbort, { once: true });
173
- }
174
- }
175
- const timer = setTimeout(() => {
176
- controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));
177
- }, timeoutMs);
178
- return {
179
- signal: controller.signal,
180
- cancel: () => {
181
- clearTimeout(timer);
182
- if (parent) {
183
- parent.removeEventListener("abort", onParentAbort);
184
- }
185
- }
186
- };
187
- }
188
- async function readBody(res, parseJson) {
189
- if (res.status === 204 || res.status === 205) {
190
- return null;
191
- }
192
- const contentType = res.headers.get("content-type") ?? "";
193
- if (parseJson && contentType.includes("application/json")) {
194
- const text = await res.text();
195
- if (text.length === 0) {
196
- return null;
197
- }
198
- return JSON.parse(text);
199
- }
200
- return res.text();
201
- }
202
- async function request(req, options = {}) {
203
- const fetchImpl = options.fetch ?? globalThis.fetch;
204
- const retry = req.retry ?? {};
205
- const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
206
- const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
207
- const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
208
- const retryOn = retry.retryOn ?? defaultRetryOn;
209
- const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;
210
- const parseJson = req.parseJson ?? true;
211
- const headers = mergeHeaders(
212
- {
213
- "User-Agent": DEFAULT_USER_AGENT,
214
- Accept: "application/json"
215
- },
216
- req.headers
217
- );
218
- let lastErr;
219
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
220
- req.signal?.throwIfAborted();
221
- const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);
222
- let res;
223
- try {
224
- res = await fetchImpl(req.url, {
225
- method: req.method ?? "GET",
226
- headers,
227
- body: req.body,
228
- signal
229
- });
230
- } catch (err2) {
231
- cancel();
232
- if (req.signal?.aborted) {
233
- throw req.signal.reason ?? err2;
234
- }
235
- const error = err2 instanceof Error ? err2 : new Error(String(err2));
236
- lastErr = error;
237
- if (attempt < maxAttempts - 1 && retryOn(null, error)) {
238
- const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);
239
- await sleep(delay, req.signal);
240
- continue;
241
- }
242
- throw new TransientError(error.message);
243
- }
244
- cancel();
245
- const body = await readBody(res, parseJson);
246
- const httpResponse = {
247
- status: res.status,
248
- headers: res.headers,
249
- body
250
- };
251
- if (req.rateLimit) {
252
- const state = req.rateLimit.parse(res.headers);
253
- if (state) {
254
- httpResponse.rateLimitState = state;
255
- }
256
- }
257
- if (options.observer) {
258
- await notifyObserver(options.observer, {
259
- url: req.url,
260
- method: req.method ?? "GET",
261
- status: res.status,
262
- resource: options.resource,
263
- requestId: options.requestId ?? newRequestId(),
264
- body
265
- });
266
- }
267
- if (res.ok) {
268
- return httpResponse;
269
- }
270
- const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
271
- const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? "GET"} ${req.url}`;
272
- const err = errorForStatus(message, httpResponse, retryAfter);
273
- if (attempt < maxAttempts - 1 && retryOn(res.status, err) && !(err instanceof AuthError) && !(err instanceof ClientBugError)) {
274
- lastErr = err;
275
- let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);
276
- if (err instanceof RateLimitError && retryAfter) {
277
- const wait = retryAfter.getTime() - Date.now();
278
- if (wait > 0) {
279
- delay = Math.min(wait, maxDelayMs);
280
- }
281
- }
282
- await sleep(delay, req.signal);
283
- continue;
284
- }
285
- throw err;
286
- }
287
- throw lastErr ?? new UpstreamBugError("Exhausted retry attempts");
288
- }
289
- function computeDelay(attempt, initialDelayMs, maxDelayMs) {
290
- const base = initialDelayMs * 2 ** attempt;
291
- const jitter = base * 0.25 * Math.random();
292
- return Math.min(base + jitter, maxDelayMs);
293
- }
294
4
  var githubRateLimit = {
295
5
  parse(h) {
296
6
  const remainingRaw = h.get("x-ratelimit-remaining");
@@ -400,14 +110,13 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
400
110
  }
401
111
  return headers;
402
112
  }
403
- get(url, signal) {
404
- const req = {
405
- url,
113
+ fetch(url, resource, signal) {
114
+ return this.get(url, {
115
+ resource,
406
116
  headers: this.buildHeaders(),
407
117
  signal,
408
118
  rateLimit: githubRateLimit
409
- };
410
- return request(req);
119
+ });
411
120
  }
412
121
  allowedPageBasePath(phase) {
413
122
  const { owner, repo } = this.settings;
@@ -456,16 +165,18 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
456
165
  }
457
166
  async fetchRepoStats(signal) {
458
167
  const { owner, repo } = this.settings;
459
- const res = await this.get(
168
+ const res = await this.fetch(
460
169
  `https://api.github.com/repos/${owner}/${repo}`,
170
+ "repo",
461
171
  signal
462
172
  );
463
173
  return { items: [res.body], next: null };
464
174
  }
465
175
  async fetchWorkflowRunsLatest(signal) {
466
176
  const { owner, repo } = this.settings;
467
- const res = await this.get(
177
+ const res = await this.fetch(
468
178
  `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,
179
+ "workflow_runs",
469
180
  signal
470
181
  );
471
182
  const run = res.body.workflow_runs[0];
@@ -474,7 +185,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
474
185
  async fetchWorkflowRunsFull(options, page, signal) {
475
186
  const { owner, repo } = this.settings;
476
187
  const url = page ?? `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`;
477
- const res = await this.get(url, signal);
188
+ const res = await this.fetch(
189
+ url,
190
+ "workflow_runs",
191
+ signal
192
+ );
478
193
  const nextLink = parseLinkHeader(res.headers.get("link"))["next"] ?? null;
479
194
  const runs = res.body.workflow_runs;
480
195
  const cutoff = options.since ? new Date(options.since).getTime() : null;
@@ -496,14 +211,15 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
496
211
  async fetchPullRequests(page, signal) {
497
212
  const { owner, repo } = this.settings;
498
213
  const url = page ?? `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`;
499
- const res = await this.get(url, signal);
214
+ const res = await this.fetch(url, "pull_requests", signal);
500
215
  const nextLink = parseLinkHeader(res.headers.get("link"))["next"] ?? null;
501
216
  const prs = res.body;
502
217
  const reviewsByPR = /* @__PURE__ */ new Map();
503
218
  for (const pr of prs) {
504
219
  signal?.throwIfAborted();
505
- const reviews = await this.get(
220
+ const reviews = await this.fetch(
506
221
  `https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,
222
+ "pull_request_reviews",
507
223
  signal
508
224
  );
509
225
  reviewsByPR.set(pr.number, reviews.body);
@@ -525,21 +241,26 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
525
241
  }
526
242
  url = u.toString();
527
243
  }
528
- const res = await this.get(url, signal);
244
+ const res = await this.fetch(url, "issues", signal);
529
245
  const nextLink = parseLinkHeader(res.headers.get("link"))["next"] ?? null;
530
246
  return { items: res.body, next: nextLink };
531
247
  }
532
248
  async fetchDeployments(page, signal) {
533
249
  const { owner, repo } = this.settings;
534
250
  const url = page ?? `https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`;
535
- const res = await this.get(url, signal);
251
+ const res = await this.fetch(
252
+ url,
253
+ "deployments",
254
+ signal
255
+ );
536
256
  const nextLink = parseLinkHeader(res.headers.get("link"))["next"] ?? null;
537
257
  const deployments = res.body;
538
258
  const latestStatusById = /* @__PURE__ */ new Map();
539
259
  for (const deployment of deployments) {
540
260
  signal?.throwIfAborted();
541
- const statusRes = await this.get(
261
+ const statusRes = await this.fetch(
542
262
  `https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,
263
+ "deployment_statuses",
543
264
  signal
544
265
  );
545
266
  latestStatusById.set(deployment.id, statusRes.body[0] ?? null);
@@ -550,7 +271,7 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
550
271
  async fetchReleases(page, signal) {
551
272
  const { owner, repo } = this.settings;
552
273
  const url = page ?? `https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`;
553
- const res = await this.get(url, signal);
274
+ const res = await this.fetch(url, "releases", signal);
554
275
  const nextLink = parseLinkHeader(res.headers.get("link"))["next"] ?? null;
555
276
  return { items: res.body, next: nextLink };
556
277
  }
@@ -558,8 +279,9 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
558
279
  const { owner, repo } = this.settings;
559
280
  const contributors = await this.withRetry(
560
281
  async (sig) => {
561
- const res = await this.get(
282
+ const res = await this.fetch(
562
283
  `https://api.github.com/repos/${owner}/${repo}/stats/contributors`,
284
+ "contributors",
563
285
  sig
564
286
  );
565
287
  if (res.status === 202) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/pagination.ts","../src/github-actions.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string | undefined;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource?: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions = {},\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport const githubRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-remaining');\n const resetRaw = h.get('x-ratelimit-reset');\n if (remainingRaw === null || resetRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n const reset = Number(resetRaw);\n if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {\n return null;\n }\n return { remaining, resetAt: new Date(reset * 1000) };\n },\n};\n\nexport const sentryRateLimit: RateLimitPolicy = {\n parse(h) {\n const concurrent = h.get('x-sentry-rate-limit-remaining');\n const reset = h.get('x-sentry-rate-limit-reset');\n if (concurrent === null || reset === null) {\n return null;\n }\n const remaining = Number(concurrent);\n const resetSec = Number(reset);\n if (\n !Number.isFinite(remaining) ||\n !Number.isFinite(resetSec) ||\n resetSec < 0\n ) {\n return null;\n }\n return { remaining, resetAt: new Date(resetSec * 1000) };\n },\n};\n\nexport const linearRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-requests-remaining');\n const resetRaw = h.get('x-ratelimit-requests-reset');\n if (remainingRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n let resetAt: Date;\n if (resetRaw !== null) {\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n resetAt = new Date(reset);\n } else {\n resetAt = new Date(Date.now() + 60_000);\n }\n return { remaining, resetAt };\n },\n};\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request({\n ...initial,\n url: next,\n });\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req);\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req);\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","import {\n type HttpRequest,\n type HttpResponse,\n githubRateLimit,\n parseLinkHeader,\n request,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ChunkedSyncCursor,\n type CredentialsSchema,\n type FetchPageResult,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n paginateChunked,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n owner: z.string().min(1).meta({\n label: 'Repository owner',\n description: 'GitHub username or organization name.',\n placeholder: 'rawdash',\n }),\n repo: z.string().min(1).meta({\n label: 'Repository',\n description: 'Repository name.',\n placeholder: 'rawdash',\n }),\n token: z.object({ $secret: z.string() }).optional().meta({\n label: 'Personal access token',\n description: 'GitHub PAT with `repo` scope.',\n secret: true,\n }),\n }),\n);\n\nexport interface GitHubActionsSettings {\n owner: string;\n repo: string;\n}\n\ninterface GitHubRunsResponse {\n workflow_runs: Array<{\n id: number;\n name: string;\n conclusion: string | null;\n status: string;\n head_branch: string | null;\n actor: { login: string } | null;\n created_at: string;\n updated_at: string;\n run_attempt: number;\n }>;\n}\n\ninterface GitHubPR {\n number: number;\n title: string;\n state: string;\n draft: boolean;\n user: { login: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GitHubReview {\n user: { login: string } | null;\n state: string;\n submitted_at: string;\n}\n\ninterface GitHubIssue {\n number: number;\n title: string;\n state: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n user: { login: string };\n created_at: string;\n updated_at: string;\n closed_at: string | null;\n pull_request?: unknown;\n}\n\ninterface GitHubDeployment {\n id: number;\n environment: string;\n ref: string;\n sha: string;\n creator: { login: string } | null;\n created_at: string;\n}\n\ninterface GitHubDeploymentStatus {\n state: string;\n updated_at: string;\n}\n\ninterface GitHubRelease {\n id: number;\n tag_name: string;\n name: string | null;\n draft: boolean;\n prerelease: boolean;\n created_at: string;\n published_at: string | null;\n author: { login: string };\n}\n\ninterface GitHubContributorStats {\n total: number;\n weeks: Array<{ w: number; a: number; d: number; c: number }>;\n author: { login: string };\n}\n\ninterface GitHubRepo {\n stargazers_count: number;\n forks_count: number;\n subscribers_count: number;\n}\n\nconst githubCredentials = {\n token: {\n description: 'GitHub personal access token',\n auth: 'optional' as const,\n },\n} satisfies CredentialsSchema;\n\ntype GitHubCredentials = typeof githubCredentials;\n\ntype GitHubSyncPhase =\n | 'repo_stats'\n | 'workflow_runs'\n | 'pull_requests'\n | 'issues'\n | 'deployments'\n | 'releases'\n | 'contributors';\n\nconst PHASE_ORDER: readonly GitHubSyncPhase[] = [\n 'repo_stats',\n 'workflow_runs',\n 'pull_requests',\n 'issues',\n 'deployments',\n 'releases',\n 'contributors',\n];\n\ntype GitHubSyncCursor = ChunkedSyncCursor<GitHubSyncPhase, string>;\n\ninterface PRPageItems {\n prs: GitHubPR[];\n reviewsByPR: Map<number, GitHubReview[]>;\n}\n\ninterface DeploymentPageItems {\n deployments: GitHubDeployment[];\n latestStatusById: Map<number, GitHubDeploymentStatus | null>;\n}\n\nconst CONTRIBUTORS_SKIPPED = Symbol('contributors-skipped');\n\nfunction isGitHubSyncCursor(value: unknown): value is GitHubSyncCursor {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const v = value as { phase?: unknown; page?: unknown };\n if (typeof v.phase !== 'string') {\n return false;\n }\n if (!(PHASE_ORDER as readonly string[]).includes(v.phase)) {\n return false;\n }\n if (v.page !== null && typeof v.page !== 'string') {\n return false;\n }\n return true;\n}\n\nexport class GitHubActionsConnector extends BaseConnector<\n GitHubActionsSettings,\n GitHubCredentials\n> {\n static readonly id = 'github-actions';\n\n static create(input: unknown): GitHubActionsConnector {\n const parsed = configFields.parse(input);\n return new GitHubActionsConnector(\n { owner: parsed.owner, repo: parsed.repo },\n { token: parsed.token },\n );\n }\n\n readonly id = 'github-actions';\n\n override readonly credentials = githubCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'rawdash/connector-github (+https://rawdash.dev)',\n };\n if (this.creds.token) {\n headers['Authorization'] = `Bearer ${this.creds.token}`;\n }\n return headers;\n }\n\n private get<T>(\n url: string,\n signal: AbortSignal | undefined,\n ): Promise<HttpResponse<T>> {\n const req: HttpRequest = {\n url,\n headers: this.buildHeaders(),\n signal,\n rateLimit: githubRateLimit,\n };\n return request<T>(req);\n }\n\n private allowedPageBasePath(phase: GitHubSyncPhase): string | null {\n const { owner, repo } = this.settings;\n switch (phase) {\n case 'workflow_runs':\n return `/repos/${owner}/${repo}/actions/runs`;\n case 'pull_requests':\n return `/repos/${owner}/${repo}/pulls`;\n case 'issues':\n return `/repos/${owner}/${repo}/issues`;\n case 'deployments':\n return `/repos/${owner}/${repo}/deployments`;\n case 'releases':\n return `/repos/${owner}/${repo}/releases`;\n case 'repo_stats':\n case 'contributors':\n return null;\n }\n }\n\n private sanitizePageUrl(\n phase: GitHubSyncPhase,\n pageUrl: string | null,\n ): string | null {\n if (pageUrl === null) {\n return null;\n }\n const allowedPath = this.allowedPageBasePath(phase);\n if (allowedPath === null) {\n return null;\n }\n try {\n const u = new URL(pageUrl);\n if (\n u.protocol !== 'https:' ||\n u.host !== 'api.github.com' ||\n u.pathname !== allowedPath\n ) {\n return null;\n }\n return u.toString();\n } catch {\n return null;\n }\n }\n\n private resolveCursor(cursor: unknown): GitHubSyncCursor | undefined {\n if (!isGitHubSyncCursor(cursor)) {\n return undefined;\n }\n return {\n phase: cursor.phase,\n page: this.sanitizePageUrl(cursor.phase, cursor.page),\n };\n }\n\n private async fetchRepoStats(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const res = await this.get<GitHubRepo>(\n `https://api.github.com/repos/${owner}/${repo}`,\n signal,\n );\n return { items: [res.body], next: null };\n }\n\n private async fetchWorkflowRunsLatest(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const res = await this.get<GitHubRunsResponse>(\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,\n signal,\n );\n const run = res.body.workflow_runs[0];\n return { items: run ? [run] : [], next: null };\n }\n\n private async fetchWorkflowRunsFull(\n options: SyncOptions,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`;\n const res = await this.get<GitHubRunsResponse>(url, signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const runs = res.body.workflow_runs;\n const cutoff = options.since ? new Date(options.since).getTime() : null;\n\n const filtered = runs.filter((run) => {\n if (cutoff === null) {\n return true;\n }\n const createdMs = new Date(run.created_at).getTime();\n const updatedMs = new Date(run.updated_at).getTime();\n return !(createdMs < cutoff && updatedMs < cutoff);\n });\n\n const lastRun = runs.at(-1);\n const cutoffReached =\n cutoff !== null &&\n lastRun !== undefined &&\n new Date(lastRun.created_at).getTime() < cutoff &&\n new Date(lastRun.updated_at).getTime() < cutoff;\n\n return {\n items: filtered,\n next: cutoffReached ? null : nextLink,\n };\n }\n\n private async fetchPullRequests(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`;\n const res = await this.get<GitHubPR[]>(url, signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const prs = res.body;\n\n const reviewsByPR = new Map<number, GitHubReview[]>();\n for (const pr of prs) {\n signal?.throwIfAborted();\n const reviews = await this.get<GitHubReview[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,\n signal,\n );\n reviewsByPR.set(pr.number, reviews.body);\n }\n\n const items: PRPageItems[] = [{ prs, reviewsByPR }];\n return { items, next: nextLink };\n }\n\n private async fetchIssues(\n options: SyncOptions,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n let url: string;\n if (page) {\n url = page;\n } else {\n const u = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);\n u.searchParams.set('state', 'all');\n u.searchParams.set('per_page', '100');\n if (options.since) {\n u.searchParams.set('since', options.since);\n }\n url = u.toString();\n }\n const res = await this.get<GitHubIssue[]>(url, signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n return { items: res.body, next: nextLink };\n }\n\n private async fetchDeployments(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`;\n const res = await this.get<GitHubDeployment[]>(url, signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const deployments = res.body;\n\n const latestStatusById = new Map<number, GitHubDeploymentStatus | null>();\n for (const deployment of deployments) {\n signal?.throwIfAborted();\n const statusRes = await this.get<GitHubDeploymentStatus[]>(\n `https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,\n signal,\n );\n latestStatusById.set(deployment.id, statusRes.body[0] ?? null);\n }\n\n const items: DeploymentPageItems[] = [{ deployments, latestStatusById }];\n return { items, next: nextLink };\n }\n\n private async fetchReleases(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`;\n const res = await this.get<GitHubRelease[]>(url, signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n return { items: res.body, next: nextLink };\n }\n\n private async fetchContributors(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const contributors = await this.withRetry<GitHubContributorStats[]>(\n async (sig) => {\n const res = await this.get<GitHubContributorStats[] | null>(\n `https://api.github.com/repos/${owner}/${repo}/stats/contributors`,\n sig,\n );\n if (res.status === 202) {\n return { status: 'retry' };\n }\n return {\n status: 'done',\n value: (res.body ?? []) as GitHubContributorStats[],\n };\n },\n { maxAttempts: 15, initialDelayMs: 1000, maxDelayMs: 10000, signal },\n );\n\n if (!contributors) {\n console.warn(\n '[github-actions] Stats endpoint never became ready — skipping contributor sync and keeping previous data.',\n );\n return { items: [CONTRIBUTORS_SKIPPED], next: null };\n }\n return { items: contributors, next: null };\n }\n\n private async writeRepoStats(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n const repoBody = items[0] as GitHubRepo | undefined;\n if (!repoBody) {\n return;\n }\n const { owner, repo } = this.settings;\n await storage.entities(\n [\n {\n type: 'repo',\n id: `${owner}/${repo}`,\n attributes: {\n stars: repoBody.stargazers_count,\n forks: repoBody.forks_count,\n watchers: repoBody.subscribers_count,\n },\n updated_at: Date.now(),\n },\n ],\n { types: ['repo'] },\n );\n }\n\n private async writeWorkflowRunsLatest(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n const run = items[0] as\n | GitHubRunsResponse['workflow_runs'][number]\n | undefined;\n if (!run) {\n return;\n }\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n\n private async writeWorkflowRunsFull(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.events([], { names: ['workflow_run'] });\n }\n const runs = items as GitHubRunsResponse['workflow_runs'];\n for (const run of runs) {\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n }\n\n private async writePullRequests(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['pull_request'] });\n await storage.edges([], { kinds: ['reviewed_by'] });\n }\n const pageItems = items as PRPageItems[];\n for (const { prs, reviewsByPR } of pageItems) {\n for (const pr of prs) {\n await storage.entity({\n type: 'pull_request',\n id: String(pr.number),\n attributes: {\n title: pr.title,\n state: pr.state,\n draft: pr.draft,\n author: pr.user.login,\n created_at: new Date(pr.created_at).getTime(),\n },\n updated_at: new Date(pr.updated_at).getTime(),\n });\n }\n for (const pr of prs) {\n const reviews = reviewsByPR.get(pr.number) ?? [];\n for (const review of reviews) {\n if (!review.user) {\n continue;\n }\n await storage.edge({\n from_type: 'pull_request',\n from_id: String(pr.number),\n kind: 'reviewed_by',\n to_type: 'user',\n to_id: review.user.login,\n attributes: { state: review.state },\n updated_at: new Date(review.submitted_at).getTime(),\n });\n }\n }\n }\n }\n\n private async writeIssues(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['issue'] });\n }\n const issues = items as GitHubIssue[];\n for (const issue of issues) {\n if (issue.pull_request !== undefined) {\n continue;\n }\n await storage.entity({\n type: 'issue',\n id: String(issue.number),\n attributes: {\n number: issue.number,\n title: issue.title,\n state: issue.state,\n labels: issue.labels.map((l) => l.name),\n assignees: issue.assignees.map((a) => a.login),\n author: issue.user.login,\n created_at: new Date(issue.created_at).getTime(),\n updated_at: new Date(issue.updated_at).getTime(),\n closed_at: issue.closed_at\n ? new Date(issue.closed_at).getTime()\n : null,\n },\n updated_at: new Date(issue.updated_at).getTime(),\n });\n }\n }\n\n private async writeDeployments(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['deployment'] });\n }\n const pageItems = items as DeploymentPageItems[];\n for (const { deployments, latestStatusById } of pageItems) {\n for (const deployment of deployments) {\n const status = latestStatusById.get(deployment.id) ?? null;\n const createdMs = new Date(deployment.created_at).getTime();\n const statusUpdatedMs = status?.updated_at\n ? new Date(status.updated_at).getTime()\n : null;\n await storage.entity({\n type: 'deployment',\n id: String(deployment.id),\n attributes: {\n environment: deployment.environment,\n ref: deployment.ref,\n sha: deployment.sha,\n creator: deployment.creator?.login ?? '',\n created_at: createdMs,\n latest_status: status?.state ?? 'unknown',\n },\n updated_at: Math.max(createdMs, statusUpdatedMs ?? 0),\n });\n }\n }\n }\n\n private async writeReleases(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['release'] });\n }\n const releases = items as GitHubRelease[];\n for (const release of releases) {\n await storage.entity({\n type: 'release',\n id: String(release.id),\n attributes: {\n tag_name: release.tag_name,\n name: release.name ?? '',\n draft: release.draft,\n prerelease: release.prerelease,\n created_at: new Date(release.created_at).getTime(),\n published_at: release.published_at\n ? new Date(release.published_at).getTime()\n : null,\n author: release.author.login,\n },\n updated_at: new Date(\n release.published_at ?? release.created_at,\n ).getTime(),\n });\n }\n }\n\n private async writeContributors(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n if (items[0] === CONTRIBUTORS_SKIPPED) {\n return;\n }\n const contributors = items as GitHubContributorStats[];\n await storage.entities(\n contributors.map((c) => {\n const additions = c.weeks.reduce((sum, w) => sum + w.a, 0);\n const deletions = c.weeks.reduce((sum, w) => sum + w.d, 0);\n const latestWeek = [...c.weeks].reverse().find((w) => w.c > 0);\n return {\n type: 'contributor',\n id: c.author.login,\n attributes: {\n commits: c.total,\n additions,\n deletions,\n latest_commit_at: latestWeek ? latestWeek.w * 1000 : null,\n },\n updated_at: latestWeek ? latestWeek.w * 1000 : 0,\n };\n }),\n { types: ['contributor'] },\n );\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = this.resolveCursor(options.cursor);\n return paginateChunked<GitHubSyncPhase, string>({\n phases: PHASE_ORDER,\n cursor,\n signal,\n fetchPage: async (phase, page, sig) => {\n switch (phase) {\n case 'repo_stats':\n return this.fetchRepoStats(sig);\n case 'workflow_runs':\n return options.mode === 'latest'\n ? this.fetchWorkflowRunsLatest(sig)\n : this.fetchWorkflowRunsFull(options, page, sig);\n case 'pull_requests':\n return this.fetchPullRequests(page, sig);\n case 'issues':\n return this.fetchIssues(options, page, sig);\n case 'deployments':\n return this.fetchDeployments(page, sig);\n case 'releases':\n return this.fetchReleases(page, sig);\n case 'contributors':\n return this.fetchContributors(sig);\n }\n },\n writeBatch: async (phase, items, page) => {\n switch (phase) {\n case 'repo_stats':\n return this.writeRepoStats(storage, items);\n case 'workflow_runs':\n return options.mode === 'latest'\n ? this.writeWorkflowRunsLatest(storage, items)\n : this.writeWorkflowRunsFull(storage, items, page);\n case 'pull_requests':\n return this.writePullRequests(storage, items, page);\n case 'issues':\n return this.writeIssues(storage, items, page);\n case 'deployments':\n return this.writeDeployments(storage, items, page);\n case 'releases':\n return this.writeReleases(storage, items, page);\n case 'contributors':\n return this.writeContributors(storage, items);\n }\n },\n });\n }\n}\n"],"mappings":"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","names":["err"]}
1
+ {"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/pagination.ts","../src/github-actions.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport const githubRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-remaining');\n const resetRaw = h.get('x-ratelimit-reset');\n if (remainingRaw === null || resetRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n const reset = Number(resetRaw);\n if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {\n return null;\n }\n return { remaining, resetAt: new Date(reset * 1000) };\n },\n};\n\nexport const sentryRateLimit: RateLimitPolicy = {\n parse(h) {\n const concurrent = h.get('x-sentry-rate-limit-remaining');\n const reset = h.get('x-sentry-rate-limit-reset');\n if (concurrent === null || reset === null) {\n return null;\n }\n const remaining = Number(concurrent);\n const resetSec = Number(reset);\n if (\n !Number.isFinite(remaining) ||\n !Number.isFinite(resetSec) ||\n resetSec < 0\n ) {\n return null;\n }\n return { remaining, resetAt: new Date(resetSec * 1000) };\n },\n};\n\nexport const linearRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-requests-remaining');\n const resetRaw = h.get('x-ratelimit-requests-reset');\n if (remainingRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n let resetAt: Date;\n if (resetRaw !== null) {\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n resetAt = new Date(reset);\n } else {\n resetAt = new Date(Date.now() + 60_000);\n }\n return { remaining, resetAt };\n },\n};\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","import {\n type HttpResponse,\n githubRateLimit,\n parseLinkHeader,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ChunkedSyncCursor,\n type CredentialsSchema,\n type FetchPageResult,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n paginateChunked,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n owner: z.string().min(1).meta({\n label: 'Repository owner',\n description: 'GitHub username or organization name.',\n placeholder: 'rawdash',\n }),\n repo: z.string().min(1).meta({\n label: 'Repository',\n description: 'Repository name.',\n placeholder: 'rawdash',\n }),\n token: z.object({ $secret: z.string() }).optional().meta({\n label: 'Personal access token',\n description: 'GitHub PAT with `repo` scope.',\n secret: true,\n }),\n }),\n);\n\nexport interface GitHubActionsSettings {\n owner: string;\n repo: string;\n}\n\ninterface GitHubRunsResponse {\n workflow_runs: Array<{\n id: number;\n name: string;\n conclusion: string | null;\n status: string;\n head_branch: string | null;\n actor: { login: string } | null;\n created_at: string;\n updated_at: string;\n run_attempt: number;\n }>;\n}\n\ninterface GitHubPR {\n number: number;\n title: string;\n state: string;\n draft: boolean;\n user: { login: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GitHubReview {\n user: { login: string } | null;\n state: string;\n submitted_at: string;\n}\n\ninterface GitHubIssue {\n number: number;\n title: string;\n state: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n user: { login: string };\n created_at: string;\n updated_at: string;\n closed_at: string | null;\n pull_request?: unknown;\n}\n\ninterface GitHubDeployment {\n id: number;\n environment: string;\n ref: string;\n sha: string;\n creator: { login: string } | null;\n created_at: string;\n}\n\ninterface GitHubDeploymentStatus {\n state: string;\n updated_at: string;\n}\n\ninterface GitHubRelease {\n id: number;\n tag_name: string;\n name: string | null;\n draft: boolean;\n prerelease: boolean;\n created_at: string;\n published_at: string | null;\n author: { login: string };\n}\n\ninterface GitHubContributorStats {\n total: number;\n weeks: Array<{ w: number; a: number; d: number; c: number }>;\n author: { login: string };\n}\n\ninterface GitHubRepo {\n stargazers_count: number;\n forks_count: number;\n subscribers_count: number;\n}\n\nconst githubCredentials = {\n token: {\n description: 'GitHub personal access token',\n auth: 'optional' as const,\n },\n} satisfies CredentialsSchema;\n\ntype GitHubCredentials = typeof githubCredentials;\n\ntype GitHubSyncPhase =\n | 'repo_stats'\n | 'workflow_runs'\n | 'pull_requests'\n | 'issues'\n | 'deployments'\n | 'releases'\n | 'contributors';\n\nconst PHASE_ORDER: readonly GitHubSyncPhase[] = [\n 'repo_stats',\n 'workflow_runs',\n 'pull_requests',\n 'issues',\n 'deployments',\n 'releases',\n 'contributors',\n];\n\ntype GitHubSyncCursor = ChunkedSyncCursor<GitHubSyncPhase, string>;\n\ninterface PRPageItems {\n prs: GitHubPR[];\n reviewsByPR: Map<number, GitHubReview[]>;\n}\n\ninterface DeploymentPageItems {\n deployments: GitHubDeployment[];\n latestStatusById: Map<number, GitHubDeploymentStatus | null>;\n}\n\nconst CONTRIBUTORS_SKIPPED = Symbol('contributors-skipped');\n\nfunction isGitHubSyncCursor(value: unknown): value is GitHubSyncCursor {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const v = value as { phase?: unknown; page?: unknown };\n if (typeof v.phase !== 'string') {\n return false;\n }\n if (!(PHASE_ORDER as readonly string[]).includes(v.phase)) {\n return false;\n }\n if (v.page !== null && typeof v.page !== 'string') {\n return false;\n }\n return true;\n}\n\nexport class GitHubActionsConnector extends BaseConnector<\n GitHubActionsSettings,\n GitHubCredentials\n> {\n static readonly id = 'github-actions';\n\n static create(input: unknown): GitHubActionsConnector {\n const parsed = configFields.parse(input);\n return new GitHubActionsConnector(\n { owner: parsed.owner, repo: parsed.repo },\n { token: parsed.token },\n );\n }\n\n readonly id = 'github-actions';\n\n override readonly credentials = githubCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'rawdash/connector-github (+https://rawdash.dev)',\n };\n if (this.creds.token) {\n headers['Authorization'] = `Bearer ${this.creds.token}`;\n }\n return headers;\n }\n\n private fetch<T>(\n url: string,\n resource: string,\n signal: AbortSignal | undefined,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n rateLimit: githubRateLimit,\n });\n }\n\n private allowedPageBasePath(phase: GitHubSyncPhase): string | null {\n const { owner, repo } = this.settings;\n switch (phase) {\n case 'workflow_runs':\n return `/repos/${owner}/${repo}/actions/runs`;\n case 'pull_requests':\n return `/repos/${owner}/${repo}/pulls`;\n case 'issues':\n return `/repos/${owner}/${repo}/issues`;\n case 'deployments':\n return `/repos/${owner}/${repo}/deployments`;\n case 'releases':\n return `/repos/${owner}/${repo}/releases`;\n case 'repo_stats':\n case 'contributors':\n return null;\n }\n }\n\n private sanitizePageUrl(\n phase: GitHubSyncPhase,\n pageUrl: string | null,\n ): string | null {\n if (pageUrl === null) {\n return null;\n }\n const allowedPath = this.allowedPageBasePath(phase);\n if (allowedPath === null) {\n return null;\n }\n try {\n const u = new URL(pageUrl);\n if (\n u.protocol !== 'https:' ||\n u.host !== 'api.github.com' ||\n u.pathname !== allowedPath\n ) {\n return null;\n }\n return u.toString();\n } catch {\n return null;\n }\n }\n\n private resolveCursor(cursor: unknown): GitHubSyncCursor | undefined {\n if (!isGitHubSyncCursor(cursor)) {\n return undefined;\n }\n return {\n phase: cursor.phase,\n page: this.sanitizePageUrl(cursor.phase, cursor.page),\n };\n }\n\n private async fetchRepoStats(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const res = await this.fetch<GitHubRepo>(\n `https://api.github.com/repos/${owner}/${repo}`,\n 'repo',\n signal,\n );\n return { items: [res.body], next: null };\n }\n\n private async fetchWorkflowRunsLatest(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const res = await this.fetch<GitHubRunsResponse>(\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,\n 'workflow_runs',\n signal,\n );\n const run = res.body.workflow_runs[0];\n return { items: run ? [run] : [], next: null };\n }\n\n private async fetchWorkflowRunsFull(\n options: SyncOptions,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`;\n const res = await this.fetch<GitHubRunsResponse>(\n url,\n 'workflow_runs',\n signal,\n );\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const runs = res.body.workflow_runs;\n const cutoff = options.since ? new Date(options.since).getTime() : null;\n\n const filtered = runs.filter((run) => {\n if (cutoff === null) {\n return true;\n }\n const createdMs = new Date(run.created_at).getTime();\n const updatedMs = new Date(run.updated_at).getTime();\n return !(createdMs < cutoff && updatedMs < cutoff);\n });\n\n const lastRun = runs.at(-1);\n const cutoffReached =\n cutoff !== null &&\n lastRun !== undefined &&\n new Date(lastRun.created_at).getTime() < cutoff &&\n new Date(lastRun.updated_at).getTime() < cutoff;\n\n return {\n items: filtered,\n next: cutoffReached ? null : nextLink,\n };\n }\n\n private async fetchPullRequests(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`;\n const res = await this.fetch<GitHubPR[]>(url, 'pull_requests', signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const prs = res.body;\n\n const reviewsByPR = new Map<number, GitHubReview[]>();\n for (const pr of prs) {\n signal?.throwIfAborted();\n const reviews = await this.fetch<GitHubReview[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,\n 'pull_request_reviews',\n signal,\n );\n reviewsByPR.set(pr.number, reviews.body);\n }\n\n const items: PRPageItems[] = [{ prs, reviewsByPR }];\n return { items, next: nextLink };\n }\n\n private async fetchIssues(\n options: SyncOptions,\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n let url: string;\n if (page) {\n url = page;\n } else {\n const u = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);\n u.searchParams.set('state', 'all');\n u.searchParams.set('per_page', '100');\n if (options.since) {\n u.searchParams.set('since', options.since);\n }\n url = u.toString();\n }\n const res = await this.fetch<GitHubIssue[]>(url, 'issues', signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n return { items: res.body, next: nextLink };\n }\n\n private async fetchDeployments(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`;\n const res = await this.fetch<GitHubDeployment[]>(\n url,\n 'deployments',\n signal,\n );\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n const deployments = res.body;\n\n const latestStatusById = new Map<number, GitHubDeploymentStatus | null>();\n for (const deployment of deployments) {\n signal?.throwIfAborted();\n const statusRes = await this.fetch<GitHubDeploymentStatus[]>(\n `https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,\n 'deployment_statuses',\n signal,\n );\n latestStatusById.set(deployment.id, statusRes.body[0] ?? null);\n }\n\n const items: DeploymentPageItems[] = [{ deployments, latestStatusById }];\n return { items, next: nextLink };\n }\n\n private async fetchReleases(\n page: string | null,\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const url =\n page ??\n `https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`;\n const res = await this.fetch<GitHubRelease[]>(url, 'releases', signal);\n const nextLink = parseLinkHeader(res.headers.get('link'))['next'] ?? null;\n return { items: res.body, next: nextLink };\n }\n\n private async fetchContributors(\n signal: AbortSignal | undefined,\n ): Promise<FetchPageResult<string>> {\n const { owner, repo } = this.settings;\n const contributors = await this.withRetry<GitHubContributorStats[]>(\n async (sig) => {\n const res = await this.fetch<GitHubContributorStats[] | null>(\n `https://api.github.com/repos/${owner}/${repo}/stats/contributors`,\n 'contributors',\n sig,\n );\n if (res.status === 202) {\n return { status: 'retry' };\n }\n return {\n status: 'done',\n value: (res.body ?? []) as GitHubContributorStats[],\n };\n },\n { maxAttempts: 15, initialDelayMs: 1000, maxDelayMs: 10000, signal },\n );\n\n if (!contributors) {\n console.warn(\n '[github-actions] Stats endpoint never became ready — skipping contributor sync and keeping previous data.',\n );\n return { items: [CONTRIBUTORS_SKIPPED], next: null };\n }\n return { items: contributors, next: null };\n }\n\n private async writeRepoStats(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n const repoBody = items[0] as GitHubRepo | undefined;\n if (!repoBody) {\n return;\n }\n const { owner, repo } = this.settings;\n await storage.entities(\n [\n {\n type: 'repo',\n id: `${owner}/${repo}`,\n attributes: {\n stars: repoBody.stargazers_count,\n forks: repoBody.forks_count,\n watchers: repoBody.subscribers_count,\n },\n updated_at: Date.now(),\n },\n ],\n { types: ['repo'] },\n );\n }\n\n private async writeWorkflowRunsLatest(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n const run = items[0] as\n | GitHubRunsResponse['workflow_runs'][number]\n | undefined;\n if (!run) {\n return;\n }\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n\n private async writeWorkflowRunsFull(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.events([], { names: ['workflow_run'] });\n }\n const runs = items as GitHubRunsResponse['workflow_runs'];\n for (const run of runs) {\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n }\n\n private async writePullRequests(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['pull_request'] });\n await storage.edges([], { kinds: ['reviewed_by'] });\n }\n const pageItems = items as PRPageItems[];\n for (const { prs, reviewsByPR } of pageItems) {\n for (const pr of prs) {\n await storage.entity({\n type: 'pull_request',\n id: String(pr.number),\n attributes: {\n title: pr.title,\n state: pr.state,\n draft: pr.draft,\n author: pr.user.login,\n created_at: new Date(pr.created_at).getTime(),\n },\n updated_at: new Date(pr.updated_at).getTime(),\n });\n }\n for (const pr of prs) {\n const reviews = reviewsByPR.get(pr.number) ?? [];\n for (const review of reviews) {\n if (!review.user) {\n continue;\n }\n await storage.edge({\n from_type: 'pull_request',\n from_id: String(pr.number),\n kind: 'reviewed_by',\n to_type: 'user',\n to_id: review.user.login,\n attributes: { state: review.state },\n updated_at: new Date(review.submitted_at).getTime(),\n });\n }\n }\n }\n }\n\n private async writeIssues(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['issue'] });\n }\n const issues = items as GitHubIssue[];\n for (const issue of issues) {\n if (issue.pull_request !== undefined) {\n continue;\n }\n await storage.entity({\n type: 'issue',\n id: String(issue.number),\n attributes: {\n number: issue.number,\n title: issue.title,\n state: issue.state,\n labels: issue.labels.map((l) => l.name),\n assignees: issue.assignees.map((a) => a.login),\n author: issue.user.login,\n created_at: new Date(issue.created_at).getTime(),\n updated_at: new Date(issue.updated_at).getTime(),\n closed_at: issue.closed_at\n ? new Date(issue.closed_at).getTime()\n : null,\n },\n updated_at: new Date(issue.updated_at).getTime(),\n });\n }\n }\n\n private async writeDeployments(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['deployment'] });\n }\n const pageItems = items as DeploymentPageItems[];\n for (const { deployments, latestStatusById } of pageItems) {\n for (const deployment of deployments) {\n const status = latestStatusById.get(deployment.id) ?? null;\n const createdMs = new Date(deployment.created_at).getTime();\n const statusUpdatedMs = status?.updated_at\n ? new Date(status.updated_at).getTime()\n : null;\n await storage.entity({\n type: 'deployment',\n id: String(deployment.id),\n attributes: {\n environment: deployment.environment,\n ref: deployment.ref,\n sha: deployment.sha,\n creator: deployment.creator?.login ?? '',\n created_at: createdMs,\n latest_status: status?.state ?? 'unknown',\n },\n updated_at: Math.max(createdMs, statusUpdatedMs ?? 0),\n });\n }\n }\n }\n\n private async writeReleases(\n storage: StorageHandle,\n items: unknown[],\n page: string | null,\n ): Promise<void> {\n if (page === null) {\n await storage.entities([], { types: ['release'] });\n }\n const releases = items as GitHubRelease[];\n for (const release of releases) {\n await storage.entity({\n type: 'release',\n id: String(release.id),\n attributes: {\n tag_name: release.tag_name,\n name: release.name ?? '',\n draft: release.draft,\n prerelease: release.prerelease,\n created_at: new Date(release.created_at).getTime(),\n published_at: release.published_at\n ? new Date(release.published_at).getTime()\n : null,\n author: release.author.login,\n },\n updated_at: new Date(\n release.published_at ?? release.created_at,\n ).getTime(),\n });\n }\n }\n\n private async writeContributors(\n storage: StorageHandle,\n items: unknown[],\n ): Promise<void> {\n if (items[0] === CONTRIBUTORS_SKIPPED) {\n return;\n }\n const contributors = items as GitHubContributorStats[];\n await storage.entities(\n contributors.map((c) => {\n const additions = c.weeks.reduce((sum, w) => sum + w.a, 0);\n const deletions = c.weeks.reduce((sum, w) => sum + w.d, 0);\n const latestWeek = [...c.weeks].reverse().find((w) => w.c > 0);\n return {\n type: 'contributor',\n id: c.author.login,\n attributes: {\n commits: c.total,\n additions,\n deletions,\n latest_commit_at: latestWeek ? latestWeek.w * 1000 : null,\n },\n updated_at: latestWeek ? latestWeek.w * 1000 : 0,\n };\n }),\n { types: ['contributor'] },\n );\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = this.resolveCursor(options.cursor);\n return paginateChunked<GitHubSyncPhase, string>({\n phases: PHASE_ORDER,\n cursor,\n signal,\n fetchPage: async (phase, page, sig) => {\n switch (phase) {\n case 'repo_stats':\n return this.fetchRepoStats(sig);\n case 'workflow_runs':\n return options.mode === 'latest'\n ? this.fetchWorkflowRunsLatest(sig)\n : this.fetchWorkflowRunsFull(options, page, sig);\n case 'pull_requests':\n return this.fetchPullRequests(page, sig);\n case 'issues':\n return this.fetchIssues(options, page, sig);\n case 'deployments':\n return this.fetchDeployments(page, sig);\n case 'releases':\n return this.fetchReleases(page, sig);\n case 'contributors':\n return this.fetchContributors(sig);\n }\n },\n writeBatch: async (phase, items, page) => {\n switch (phase) {\n case 'repo_stats':\n return this.writeRepoStats(storage, items);\n case 'workflow_runs':\n return options.mode === 'latest'\n ? this.writeWorkflowRunsLatest(storage, items)\n : this.writeWorkflowRunsFull(storage, items, page);\n case 'pull_requests':\n return this.writePullRequests(storage, items, page);\n case 'issues':\n return this.writeIssues(storage, items, page);\n case 'deployments':\n return this.writeDeployments(storage, items, page);\n case 'releases':\n return this.writeReleases(storage, items, page);\n case 'contributors':\n return this.writeContributors(storage, items);\n }\n },\n });\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawdash/connector-github",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "Rawdash connector for GitHub Actions",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -23,12 +23,12 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "zod": "^4.4.3",
26
- "@rawdash/core": "0.10.1"
26
+ "@rawdash/core": "0.11.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "tsup": "^8.0.0",
30
30
  "typescript": "^5.7.2",
31
- "@rawdash/connector-shared": "0.1.0"
31
+ "@rawdash/connector-shared": "0.2.0"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsup",