@stoked-ui/github 0.0.0-a.0 → 0.1.0-alpha.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/GithubBranch/GithubBranch.d.ts +12 -0
  2. package/GithubBranch/GithubBranch.js +177 -0
  3. package/GithubBranch/index.d.ts +2 -0
  4. package/GithubBranch/index.js +2 -0
  5. package/GithubBranch/package.json +6 -0
  6. package/GithubCalendar/GithubCalendar.d.ts +6 -2
  7. package/GithubCalendar/GithubCalendar.js +70 -28
  8. package/GithubCommit/GithubCommit.d.ts +11 -0
  9. package/GithubCommit/GithubCommit.js +170 -0
  10. package/GithubCommit/index.d.ts +2 -0
  11. package/GithubCommit/index.js +2 -0
  12. package/GithubCommit/package.json +6 -0
  13. package/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
  14. package/GithubEvents/GithubEvents.d.ts +4 -24
  15. package/GithubEvents/GithubEvents.js +141 -220
  16. package/apiHandlers/createGithubBranchHandler.d.ts +12 -0
  17. package/apiHandlers/createGithubBranchHandler.js +41 -0
  18. package/apiHandlers/createGithubCommitHandler.d.ts +12 -0
  19. package/apiHandlers/createGithubCommitHandler.js +39 -0
  20. package/apiHandlers/createGithubContributionsHandler.d.ts +15 -0
  21. package/apiHandlers/createGithubContributionsHandler.js +41 -0
  22. package/apiHandlers/createGithubEventsHandler.d.ts +15 -0
  23. package/apiHandlers/createGithubEventsHandler.js +50 -0
  24. package/apiHandlers/getBranchCompareDetails.d.ts +9 -0
  25. package/apiHandlers/getBranchCompareDetails.js +29 -0
  26. package/apiHandlers/getCommitDetails.d.ts +8 -0
  27. package/apiHandlers/getCommitDetails.js +34 -0
  28. package/apiHandlers/getGithubContributions.d.ts +8 -0
  29. package/apiHandlers/getGithubContributions.js +126 -0
  30. package/apiHandlers/getGithubEvents.d.ts +25 -0
  31. package/apiHandlers/getGithubEvents.js +142 -0
  32. package/apiHandlers/getPullRequestDetails.js +2 -2
  33. package/apiHandlers/githubApi.d.ts +17 -0
  34. package/apiHandlers/githubApi.js +155 -0
  35. package/apiHandlers/index.d.ts +9 -0
  36. package/apiHandlers/index.js +9 -1
  37. package/components/GithubContributorsList.d.ts +8 -0
  38. package/components/GithubContributorsList.js +72 -0
  39. package/components/fetchGithubViewData.d.ts +1 -0
  40. package/components/fetchGithubViewData.js +10 -0
  41. package/index.d.ts +7 -3
  42. package/index.js +6 -4
  43. package/modern/GithubBranch/GithubBranch.js +177 -0
  44. package/modern/GithubBranch/index.js +2 -0
  45. package/modern/GithubCalendar/GithubCalendar.js +70 -28
  46. package/modern/GithubCommit/GithubCommit.js +170 -0
  47. package/modern/GithubCommit/index.js +2 -0
  48. package/modern/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
  49. package/modern/GithubEvents/GithubEvents.js +141 -220
  50. package/modern/apiHandlers/createGithubBranchHandler.js +41 -0
  51. package/modern/apiHandlers/createGithubCommitHandler.js +39 -0
  52. package/modern/apiHandlers/createGithubContributionsHandler.js +41 -0
  53. package/modern/apiHandlers/createGithubEventsHandler.js +50 -0
  54. package/modern/apiHandlers/getBranchCompareDetails.js +29 -0
  55. package/modern/apiHandlers/getCommitDetails.js +34 -0
  56. package/modern/apiHandlers/getGithubContributions.js +126 -0
  57. package/modern/apiHandlers/getGithubEvents.js +142 -0
  58. package/modern/apiHandlers/getPullRequestDetails.js +2 -2
  59. package/modern/apiHandlers/githubApi.js +155 -0
  60. package/modern/apiHandlers/index.js +9 -1
  61. package/modern/components/GithubContributorsList.js +72 -0
  62. package/modern/components/fetchGithubViewData.js +10 -0
  63. package/modern/index.js +6 -4
  64. package/node/GithubBranch/GithubBranch.js +185 -0
  65. package/node/GithubBranch/index.js +9 -0
  66. package/node/GithubCalendar/GithubCalendar.js +70 -28
  67. package/node/GithubCommit/GithubCommit.js +178 -0
  68. package/node/GithubCommit/index.js +9 -0
  69. package/node/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
  70. package/node/GithubEvents/GithubEvents.js +148 -223
  71. package/node/apiHandlers/createGithubBranchHandler.js +48 -0
  72. package/node/apiHandlers/createGithubCommitHandler.js +46 -0
  73. package/node/apiHandlers/createGithubContributionsHandler.js +48 -0
  74. package/node/apiHandlers/createGithubEventsHandler.js +57 -0
  75. package/node/apiHandlers/getBranchCompareDetails.js +35 -0
  76. package/node/apiHandlers/getCommitDetails.js +40 -0
  77. package/node/apiHandlers/getGithubContributions.js +132 -0
  78. package/node/apiHandlers/getGithubEvents.js +149 -0
  79. package/node/apiHandlers/getPullRequestDetails.js +2 -2
  80. package/node/apiHandlers/githubApi.js +168 -0
  81. package/node/apiHandlers/index.js +64 -1
  82. package/node/components/GithubContributorsList.js +80 -0
  83. package/node/components/fetchGithubViewData.js +16 -0
  84. package/node/index.js +77 -2
  85. package/package.json +2 -5
  86. package/stoked-ui-github-0.1.0-alpha.11.2.tgz +0 -0
  87. package/types/github.d.ts +75 -11
@@ -1,5 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
- var _div, _Chip, _SmalMi, _SmalMi2, _SmalMi3, _SmalMi4, _SmalMi5, _TableRow, _TableRow2;
2
+ var _Chip, _SmalMi, _SmalMi2, _SmalMi3, _SmalMi4, _SmalMi5, _TableRow, _TableRow2;
3
3
  import * as React from 'react';
4
4
  import { RequestError } from '@octokit/request-error';
5
5
  import Box from "@mui/material/Box";
@@ -21,23 +21,16 @@ import { toZonedTime } from 'date-fns-tz';
21
21
  import { styled, useTheme } from '@mui/material/styles';
22
22
  import Autocomplete from '@mui/material/Autocomplete';
23
23
  import Pagination from '@mui/material/Pagination';
24
- import dynamic from 'next/dynamic';
25
24
  import PullRequestEvent from './EventTypes/PullRequest/PullRequestEvent';
26
25
  import PushEvent from './EventTypes/PushEvent';
27
26
  import DeleteEvent from './EventTypes/DeleteEvent';
28
27
  import CreateEvent from './EventTypes/CreateEvent';
29
28
  import IssuesEvent from './EventTypes/IssuesEvent';
30
29
  import IssueCommentEvent from './EventTypes/IssueCommentEvent';
30
+ import { githubEventsQuery } from '../apiHandlers/getGithubEvents';
31
31
  import Chip from '@mui/material/Chip';
32
32
  // Extend the EventDetails interface for internal component use
33
33
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
34
- // Import react-json-view dynamically to avoid SSR issues
35
- const ReactJson = dynamic(() => import('react-json-view'), {
36
- ssr: false,
37
- loading: () => _div || (_div = /*#__PURE__*/_jsx("div", {
38
- children: "Loading JSON viewer..."
39
- }))
40
- });
41
34
  const MetadataDisplay = styled(Box)(({
42
35
  theme
43
36
  }) => {
@@ -55,176 +48,112 @@ const MetadataDisplay = styled(Box)(({
55
48
  overflow: 'auto'
56
49
  };
57
50
  });
58
- function parseLinkHeader(header) {
59
- if (!header) return {};
60
- return header.split(',').reduce((links, part) => {
61
- const match = part.match(/<(.+)>;\s*rel="([\w]+)"/);
62
- if (match) {
63
- const [, url, rel] = match;
64
- if (rel === 'next' || rel === 'last') {
65
- links[rel] = url;
66
- }
67
- }
68
- return links;
69
- }, {});
51
+ export { githubEventsQuery };
52
+ const CACHE_PERSIST_LIMITS = [200, 150, 100, 50, 25];
53
+ function isStorageQuotaError(error) {
54
+ return error instanceof DOMException && (error.name === 'QuotaExceededError' || error.name === 'NS_ERROR_DOM_QUOTA_REACHED');
70
55
  }
71
- export async function githubEventsQuery({
72
- query,
73
- githubUser,
74
- githubToken
75
- }) {
56
+ function getStorageItem(storage, key) {
76
57
  try {
77
- const {
78
- page = query.page || 1,
79
- per_page = query.per_page || 100,
80
- // Default to 100 per page to minimize API calls
81
- repo,
82
- action,
83
- date,
84
- description
85
- } = query;
86
- const queryParams = new URLSearchParams(_extends({
87
- page: String(page),
88
- per_page: String(per_page)
89
- }, repo && {
90
- repo
91
- }, action && {
92
- action
93
- }, date && {
94
- date
95
- }, description && {
96
- description
97
- }));
98
-
99
- // Get GitHub token from environment variables
100
- console.log(`Fetching events for user: ${githubUser}, page: ${page}, per_page: ${per_page}`);
101
-
102
- // Fetch all available pages from GitHub API
103
- let allEvents = [];
104
- let hasMore = true;
105
- let githubPage = 1;
106
- const maxPages = 30; // GitHub's maximum for events endpoint
107
-
108
- while (hasMore && githubPage <= maxPages) {
109
- console.log(`Fetching page ${githubPage}...`);
110
- const fetchOptions = {
111
- headers: {
112
- 'User-Agent': 'brianstoker.com-website'
113
- }
114
- };
115
- if (githubToken) {
116
- fetchOptions.headers.Authorization = `token ${githubToken}`;
117
- }
118
- const response = await fetch(`https://api.github.com/users/${githubUser}/events?${queryParams}`, fetchOptions);
119
- if (!response.ok) {
120
- const errorText = await response.text();
121
- console.error(`GitHub API error: ${response.status}`, errorText);
122
- throw new Error(`GitHub API error: ${response.status} - ${errorText}`);
123
- }
124
- const data = await response.json();
125
- console.log(`Page ${githubPage}: Received ${data.length} events`);
126
- if (data.length === 0) {
127
- hasMore = false;
128
- } else {
129
- allEvents = [...allEvents, ...data];
130
- console.log(`Total events so far: ${allEvents.length}`);
131
-
132
- // Check Link header to see if there are more pages
133
- const linkHeader = response.headers.get('Link');
134
- const links = parseLinkHeader(linkHeader);
135
- hasMore = !!links.next; // Simplified logic
136
-
137
- githubPage++;
138
- }
139
- }
140
- console.log(`Final total events: ${allEvents.length}`);
141
-
142
- // Apply filters
143
- let filteredEvents = allEvents;
144
- if (repo) {
145
- filteredEvents = filteredEvents.filter(event => event.repo.name === repo);
146
- }
147
- if (action) {
148
- filteredEvents = filteredEvents.filter(event => {
149
- const eventAction = event.type.replace('Event', '');
150
- return eventAction === action;
151
- });
152
- }
153
- if (date) {
154
- const now = new Date();
155
- let cutoffDate;
156
- switch (date) {
157
- case 'today':
158
- cutoffDate = new Date(now.setHours(0, 0, 0, 0));
159
- break;
160
- case 'yesterday':
161
- cutoffDate = new Date(now);
162
- cutoffDate.setDate(cutoffDate.getDate() - 1);
163
- cutoffDate.setHours(0, 0, 0, 0);
164
- break;
165
- case 'week':
166
- cutoffDate = new Date(now);
167
- cutoffDate.setDate(cutoffDate.getDate() - 7);
168
- cutoffDate.setHours(0, 0, 0, 0);
169
- break;
170
- case 'month':
171
- cutoffDate = new Date(now);
172
- cutoffDate.setMonth(cutoffDate.getMonth() - 1);
173
- cutoffDate.setHours(0, 0, 0, 0);
174
- break;
175
- default:
176
- cutoffDate = new Date(0);
177
- }
178
- filteredEvents = filteredEvents.filter(event => {
179
- const eventDate = new Date(event.created_at);
180
- return eventDate >= cutoffDate;
181
- });
182
- }
183
- if (description) {
184
- filteredEvents = filteredEvents.filter(event => {
185
- var _event$payload$commit, _event$payload$pull_r, _event$payload$issue, _event$payload$issue2;
186
- let eventDescription = '';
187
- if (event.type === 'PushEvent' && (_event$payload$commit = event.payload.commits) != null && _event$payload$commit.length) {
188
- eventDescription = `Pushed ${event.payload.commits.length} commits`;
189
- } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r = event.payload.pull_request) != null && _event$payload$pull_r.title) {
190
- eventDescription = event.payload.pull_request.title;
191
- } else if (event.type === 'IssuesEvent' && (_event$payload$issue = event.payload.issue) != null && _event$payload$issue.title) {
192
- eventDescription = event.payload.issue.title;
193
- } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue2 = event.payload.issue) != null && _event$payload$issue2.title) {
194
- eventDescription = `Commented on issue: ${event.payload.issue.title}`;
195
- }
196
- return eventDescription.toLowerCase().includes(description.toLowerCase());
197
- });
198
- }
199
-
200
- // Calculate pagination
201
- const pageNum = Number(page);
202
- const perPage = Number(per_page);
203
- const startIndex = (pageNum - 1) * perPage;
204
- const endIndex = startIndex + perPage;
205
- const paginatedEvents = filteredEvents.slice(startIndex, endIndex);
206
-
207
- // Extract unique values for filters (only on first page)
208
- const repositories = [...new Set(allEvents.map(event => event.repo.name))].sort();
209
- const actionTypes = [...new Set(allEvents.map(event => event.type.replace('Event', '')))].sort();
210
-
211
- // Return paginated results with metadata
58
+ return storage.getItem(key);
59
+ } catch (error) {
60
+ console.warn(`Failed to read storage key "${key}"`, error);
61
+ return null;
62
+ }
63
+ }
64
+ function setStorageItem(storage, key, value) {
65
+ try {
66
+ storage.setItem(key, value);
212
67
  return {
213
- events: paginatedEvents,
214
- total: filteredEvents.length,
215
- repositories,
216
- actionTypes,
217
- page: pageNum,
218
- per_page: perPage,
219
- total_pages: Math.ceil(filteredEvents.length / perPage),
220
- total_fetched_events: allEvents.length,
221
- max_pages_fetched: githubPage - 1
68
+ ok: true,
69
+ quotaExceeded: false
222
70
  };
223
71
  } catch (error) {
224
- console.error('Error fetching GitHub events:', error);
225
- throw new Error(`${error instanceof Error ? error.message : String(error)}`);
72
+ console.warn(`Failed to write storage key "${key}"`, error);
73
+ return {
74
+ ok: false,
75
+ quotaExceeded: isStorageQuotaError(error)
76
+ };
77
+ }
78
+ }
79
+ function removeStorageItem(storage, key) {
80
+ try {
81
+ storage.removeItem(key);
82
+ } catch (error) {
83
+ console.warn(`Failed to remove storage key "${key}"`, error);
84
+ }
85
+ }
86
+ function getStorageKeys(storage) {
87
+ try {
88
+ return Object.keys(storage);
89
+ } catch (error) {
90
+ console.warn('Failed to enumerate storage keys', error);
91
+ return [];
92
+ }
93
+ }
94
+ function buildCachePayload(events, limit = events.length) {
95
+ const normalizedLimit = Math.max(0, Math.min(events.length, limit));
96
+ const cachedEvents = normalizedLimit === events.length ? events : events.slice(0, normalizedLimit);
97
+ return {
98
+ events: cachedEvents,
99
+ lastFetched: Date.now(),
100
+ totalCount: cachedEvents.length
101
+ };
102
+ }
103
+ function persistCachedEvents(cacheKey, events) {
104
+ const attempts = Array.from(new Set([Math.min(events.length, CACHE_PERSIST_LIMITS[0]), ...CACHE_PERSIST_LIMITS])).filter(limit => limit > 0 && limit <= events.length);
105
+ let removedExistingCache = false;
106
+ for (const limit of attempts) {
107
+ const payload = buildCachePayload(events, limit);
108
+ const result = setStorageItem(localStorage, cacheKey, JSON.stringify(payload));
109
+ if (result.ok) {
110
+ return payload;
111
+ }
112
+ if (result.quotaExceeded && !removedExistingCache) {
113
+ removeStorageItem(localStorage, cacheKey);
114
+ removedExistingCache = true;
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ function updateCachedEventsTimestamp(cacheKey, payload) {
120
+ if (!payload) {
121
+ return;
122
+ }
123
+ const result = setStorageItem(localStorage, cacheKey, JSON.stringify(_extends({}, payload, {
124
+ lastFetched: Date.now()
125
+ })));
126
+ if (!result.ok) {
127
+ console.warn(`Skipping timestamp update for "${cacheKey}"`);
226
128
  }
227
129
  }
130
+ function JsonFallbackView({
131
+ value
132
+ }) {
133
+ const json = React.useMemo(() => {
134
+ try {
135
+ return JSON.stringify(value, null, 2);
136
+ } catch (error) {
137
+ return `Failed to serialize event payload: ${error instanceof Error ? error.message : String(error)}`;
138
+ }
139
+ }, [value]);
140
+ return /*#__PURE__*/_jsx(Box, {
141
+ component: "pre",
142
+ sx: {
143
+ backgroundColor: 'transparent',
144
+ fontSize: '0.875rem',
145
+ fontFamily: 'monospace',
146
+ padding: '8px',
147
+ borderRadius: '4px',
148
+ overflow: 'auto',
149
+ maxHeight: 'calc(100vh - 200px)',
150
+ margin: 0,
151
+ whiteSpace: 'pre-wrap',
152
+ wordBreak: 'break-word'
153
+ },
154
+ children: json
155
+ });
156
+ }
228
157
  async function getEvents({
229
158
  githubUser,
230
159
  githubToken,
@@ -253,6 +182,7 @@ async function getEvents({
253
182
  description
254
183
  }));
255
184
  if (apiUrl) {
185
+ queryParams.set('username', githubUser);
256
186
  const url = apiUrl;
257
187
  console.log(`Fetching from custom API URL: ${url}?${queryParams}`);
258
188
  const response = await fetch(`${url}?${queryParams}`);
@@ -422,14 +352,14 @@ export default function GithubEvents({
422
352
  uniqueRepos.add(event.repo.name);
423
353
  uniqueActions.add(event.type.replace('Event', ''));
424
354
  if (event.payload) {
425
- var _event$payload$commit2, _event$payload$pull_r2, _event$payload$issue3, _event$payload$issue4;
426
- if (event.type === 'PushEvent' && (_event$payload$commit2 = event.payload.commits) != null && _event$payload$commit2.length) {
355
+ var _event$payload$commit, _event$payload$pull_r, _event$payload$issue, _event$payload$issue2;
356
+ if (event.type === 'PushEvent' && (_event$payload$commit = event.payload.commits) != null && _event$payload$commit.length) {
427
357
  uniqueDescriptions.add(`Pushed ${event.payload.commits.length} commits`);
428
- } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r2 = event.payload.pull_request) != null && _event$payload$pull_r2.title) {
358
+ } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r = event.payload.pull_request) != null && _event$payload$pull_r.title) {
429
359
  uniqueDescriptions.add(event.payload.pull_request.title);
430
- } else if (event.type === 'IssuesEvent' && (_event$payload$issue3 = event.payload.issue) != null && _event$payload$issue3.title) {
360
+ } else if (event.type === 'IssuesEvent' && (_event$payload$issue = event.payload.issue) != null && _event$payload$issue.title) {
431
361
  uniqueDescriptions.add(event.payload.issue.title);
432
- } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue4 = event.payload.issue) != null && _event$payload$issue4.title) {
362
+ } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue2 = event.payload.issue) != null && _event$payload$issue2.title) {
433
363
  uniqueDescriptions.add(`Commented on issue: ${event.payload.issue.title}`);
434
364
  }
435
365
  }
@@ -450,7 +380,7 @@ export default function GithubEvents({
450
380
  console.log('Sample raw event to process:', JSON.stringify(rawEvents[0]).substring(0, 500) + '...');
451
381
  }
452
382
  return rawEvents.map((event, index) => {
453
- var _event$payload$commit3;
383
+ var _event$payload$commit2;
454
384
  try {
455
385
  var _event$repo2;
456
386
  if (!event) {
@@ -472,7 +402,7 @@ export default function GithubEvents({
472
402
  switch (event.type) {
473
403
  case 'PushEvent':
474
404
  action = 'Push';
475
- description = `Pushed ${((_event$payload$commit3 = event.payload.commits) == null ? void 0 : _event$payload$commit3.length) || 0} commits`;
405
+ description = `Pushed ${((_event$payload$commit2 = event.payload.commits) == null ? void 0 : _event$payload$commit2.length) || 0} commits`;
476
406
  link = `https://github.com/${event.repo.name}/commit/${event.payload.head}`;
477
407
  break;
478
408
  case 'PullRequestEvent':
@@ -574,8 +504,8 @@ export default function GithubEvents({
574
504
  };
575
505
  const getEventDescription = event => {
576
506
  if (event.type === 'PushEvent') {
577
- var _event$payload$commit4;
578
- return `Pushed ${((_event$payload$commit4 = event.payload.commits) == null ? void 0 : _event$payload$commit4.length) || 0} commits`;
507
+ var _event$payload$commit3;
508
+ return `Pushed ${((_event$payload$commit3 = event.payload.commits) == null ? void 0 : _event$payload$commit3.length) || 0} commits`;
579
509
  } else if (event.type === 'PullRequestEvent') {
580
510
  return event.payload.pull_request.title;
581
511
  } else if (event.type === 'IssuesEvent') {
@@ -670,15 +600,15 @@ export default function GithubEvents({
670
600
  if (allEvents.length > 0) {
671
601
  // Save all events to cache with user-specific key
672
602
  setCachedEvents(allEvents);
673
- localStorage.setItem(cacheKey, JSON.stringify({
674
- events: allEvents,
675
- lastFetched: Date.now(),
676
- totalCount: allEvents.length
677
- }));
603
+ const persistedCache = persistCachedEvents(cacheKey, allEvents);
604
+ if (persistedCache && persistedCache.events.length < allEvents.length) {
605
+ console.warn(`Persisted a trimmed GitHub events cache for "${cacheKey}" (${persistedCache.events.length}/${allEvents.length} events)`);
606
+ }
678
607
 
679
608
  // Mark that we've fetched this session
680
- sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
609
+ setStorageItem(sessionStorage, `${cacheKey}_session_fetched`, 'true');
681
610
  fetchedThisSessionRef.current = true;
611
+ setLastUpdated(format(new Date(), 'MMM d, yyyy h:mm a'));
682
612
 
683
613
  // Update filter options with all data
684
614
  buildFilterOptionsFromEvents(allEvents);
@@ -794,16 +724,15 @@ export default function GithubEvents({
794
724
  updatedEvents.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
795
725
 
796
726
  // Mark that we've fetched this session
797
- sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
727
+ setStorageItem(sessionStorage, `${cacheKey}_session_fetched`, 'true');
798
728
  fetchedThisSessionRef.current = true;
799
729
 
800
730
  // Update cache with new events using user-specific key
801
731
  setCachedEvents(updatedEvents);
802
- localStorage.setItem(cacheKey, JSON.stringify({
803
- events: updatedEvents,
804
- lastFetched: Date.now(),
805
- totalCount: updatedEvents.length
806
- }));
732
+ const persistedCache = persistCachedEvents(cacheKey, updatedEvents);
733
+ if (persistedCache && persistedCache.events.length < updatedEvents.length) {
734
+ console.warn(`Persisted a trimmed GitHub events cache for "${cacheKey}" (${persistedCache.events.length}/${updatedEvents.length} events)`);
735
+ }
807
736
 
808
737
  // Update UI
809
738
  buildFilterOptionsFromEvents(updatedEvents);
@@ -820,14 +749,21 @@ export default function GithubEvents({
820
749
  console.log('No new events found');
821
750
 
822
751
  // Mark that we've fetched this session even if no new events
823
- sessionStorage.setItem(`${cacheKey}_session_fetched`, 'true');
752
+ setStorageItem(sessionStorage, `${cacheKey}_session_fetched`, 'true');
824
753
  fetchedThisSessionRef.current = true;
825
754
 
826
755
  // Just update the last fetched time with user-specific key
827
- const currentCache = JSON.parse(localStorage.getItem(cacheKey) || '{}');
828
- localStorage.setItem(cacheKey, JSON.stringify(_extends({}, currentCache, {
829
- lastFetched: Date.now()
830
- })));
756
+ const currentCache = getStorageItem(localStorage, cacheKey);
757
+ let parsedCache = null;
758
+ if (currentCache) {
759
+ try {
760
+ parsedCache = JSON.parse(currentCache);
761
+ } catch (parseError) {
762
+ console.warn(`Failed to parse cached GitHub events for "${cacheKey}"`, parseError);
763
+ removeStorageItem(localStorage, cacheKey);
764
+ }
765
+ }
766
+ updateCachedEventsTimestamp(cacheKey, parsedCache);
831
767
  setLastUpdated(format(new Date(), 'MMM d, yyyy h:mm a'));
832
768
 
833
769
  // Use existing cached data for display
@@ -919,13 +855,13 @@ export default function GithubEvents({
919
855
 
920
856
  // Check session storage to see if we've already fetched this session
921
857
  const sessionKey = `${cacheKey}_session_fetched`;
922
- const fetchedThisSession = sessionStorage.getItem(sessionKey) === 'true';
858
+ const fetchedThisSession = getStorageItem(sessionStorage, sessionKey) === 'true';
923
859
  console.log('Already fetched this session:', fetchedThisSession);
924
860
  fetchedThisSessionRef.current = fetchedThisSession;
925
861
 
926
862
  // Debug all localStorage keys to make sure we're looking at the right one
927
- console.log('All localStorage keys:', Object.keys(localStorage));
928
- const cached = localStorage.getItem(cacheKey);
863
+ console.log('All localStorage keys:', getStorageKeys(localStorage));
864
+ const cached = getStorageItem(localStorage, cacheKey);
929
865
  console.log(`LocalStorage for "${cacheKey}" exists:`, !!cached);
930
866
  if (cached) {
931
867
  try {
@@ -968,7 +904,7 @@ export default function GithubEvents({
968
904
  setTimeout(() => {
969
905
  fetchNewEvents();
970
906
  // Mark that we've fetched this session
971
- sessionStorage.setItem(sessionKey, 'true');
907
+ setStorageItem(sessionStorage, sessionKey, 'true');
972
908
  fetchedThisSessionRef.current = true;
973
909
  }, 100);
974
910
  } else {
@@ -989,6 +925,7 @@ export default function GithubEvents({
989
925
  }
990
926
  } catch (err) {
991
927
  console.error('Failed to parse cached events, fetching new data:', err);
928
+ removeStorageItem(localStorage, cacheKey);
992
929
  fetchAllGitHubEvents();
993
930
  }
994
931
  } else {
@@ -1429,24 +1366,8 @@ export default function GithubEvents({
1429
1366
  event: selectedEvent
1430
1367
  }) : selectedEvent.actionType === 'IssueCommentEvent' ? /*#__PURE__*/_jsx(IssueCommentEvent, {
1431
1368
  event: selectedEvent
1432
- }) : /*#__PURE__*/_jsx(ReactJson, {
1433
- src: selectedEvent,
1434
- name: false,
1435
- theme: "monokai",
1436
- displayDataTypes: false,
1437
- enableClipboard: false,
1438
- displayObjectSize: false,
1439
- collapsed: 1,
1440
- collapseStringsAfterLength: 50,
1441
- style: {
1442
- backgroundColor: 'transparent',
1443
- fontSize: '0.875rem',
1444
- fontFamily: 'monospace',
1445
- padding: '8px',
1446
- borderRadius: '4px',
1447
- overflow: 'auto',
1448
- maxHeight: 'calc(100vh - 200px)'
1449
- }
1369
+ }) : /*#__PURE__*/_jsx(JsonFallbackView, {
1370
+ value: selectedEvent
1450
1371
  })
1451
1372
  })]
1452
1373
  })]
@@ -0,0 +1,41 @@
1
+ import getBranchCompareDetails from './getBranchCompareDetails';
2
+ function getQueryValue(value) {
3
+ return Array.isArray(value) ? value[0] : value;
4
+ }
5
+ export default function createGithubBranchHandler() {
6
+ return async function handler(req, res) {
7
+ if (req.method !== 'GET') {
8
+ var _res$setHeader;
9
+ (_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
10
+ return res.status(405).json({
11
+ message: 'Method not allowed'
12
+ });
13
+ }
14
+ const owner = getQueryValue(req.query.owner);
15
+ const repo = getQueryValue(req.query.repo);
16
+ const base = getQueryValue(req.query.base);
17
+ const head = getQueryValue(req.query.head);
18
+ if (!owner || !repo || !base || !head) {
19
+ return res.status(400).json({
20
+ message: 'owner, repo, base, and head are required'
21
+ });
22
+ }
23
+ try {
24
+ var _res$setHeader2;
25
+ const data = await getBranchCompareDetails({
26
+ owner,
27
+ repo,
28
+ base,
29
+ head
30
+ });
31
+ (_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=300, stale-while-revalidate=3600');
32
+ return res.status(200).json(data);
33
+ } catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ const status = message.includes('Missing required parameters') ? 400 : 502;
36
+ return res.status(status).json({
37
+ message
38
+ });
39
+ }
40
+ };
41
+ }
@@ -0,0 +1,39 @@
1
+ import getCommitDetails from './getCommitDetails';
2
+ function getQueryValue(value) {
3
+ return Array.isArray(value) ? value[0] : value;
4
+ }
5
+ export default function createGithubCommitHandler() {
6
+ return async function handler(req, res) {
7
+ if (req.method !== 'GET') {
8
+ var _res$setHeader;
9
+ (_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
10
+ return res.status(405).json({
11
+ message: 'Method not allowed'
12
+ });
13
+ }
14
+ const owner = getQueryValue(req.query.owner);
15
+ const repo = getQueryValue(req.query.repo);
16
+ const ref = getQueryValue(req.query.ref);
17
+ if (!owner || !repo || !ref) {
18
+ return res.status(400).json({
19
+ message: 'owner, repo, and ref are required'
20
+ });
21
+ }
22
+ try {
23
+ var _res$setHeader2;
24
+ const data = await getCommitDetails({
25
+ owner,
26
+ repo,
27
+ ref
28
+ });
29
+ (_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=300, stale-while-revalidate=3600');
30
+ return res.status(200).json(data);
31
+ } catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ const status = message.includes('Missing required parameters') ? 400 : 502;
34
+ return res.status(status).json({
35
+ message
36
+ });
37
+ }
38
+ };
39
+ }
@@ -0,0 +1,41 @@
1
+ import getGithubContributions from './getGithubContributions';
2
+ function getQueryValue(value) {
3
+ return Array.isArray(value) ? value[0] : value;
4
+ }
5
+ export default function createGithubContributionsHandler(config = {}) {
6
+ return async function handler(req, res) {
7
+ if (req.method !== 'GET') {
8
+ var _res$setHeader;
9
+ (_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
10
+ return res.status(405).json({
11
+ message: 'Method not allowed'
12
+ });
13
+ }
14
+ const githubUser = getQueryValue(req.query.username);
15
+ const from = getQueryValue(req.query.from);
16
+ const to = getQueryValue(req.query.to);
17
+ if (!githubUser) {
18
+ return res.status(400).json({
19
+ message: 'username is required'
20
+ });
21
+ }
22
+ try {
23
+ var _config$getGithubToke, _res$setHeader2;
24
+ const githubToken = ((_config$getGithubToke = config.getGithubToken) == null ? void 0 : _config$getGithubToke.call(config, req)) || process.env.GITHUB_TOKEN;
25
+ const data = await getGithubContributions({
26
+ githubUser,
27
+ githubToken,
28
+ from,
29
+ to
30
+ });
31
+ (_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=3600, stale-while-revalidate=86400');
32
+ return res.status(200).json(data);
33
+ } catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ const status = message.includes('username is required') ? 400 : message.includes('No contribution calendar returned') ? 404 : message.includes('GitHub token not configured') ? 500 : 502;
36
+ return res.status(status).json({
37
+ message
38
+ });
39
+ }
40
+ };
41
+ }
@@ -0,0 +1,50 @@
1
+ import githubEventsQuery from './getGithubEvents';
2
+ function getQueryValue(value) {
3
+ return Array.isArray(value) ? value[0] : value;
4
+ }
5
+ function parseNumber(value, fallback) {
6
+ const parsed = Number(getQueryValue(value));
7
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
8
+ }
9
+ export default function createGithubEventsHandler(config = {}) {
10
+ return async function handler(req, res) {
11
+ if (req.method !== 'GET') {
12
+ var _res$setHeader;
13
+ (_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
14
+ return res.status(405).json({
15
+ message: 'Method not allowed'
16
+ });
17
+ }
18
+ const githubUser = getQueryValue(req.query.username);
19
+ if (!githubUser) {
20
+ return res.status(400).json({
21
+ message: 'username is required'
22
+ });
23
+ }
24
+ const query = {
25
+ page: parseNumber(req.query.page, 1),
26
+ per_page: parseNumber(req.query.per_page, 40),
27
+ repo: getQueryValue(req.query.repo) || undefined,
28
+ action: getQueryValue(req.query.action) || undefined,
29
+ date: getQueryValue(req.query.date) || undefined,
30
+ description: getQueryValue(req.query.description) || undefined
31
+ };
32
+ try {
33
+ var _config$getGithubToke, _res$setHeader2;
34
+ const githubToken = ((_config$getGithubToke = config.getGithubToken) == null ? void 0 : _config$getGithubToke.call(config, req)) || process.env.GITHUB_TOKEN;
35
+ const data = await githubEventsQuery({
36
+ query,
37
+ githubUser,
38
+ githubToken
39
+ });
40
+ (_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=300, stale-while-revalidate=3600');
41
+ return res.status(200).json(data);
42
+ } catch (error) {
43
+ const message = error instanceof Error ? error.message : String(error);
44
+ const status = message.includes('username is required') ? 400 : 502;
45
+ return res.status(status).json({
46
+ message
47
+ });
48
+ }
49
+ };
50
+ }