@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
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = createGithubEventsHandler;
8
+ var _getGithubEvents = _interopRequireDefault(require("./getGithubEvents"));
9
+ function getQueryValue(value) {
10
+ return Array.isArray(value) ? value[0] : value;
11
+ }
12
+ function parseNumber(value, fallback) {
13
+ const parsed = Number(getQueryValue(value));
14
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
15
+ }
16
+ function createGithubEventsHandler(config = {}) {
17
+ return async function handler(req, res) {
18
+ if (req.method !== 'GET') {
19
+ var _res$setHeader;
20
+ (_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
21
+ return res.status(405).json({
22
+ message: 'Method not allowed'
23
+ });
24
+ }
25
+ const githubUser = getQueryValue(req.query.username);
26
+ if (!githubUser) {
27
+ return res.status(400).json({
28
+ message: 'username is required'
29
+ });
30
+ }
31
+ const query = {
32
+ page: parseNumber(req.query.page, 1),
33
+ per_page: parseNumber(req.query.per_page, 40),
34
+ repo: getQueryValue(req.query.repo) || undefined,
35
+ action: getQueryValue(req.query.action) || undefined,
36
+ date: getQueryValue(req.query.date) || undefined,
37
+ description: getQueryValue(req.query.description) || undefined
38
+ };
39
+ try {
40
+ var _config$getGithubToke, _res$setHeader2;
41
+ const githubToken = ((_config$getGithubToke = config.getGithubToken) == null ? void 0 : _config$getGithubToke.call(config, req)) || process.env.GITHUB_TOKEN;
42
+ const data = await (0, _getGithubEvents.default)({
43
+ query,
44
+ githubUser,
45
+ githubToken
46
+ });
47
+ (_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=300, stale-while-revalidate=3600');
48
+ return res.status(200).json(data);
49
+ } catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ const status = message.includes('username is required') ? 400 : 502;
52
+ return res.status(status).json({
53
+ message
54
+ });
55
+ }
56
+ };
57
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = getBranchCompareDetails;
7
+ var _githubApi = require("./githubApi");
8
+ async function getBranchCompareDetails(params) {
9
+ const {
10
+ owner,
11
+ repo,
12
+ base,
13
+ head
14
+ } = params;
15
+ if (!owner || !repo || !base || !head) {
16
+ throw new Error('Missing required parameters: owner, repo, base, head');
17
+ }
18
+ const compare = await (0, _githubApi.fetchGithubResource)(`/repos/${owner}/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`);
19
+ const commits = (compare.commits || []).map(commit => (0, _githubApi.normalizeGithubCommit)(commit));
20
+ const files = (compare.files || []).map(file => (0, _githubApi.normalizeGithubFile)(file));
21
+ return {
22
+ repo: `${owner}/${repo}`,
23
+ baseRef: base,
24
+ headRef: head,
25
+ status: compare.status || 'unknown',
26
+ aheadBy: compare.ahead_by || 0,
27
+ behindBy: compare.behind_by || 0,
28
+ totalCommits: compare.total_commits || commits.length,
29
+ url: compare.html_url || `https://github.com/${owner}/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`,
30
+ contributors: (0, _githubApi.buildGithubContributors)(compare.commits || []),
31
+ commits,
32
+ files,
33
+ stats: (0, _githubApi.summarizeGithubStats)(files)
34
+ };
35
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = getCommitDetails;
7
+ var _githubApi = require("./githubApi");
8
+ async function getCommitDetails(params) {
9
+ var _commit$commit, _commit$commit2, _commit$commit3, _commit$commit4;
10
+ const {
11
+ owner,
12
+ repo,
13
+ ref
14
+ } = params;
15
+ if (!owner || !repo || !ref) {
16
+ throw new Error('Missing required parameters: owner, repo, ref');
17
+ }
18
+ const commit = await (0, _githubApi.fetchGithubResource)(`/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`);
19
+ const files = (commit.files || []).map(file => (0, _githubApi.normalizeGithubFile)(file));
20
+ const commits = [(0, _githubApi.normalizeGithubCommit)(commit)];
21
+ const contributor = (0, _githubApi.buildGithubContributors)([commit])[0] || {
22
+ login: commits[0].author.login,
23
+ name: commits[0].author.name,
24
+ avatarUrl: commits[0].author.avatar,
25
+ contributions: 1
26
+ };
27
+ return {
28
+ repo: `${owner}/${repo}`,
29
+ ref: commit.sha || ref,
30
+ shortRef: (0, _githubApi.getGithubShortRef)(commit.sha || ref),
31
+ url: commit.html_url || `https://github.com/${owner}/${repo}/commit/${encodeURIComponent(commit.sha || ref)}`,
32
+ summary: (0, _githubApi.getGithubMessageSummary)(((_commit$commit = commit.commit) == null ? void 0 : _commit$commit.message) || ''),
33
+ message: ((_commit$commit2 = commit.commit) == null ? void 0 : _commit$commit2.message) || '',
34
+ committedAt: ((_commit$commit3 = commit.commit) == null || (_commit$commit3 = _commit$commit3.author) == null ? void 0 : _commit$commit3.date) || ((_commit$commit4 = commit.commit) == null || (_commit$commit4 = _commit$commit4.committer) == null ? void 0 : _commit$commit4.date) || '',
35
+ contributor,
36
+ commits,
37
+ files,
38
+ stats: (0, _githubApi.summarizeGithubStats)(files)
39
+ };
40
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = getGithubContributions;
7
+ const CONTRIBUTION_LEVEL_MAP = {
8
+ NONE: 0,
9
+ FIRST_QUARTILE: 1,
10
+ SECOND_QUARTILE: 2,
11
+ THIRD_QUARTILE: 3,
12
+ FOURTH_QUARTILE: 4
13
+ };
14
+ const GITHUB_CONTRIBUTIONS_QUERY = `
15
+ query GithubContributions($login: String!, $from: DateTime!, $to: DateTime!) {
16
+ user(login: $login) {
17
+ contributionsCollection(from: $from, to: $to) {
18
+ contributionCalendar {
19
+ totalContributions
20
+ weeks {
21
+ contributionDays {
22
+ date
23
+ contributionCount
24
+ contributionLevel
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ `;
32
+ function isValidDateInput(value) {
33
+ if (!value) {
34
+ return false;
35
+ }
36
+ return !Number.isNaN(new Date(value).getTime());
37
+ }
38
+ function toDateRange(from, to) {
39
+ const rangeEnd = isValidDateInput(to) ? new Date(to) : new Date();
40
+ const rangeStart = isValidDateInput(from) ? new Date(from) : new Date(rangeEnd);
41
+ if (!isValidDateInput(from)) {
42
+ rangeStart.setFullYear(rangeEnd.getFullYear() - 1);
43
+ }
44
+ if (rangeStart > rangeEnd) {
45
+ throw new Error('Invalid contribution range: "from" must be before "to".');
46
+ }
47
+ return {
48
+ from: rangeStart,
49
+ to: rangeEnd
50
+ };
51
+ }
52
+ function buildContributionTotals(contributions) {
53
+ return contributions.reduce((acc, contribution) => {
54
+ const year = contribution.date.slice(0, 4);
55
+ acc[year] = (acc[year] || 0) + contribution.count;
56
+ return acc;
57
+ }, {});
58
+ }
59
+ function buildCountLabel(total, from, to) {
60
+ const fromYear = from.getFullYear();
61
+ const toYear = to.getFullYear();
62
+ if (fromYear === toYear) {
63
+ return `${total} contributions in ${fromYear}`;
64
+ }
65
+ return `${total} contributions from ${fromYear} to ${toYear}`;
66
+ }
67
+ async function getGithubContributions({
68
+ githubUser,
69
+ githubToken = process.env.GITHUB_TOKEN,
70
+ from,
71
+ to
72
+ }) {
73
+ var _payload$errors2, _payload$data;
74
+ if (!githubUser) {
75
+ throw new Error('Missing required parameter: githubUser');
76
+ }
77
+ if (!githubToken) {
78
+ throw new Error('GitHub token not configured');
79
+ }
80
+ const range = toDateRange(from, to);
81
+ const response = await fetch('https://api.github.com/graphql', {
82
+ method: 'POST',
83
+ headers: {
84
+ 'Content-Type': 'application/json',
85
+ 'User-Agent': 'stoked-ui-github-calendar',
86
+ Authorization: `Bearer ${githubToken}`
87
+ },
88
+ body: JSON.stringify({
89
+ query: GITHUB_CONTRIBUTIONS_QUERY,
90
+ variables: {
91
+ login: githubUser,
92
+ from: range.from.toISOString(),
93
+ to: range.to.toISOString()
94
+ }
95
+ })
96
+ });
97
+ const payload = await response.json();
98
+ if (!response.ok) {
99
+ var _payload$errors;
100
+ const message = (payload == null ? void 0 : payload.message) || (payload == null || (_payload$errors = payload.errors) == null || (_payload$errors = _payload$errors[0]) == null ? void 0 : _payload$errors.message) || `GitHub GraphQL error: ${response.status}`;
101
+ throw new Error(message);
102
+ }
103
+ if (payload != null && (_payload$errors2 = payload.errors) != null && _payload$errors2.length) {
104
+ throw new Error(payload.errors.map(error => error.message || 'Unknown GitHub GraphQL error').join('; '));
105
+ }
106
+ const calendar = payload == null || (_payload$data = payload.data) == null || (_payload$data = _payload$data.user) == null || (_payload$data = _payload$data.contributionsCollection) == null ? void 0 : _payload$data.contributionCalendar;
107
+ if (!calendar) {
108
+ throw new Error(`No contribution calendar returned for "${githubUser}".`);
109
+ }
110
+ const contributions = (calendar.weeks || []).flatMap(week => week.contributionDays || []).map(day => {
111
+ var _CONTRIBUTION_LEVEL_M;
112
+ return {
113
+ date: day.date,
114
+ count: day.contributionCount,
115
+ level: (_CONTRIBUTION_LEVEL_M = CONTRIBUTION_LEVEL_MAP[day.contributionLevel]) != null ? _CONTRIBUTION_LEVEL_M : 0
116
+ };
117
+ }).sort((a, b) => {
118
+ if (a.date < b.date) {
119
+ return -1;
120
+ }
121
+ if (a.date > b.date) {
122
+ return 1;
123
+ }
124
+ return 0;
125
+ });
126
+ const total = buildContributionTotals(contributions);
127
+ return {
128
+ total,
129
+ contributions,
130
+ countLabel: buildCountLabel(calendar.totalContributions || 0, range.from, range.to)
131
+ };
132
+ }
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ exports.githubEventsQuery = githubEventsQuery;
8
+ function parseLinkHeader(header) {
9
+ if (!header) return {};
10
+ return header.split(',').reduce((links, part) => {
11
+ const match = part.match(/<(.+)>;\s*rel="([\w]+)"/);
12
+ if (match) {
13
+ const [, url, rel] = match;
14
+ if (rel === 'next' || rel === 'last') {
15
+ links[rel] = url;
16
+ }
17
+ }
18
+ return links;
19
+ }, {});
20
+ }
21
+ async function githubEventsQuery({
22
+ query,
23
+ githubUser,
24
+ githubToken
25
+ }) {
26
+ try {
27
+ const {
28
+ page = query.page || 1,
29
+ per_page = query.per_page || 100,
30
+ repo,
31
+ action,
32
+ date,
33
+ description
34
+ } = query;
35
+ const pageNum = Number(page);
36
+ const perPage = Number(per_page);
37
+ console.log(`Fetching events for user: ${githubUser}, page: ${pageNum}, per_page: ${perPage}`);
38
+ let allEvents = [];
39
+ let hasMore = true;
40
+ let githubPage = 1;
41
+ const maxPages = 30;
42
+ const fetchPerPage = 100;
43
+ while (hasMore && githubPage <= maxPages) {
44
+ console.log(`Fetching page ${githubPage}...`);
45
+ const fetchOptions = {
46
+ headers: {
47
+ 'User-Agent': 'brianstoker.com-website'
48
+ }
49
+ };
50
+ if (githubToken) {
51
+ fetchOptions.headers.Authorization = `token ${githubToken}`;
52
+ }
53
+ const queryParams = new URLSearchParams({
54
+ page: String(githubPage),
55
+ per_page: String(fetchPerPage)
56
+ });
57
+ const response = await fetch(`https://api.github.com/users/${githubUser}/events?${queryParams}`, fetchOptions);
58
+ if (!response.ok) {
59
+ const errorText = await response.text();
60
+ console.error(`GitHub API error: ${response.status}`, errorText);
61
+ throw new Error(`GitHub API error: ${response.status} - ${errorText}`);
62
+ }
63
+ const data = await response.json();
64
+ console.log(`Page ${githubPage}: Received ${data.length} events`);
65
+ if (data.length === 0) {
66
+ hasMore = false;
67
+ } else {
68
+ allEvents = [...allEvents, ...data];
69
+ console.log(`Total events so far: ${allEvents.length}`);
70
+ const linkHeader = response.headers.get('Link');
71
+ const links = parseLinkHeader(linkHeader);
72
+ hasMore = !!links.next;
73
+ githubPage++;
74
+ }
75
+ }
76
+ allEvents = Array.from(new Map(allEvents.map(event => [event.id, event])).values());
77
+ console.log(`Final total events: ${allEvents.length}`);
78
+ let filteredEvents = allEvents;
79
+ if (repo) {
80
+ filteredEvents = filteredEvents.filter(event => event.repo.name === repo);
81
+ }
82
+ if (action) {
83
+ filteredEvents = filteredEvents.filter(event => event.type.replace('Event', '') === action);
84
+ }
85
+ if (date) {
86
+ const now = new Date();
87
+ let cutoffDate;
88
+ switch (date) {
89
+ case 'today':
90
+ cutoffDate = new Date(now.setHours(0, 0, 0, 0));
91
+ break;
92
+ case 'yesterday':
93
+ cutoffDate = new Date(now);
94
+ cutoffDate.setDate(cutoffDate.getDate() - 1);
95
+ cutoffDate.setHours(0, 0, 0, 0);
96
+ break;
97
+ case 'week':
98
+ cutoffDate = new Date(now);
99
+ cutoffDate.setDate(cutoffDate.getDate() - 7);
100
+ cutoffDate.setHours(0, 0, 0, 0);
101
+ break;
102
+ case 'month':
103
+ cutoffDate = new Date(now);
104
+ cutoffDate.setMonth(cutoffDate.getMonth() - 1);
105
+ cutoffDate.setHours(0, 0, 0, 0);
106
+ break;
107
+ default:
108
+ cutoffDate = new Date(0);
109
+ }
110
+ filteredEvents = filteredEvents.filter(event => new Date(event.created_at) >= cutoffDate);
111
+ }
112
+ if (description) {
113
+ filteredEvents = filteredEvents.filter(event => {
114
+ var _event$payload$commit, _event$payload$pull_r, _event$payload$issue, _event$payload$issue2;
115
+ let eventDescription = '';
116
+ if (event.type === 'PushEvent' && (_event$payload$commit = event.payload.commits) != null && _event$payload$commit.length) {
117
+ eventDescription = `Pushed ${event.payload.commits.length} commits`;
118
+ } else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r = event.payload.pull_request) != null && _event$payload$pull_r.title) {
119
+ eventDescription = event.payload.pull_request.title;
120
+ } else if (event.type === 'IssuesEvent' && (_event$payload$issue = event.payload.issue) != null && _event$payload$issue.title) {
121
+ eventDescription = event.payload.issue.title;
122
+ } else if (event.type === 'IssueCommentEvent' && (_event$payload$issue2 = event.payload.issue) != null && _event$payload$issue2.title) {
123
+ eventDescription = `Commented on issue: ${event.payload.issue.title}`;
124
+ }
125
+ return eventDescription.toLowerCase().includes(description.toLowerCase());
126
+ });
127
+ }
128
+ const startIndex = (pageNum - 1) * perPage;
129
+ const endIndex = startIndex + perPage;
130
+ const paginatedEvents = filteredEvents.slice(startIndex, endIndex);
131
+ const repositories = Array.from(new Set(allEvents.map(event => event.repo.name))).sort();
132
+ const actionTypes = Array.from(new Set(allEvents.map(event => event.type.replace('Event', '')))).sort();
133
+ return {
134
+ events: paginatedEvents,
135
+ total: filteredEvents.length,
136
+ repositories,
137
+ actionTypes,
138
+ page: pageNum,
139
+ per_page: perPage,
140
+ total_pages: Math.ceil(filteredEvents.length / perPage),
141
+ total_fetched_events: allEvents.length,
142
+ max_pages_fetched: githubPage - 1
143
+ };
144
+ } catch (error) {
145
+ console.error('Error fetching GitHub events:', error);
146
+ throw new Error(`${error instanceof Error ? error.message : String(error)}`);
147
+ }
148
+ }
149
+ var _default = exports.default = githubEventsQuery;
@@ -44,7 +44,7 @@ async function getPullRequestDetails(params) {
44
44
  if (githubToken) {
45
45
  headers.Authorization = `token ${githubToken}`;
46
46
  }
47
- async function fetchWithRateLimit(url) {
47
+ const fetchWithRateLimit = async url => {
48
48
  const response = await fetch(url, {
49
49
  headers
50
50
  });
@@ -66,7 +66,7 @@ async function getPullRequestDetails(params) {
66
66
  data: await response.json(),
67
67
  rateLimit
68
68
  };
69
- }
69
+ };
70
70
 
71
71
  // Fetch basic PR information
72
72
  const {
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.buildGithubContributors = buildGithubContributors;
7
+ exports.fetchGithubResource = fetchGithubResource;
8
+ exports.getGithubMessageSummary = getGithubMessageSummary;
9
+ exports.getGithubShortRef = getGithubShortRef;
10
+ exports.normalizeGithubCommit = normalizeGithubCommit;
11
+ exports.normalizeGithubFile = normalizeGithubFile;
12
+ exports.parseGithubDiff = parseGithubDiff;
13
+ exports.summarizeGithubStats = summarizeGithubStats;
14
+ const GITHUB_API_BASE_URL = 'https://api.github.com';
15
+ const DEFAULT_DIFF_LINE_LIMIT = 24;
16
+ function getGithubHeaders() {
17
+ const githubToken = process.env.GITHUB_TOKEN;
18
+ const headers = {
19
+ 'User-Agent': 'stoked-ui-github-components',
20
+ Accept: 'application/vnd.github+json'
21
+ };
22
+ if (githubToken) {
23
+ headers.Authorization = `token ${githubToken}`;
24
+ }
25
+ return headers;
26
+ }
27
+ async function fetchGithubResource(path) {
28
+ const response = await fetch(`${GITHUB_API_BASE_URL}${path}`, {
29
+ headers: getGithubHeaders()
30
+ });
31
+ const rateLimit = {
32
+ remaining: response.headers.get('x-ratelimit-remaining'),
33
+ reset: response.headers.get('x-ratelimit-reset')
34
+ };
35
+ if (!response.ok) {
36
+ const body = await response.text();
37
+ if (response.status === 403 && rateLimit.remaining === '0') {
38
+ const resetDate = rateLimit.reset ? new Date(Number(rateLimit.reset) * 1000).toLocaleString() : 'later';
39
+ throw new Error(`GitHub rate limit exceeded. Resets at ${resetDate}.`);
40
+ }
41
+ throw new Error(body || `GitHub API error: ${response.status}`);
42
+ }
43
+ return response.json();
44
+ }
45
+ function parseGithubDiff(patch, maxLines = DEFAULT_DIFF_LINE_LIMIT) {
46
+ if (!patch) {
47
+ return [];
48
+ }
49
+ const patchLines = patch.split('\n');
50
+ const visibleLines = patchLines.slice(0, maxLines);
51
+ const diffLines = visibleLines.map((line, index) => {
52
+ let type = 'context';
53
+ if (line.startsWith('+')) {
54
+ type = 'addition';
55
+ } else if (line.startsWith('-')) {
56
+ type = 'deletion';
57
+ }
58
+ return {
59
+ type,
60
+ content: line,
61
+ lineNumber: index + 1
62
+ };
63
+ });
64
+ if (patchLines.length > maxLines) {
65
+ diffLines.push({
66
+ type: 'context',
67
+ content: `... ${patchLines.length - maxLines} more diff lines`,
68
+ lineNumber: diffLines.length + 1
69
+ });
70
+ }
71
+ return diffLines;
72
+ }
73
+ function toFileChangeType(status) {
74
+ switch (status) {
75
+ case 'added':
76
+ return 'added';
77
+ case 'removed':
78
+ return 'deleted';
79
+ default:
80
+ return 'modified';
81
+ }
82
+ }
83
+ function normalizeGithubFile(file, maxDiffLines = DEFAULT_DIFF_LINE_LIMIT) {
84
+ return {
85
+ path: file.filename || file.path || 'unknown',
86
+ type: toFileChangeType(file.status),
87
+ additions: file.additions || 0,
88
+ deletions: file.deletions || 0,
89
+ diff: file.diff || parseGithubDiff(file.patch, maxDiffLines)
90
+ };
91
+ }
92
+ function getGithubIdentity(commit) {
93
+ var _commit$commit, _commit$commit2;
94
+ const apiAuthor = commit.author || commit.committer || {};
95
+ const commitAuthor = ((_commit$commit = commit.commit) == null ? void 0 : _commit$commit.author) || ((_commit$commit2 = commit.commit) == null ? void 0 : _commit$commit2.committer) || {};
96
+ return {
97
+ login: apiAuthor.login || commitAuthor.name || commitAuthor.email || commit.sha || 'unknown',
98
+ name: commitAuthor.name || apiAuthor.login || commitAuthor.email || 'Unknown author',
99
+ avatarUrl: apiAuthor.avatar_url || ''
100
+ };
101
+ }
102
+ function normalizeGithubCommit(commit) {
103
+ var _commit$commit3, _commit$commit4, _commit$commit5;
104
+ const identity = getGithubIdentity(commit);
105
+ return {
106
+ id: commit.sha || commit.node_id || identity.login,
107
+ message: ((_commit$commit3 = commit.commit) == null ? void 0 : _commit$commit3.message) || '',
108
+ author: {
109
+ name: identity.name,
110
+ login: identity.login,
111
+ avatar: identity.avatarUrl
112
+ },
113
+ date: ((_commit$commit4 = commit.commit) == null || (_commit$commit4 = _commit$commit4.author) == null ? void 0 : _commit$commit4.date) || ((_commit$commit5 = commit.commit) == null || (_commit$commit5 = _commit$commit5.committer) == null ? void 0 : _commit$commit5.date) || '',
114
+ hash: commit.sha || '',
115
+ url: commit.html_url || ''
116
+ };
117
+ }
118
+ function buildGithubContributors(commits) {
119
+ const contributors = new Map();
120
+ commits.forEach(commit => {
121
+ const identity = getGithubIdentity(commit);
122
+ const key = identity.login || identity.name;
123
+ const current = contributors.get(key);
124
+ if (current) {
125
+ current.contributions += 1;
126
+ if (!current.avatarUrl && identity.avatarUrl) {
127
+ current.avatarUrl = identity.avatarUrl;
128
+ }
129
+ if (current.name === 'Unknown author' && identity.name) {
130
+ current.name = identity.name;
131
+ }
132
+ return;
133
+ }
134
+ contributors.set(key, {
135
+ login: identity.login,
136
+ name: identity.name,
137
+ avatarUrl: identity.avatarUrl,
138
+ contributions: 1
139
+ });
140
+ });
141
+ return Array.from(contributors.values()).sort((a, b) => {
142
+ if (b.contributions !== a.contributions) {
143
+ return b.contributions - a.contributions;
144
+ }
145
+ return a.login.localeCompare(b.login);
146
+ });
147
+ }
148
+ function summarizeGithubStats(files) {
149
+ return files.reduce((stats, file) => ({
150
+ additions: stats.additions + file.additions,
151
+ deletions: stats.deletions + file.deletions,
152
+ changedFiles: stats.changedFiles + 1
153
+ }), {
154
+ additions: 0,
155
+ deletions: 0,
156
+ changedFiles: 0
157
+ });
158
+ }
159
+ function getGithubMessageSummary(message) {
160
+ var _message$split$;
161
+ return ((_message$split$ = message.split('\n')[0]) == null ? void 0 : _message$split$.trim()) || 'Untitled commit';
162
+ }
163
+ function getGithubShortRef(ref, length = 7) {
164
+ if (!ref) {
165
+ return '';
166
+ }
167
+ return ref.length > length ? ref.slice(0, length) : ref;
168
+ }
@@ -4,10 +4,73 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
+ Object.defineProperty(exports, "createGithubBranchHandler", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _createGithubBranchHandler.default;
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "createGithubCommitHandler", {
14
+ enumerable: true,
15
+ get: function () {
16
+ return _createGithubCommitHandler.default;
17
+ }
18
+ });
19
+ Object.defineProperty(exports, "createGithubContributionsHandler", {
20
+ enumerable: true,
21
+ get: function () {
22
+ return _createGithubContributionsHandler.default;
23
+ }
24
+ });
25
+ Object.defineProperty(exports, "createGithubEventsHandler", {
26
+ enumerable: true,
27
+ get: function () {
28
+ return _createGithubEventsHandler.default;
29
+ }
30
+ });
31
+ Object.defineProperty(exports, "getBranchCompareDetails", {
32
+ enumerable: true,
33
+ get: function () {
34
+ return _getBranchCompareDetails.default;
35
+ }
36
+ });
37
+ Object.defineProperty(exports, "getCommitDetails", {
38
+ enumerable: true,
39
+ get: function () {
40
+ return _getCommitDetails.default;
41
+ }
42
+ });
43
+ Object.defineProperty(exports, "getGithubContributions", {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _getGithubContributions.default;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "getGithubEvents", {
50
+ enumerable: true,
51
+ get: function () {
52
+ return _getGithubEvents.default;
53
+ }
54
+ });
7
55
  Object.defineProperty(exports, "getPullRequestDetails", {
8
56
  enumerable: true,
9
57
  get: function () {
10
58
  return _getPullRequestDetails.default;
11
59
  }
12
60
  });
13
- var _getPullRequestDetails = _interopRequireDefault(require("./getPullRequestDetails"));
61
+ Object.defineProperty(exports, "githubEventsQuery", {
62
+ enumerable: true,
63
+ get: function () {
64
+ return _getGithubEvents.githubEventsQuery;
65
+ }
66
+ });
67
+ var _createGithubBranchHandler = _interopRequireDefault(require("./createGithubBranchHandler"));
68
+ var _createGithubCommitHandler = _interopRequireDefault(require("./createGithubCommitHandler"));
69
+ var _getBranchCompareDetails = _interopRequireDefault(require("./getBranchCompareDetails"));
70
+ var _getCommitDetails = _interopRequireDefault(require("./getCommitDetails"));
71
+ var _getPullRequestDetails = _interopRequireDefault(require("./getPullRequestDetails"));
72
+ var _getGithubContributions = _interopRequireDefault(require("./getGithubContributions"));
73
+ var _createGithubContributionsHandler = _interopRequireDefault(require("./createGithubContributionsHandler"));
74
+ var _getGithubEvents = _interopRequireWildcard(require("./getGithubEvents"));
75
+ var _createGithubEventsHandler = _interopRequireDefault(require("./createGithubEventsHandler"));
76
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }