@rmdes/indiekit-endpoint-github 1.2.6 → 1.2.7

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/index.js CHANGED
@@ -2,6 +2,8 @@ import express from "express";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import path from "node:path";
4
4
 
5
+ import { waitForReady } from "@rmdes/indiekit-startup-gate";
6
+
5
7
  import { activityController } from "./lib/controllers/activity.js";
6
8
  import { changelogController } from "./lib/controllers/changelog.js";
7
9
  import { commitsController } from "./lib/controllers/commits.js";
@@ -115,13 +117,22 @@ export default class GitHubEndpoint {
115
117
 
116
118
  // Start background sync for starred repos (if token + DB available)
117
119
  if (this.options.token && Indiekit.database) {
118
- import("./lib/starred-sync.js")
119
- .then(({ startStarredSync }) => {
120
- startStarredSync(Indiekit, this.options);
121
- })
122
- .catch((error) => {
123
- console.error("[GitHub Stars] Sync scheduler failed to start:", error.message);
124
- });
120
+ this._stopGate = waitForReady(
121
+ () => {
122
+ import("./lib/starred-sync.js")
123
+ .then(({ startStarredSync }) => {
124
+ startStarredSync(Indiekit, this.options);
125
+ })
126
+ .catch((error) => {
127
+ console.error("[GitHub Stars] Sync scheduler failed to start:", error.message);
128
+ });
129
+ },
130
+ { label: "GitHub" },
131
+ );
125
132
  }
126
133
  }
134
+
135
+ destroy() {
136
+ this._stopGate?.();
137
+ }
127
138
  }
@@ -109,16 +109,16 @@ export const activityController = {
109
109
  activity = utils.extractRepoActivity(events, username);
110
110
  }
111
111
  } catch (apiError) {
112
- console.error("[Activity] API error:", apiError.message);
113
- return response.json({ activity: [], error: "GitHub API temporarily unavailable" });
112
+ return response
113
+ .status(apiError.status || 500)
114
+ .json({ error: apiError.message });
114
115
  }
115
116
 
116
117
  activity = activity.slice(0, limits.activity);
117
118
 
118
119
  response.json({ activity });
119
120
  } catch (error) {
120
- console.error("[Activity] Controller error:", error.message);
121
- response.json({ activity: [], error: "GitHub API temporarily unavailable" });
121
+ next(error);
122
122
  }
123
123
  },
124
124
  };
@@ -206,16 +206,7 @@ export const changelogController = {
206
206
  generatedAt: new Date().toISOString(),
207
207
  });
208
208
  } catch (error) {
209
- console.error("[Changelog] API error:", error.message);
210
- response.json({
211
- commits: [],
212
- categories: {},
213
- commitCategories: {},
214
- totalCommits: 0,
215
- days: daysValue || 30,
216
- generatedAt: new Date().toISOString(),
217
- error: "GitHub API temporarily unavailable",
218
- });
209
+ next(error);
219
210
  }
220
211
  },
221
212
  };
@@ -69,16 +69,16 @@ export const starsController = {
69
69
  try {
70
70
  starred = await client.getUserStarred(username, limits.stars);
71
71
  } catch (apiError) {
72
- console.error("[Stars] API error:", apiError.message);
73
- return response.json({ stars: [], error: "GitHub API temporarily unavailable" });
72
+ return response
73
+ .status(apiError.status || 500)
74
+ .json({ error: apiError.message });
74
75
  }
75
76
 
76
77
  const stars = utils.formatStarred(starred);
77
78
 
78
79
  response.json({ stars });
79
80
  } catch (error) {
80
- console.error("[Stars] Controller error:", error.message);
81
- response.json({ stars: [], error: "GitHub API temporarily unavailable" });
81
+ next(error);
82
82
  }
83
83
  },
84
84
  };
@@ -22,7 +22,7 @@ export class GitHubClient {
22
22
  async fetch(endpoint) {
23
23
  const url = `${BASE_URL}${endpoint}`;
24
24
 
25
- // Check cache first — return fresh data immediately
25
+ // Check cache first
26
26
  const cached = this.cache.get(url);
27
27
  if (cached && Date.now() - cached.timestamp < this.cacheTtl) {
28
28
  return cached.data;
@@ -37,40 +37,28 @@ export class GitHubClient {
37
37
  headers.Authorization = `Bearer ${this.token}`;
38
38
  }
39
39
 
40
- try {
41
- const response = await fetch(url, { headers });
42
-
43
- if (!response.ok) {
44
- // Only use fromFetch for JSON error responses; GitHub sometimes returns
45
- // HTML error pages (e.g., 502 Bad Gateway) which cause SyntaxError noise
46
- const contentType = response.headers.get("content-type") || "";
47
- if (contentType.includes("json")) {
48
- throw await IndiekitError.fromFetch(response);
49
- }
50
-
51
- throw new IndiekitError(response.statusText, {
52
- status: response.status,
53
- code: response.statusText,
54
- });
40
+ const response = await fetch(url, { headers });
41
+
42
+ if (!response.ok) {
43
+ // Only use fromFetch for JSON error responses; GitHub sometimes returns
44
+ // HTML error pages (e.g., 502 Bad Gateway) which cause SyntaxError noise
45
+ const contentType = response.headers.get("content-type") || "";
46
+ if (contentType.includes("json")) {
47
+ throw await IndiekitError.fromFetch(response);
55
48
  }
56
49
 
57
- const data = await response.json();
50
+ throw new IndiekitError(response.statusText, {
51
+ status: response.status,
52
+ code: response.statusText,
53
+ });
54
+ }
58
55
 
59
- // Cache result
60
- this.cache.set(url, { data, timestamp: Date.now() });
56
+ const data = await response.json();
61
57
 
62
- return data;
63
- } catch (error) {
64
- // Stale-while-error: if we have stale cached data, return it
65
- if (cached) {
66
- console.warn(
67
- `[GitHub] API error for ${endpoint}: ${error.message}. Serving stale cache (age: ${Math.round((Date.now() - cached.timestamp) / 60_000)}min)`,
68
- );
69
- return cached.data;
70
- }
58
+ // Cache result
59
+ this.cache.set(url, { data, timestamp: Date.now() });
71
60
 
72
- throw error;
73
- }
61
+ return data;
74
62
  }
75
63
 
76
64
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-github",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "GitHub activity endpoint for Indiekit. Display commits, stars, contributions, and featured repositories.",
5
5
  "keywords": [
6
6
  "indiekit",
@@ -40,6 +40,7 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "@indiekit/error": "^1.0.0-beta.25",
43
+ "@rmdes/indiekit-startup-gate": "^1.0.0",
43
44
  "express": "^5.0.0"
44
45
  },
45
46
  "peerDependencies": {