@@ -20,6 +20,17 @@ const octokit = new Octokit({
2020
2121const detailCache = new Map <string , { title: string ; body: string ; merged? : boolean ; url: string }>();
2222
23+ // Use globalThis to persist cache across requests
24+ const globalCache = globalThis as any ;
25+ if (! globalCache .__githubEventsCache ) {
26+ globalCache .__githubEventsCache = {
27+ data: null as DisplayEvent [] | null ,
28+ timestamp: 0 ,
29+ TTL: 5 * 60 * 1000 // 5 minutes in milliseconds
30+ };
31+ }
32+ const eventsCache = globalCache .__githubEventsCache ;
33+
2334const cleanDescription = (text : string | null | undefined ) => (text ? text .replace (/ [#*`_] / g , " " ).trim () : " " );
2435
2536const formatDate = (iso : string ) =>
@@ -47,66 +58,86 @@ async function fetchDetails(apiUrl: string) {
4758 }
4859}
4960
50- let events: DisplayEvent [] = [];
51-
52- try {
53- const res = await octokit .rest .activity .listPublicEventsForUser ({
54- username: " dsnsgithub" ,
55- per_page: 30 ,
56- headers: { " X-GitHub-Api-Version" : " 2022-11-28" }
57- });
58-
59- const allowedActions = [" opened" , " closed" , " reopened" ];
60- const ignoredTypes = [" PushEvent" , " IssueCommentEvent" , " PullRequestReviewCommentEvent" , " CommitCommentEvent" ];
61- const rawEvents = res .data .filter ((e ) => ! ignoredTypes .includes (e .type ! ));
62-
63- const processedPRs = new Set <string >();
64-
65- for (const event of rawEvents ) {
66- const { payload, actor, repo, created_at, id, type } = event ;
67- if (! created_at || ! id ) continue ;
61+ async function fetchGitHubEvents(): Promise <DisplayEvent []> {
62+ const events: DisplayEvent [] = [];
6863
69- const base = {
70- id ,
71- actor: { login: actor .login , avatar_url: actor .avatar_url },
72- repo: repo .name ,
73- timestamp: formatDate (created_at )
74- };
75-
76- if (type === " PullRequestEvent" || type === " PullRequestReviewEvent" ) {
77- const pr = (payload as any ).pull_request ;
78- const prKey = ` ${repo .name }#${pr .number } ` ;
79- if (! pr || processedPRs .has (prKey )) continue ;
80-
81- let verb = " " ;
82- if (type === " PullRequestEvent" && (payload as any ).action === " closed" && pr .merged ) {
83- verb = " merged" ;
84- } else if (type === " PullRequestReviewEvent" ) {
85- const state = (payload as any ).review .state ?.toLowerCase ();
86- if (state === " commented" ) continue ;
87- verb = state .replace (" _" , " " );
88- } else if (type === " PullRequestEvent" && allowedActions .includes ((payload as any ).action )) {
89- verb = (payload as any ).action ;
90- } else continue ;
91-
92- const details = await fetchDetails (pr .url );
93- processedPRs .add (prKey );
94- events .push ({ ... base , verb: verb + " pull request" , object: ` ${details .title } (#${pr .number }) ` , description: details .body , url: details .url });
95- } else if (type === " IssuesEvent" ) {
96- const issue = (payload as any ).issue ;
97- if (! issue ) continue ;
98- const details = await fetchDetails (issue .url );
99- events .push ({ ... base , verb: (payload as any ).action + " issue" , object: ` ${details .title } (#${issue .number }) ` , description: details .body , url: details .url });
100- } else if (type === " WatchEvent" ) {
101- events .push ({ ... base , verb: " starred" , object: repo .name , url: ` https://github.com/${repo .name } ` });
102- } else if (type === " ForkEvent" ) {
103- const forkee = (payload as any ).forkee ;
104- if (! forkee ) continue ;
105- events .push ({ ... base , verb: " forked" , object: repo .name , description: ` Original repository created by ${forkee .full_name } ` , url: forkee .html_url });
64+ try {
65+ const res = await octokit .rest .activity .listPublicEventsForUser ({
66+ username: " dsnsgithub" ,
67+ per_page: 30 ,
68+ headers: { " X-GitHub-Api-Version" : " 2022-11-28" }
69+ });
70+
71+ const allowedActions = [" opened" , " closed" , " reopened" ];
72+ const ignoredTypes = [" PushEvent" , " IssueCommentEvent" , " PullRequestReviewCommentEvent" , " CommitCommentEvent" ];
73+ const rawEvents = res .data .filter ((e ) => ! ignoredTypes .includes (e .type ! ));
74+
75+ const processedPRs = new Set <string >();
76+
77+ for (const event of rawEvents ) {
78+ const { payload, actor, repo, created_at, id, type } = event ;
79+ if (! created_at || ! id ) continue ;
80+
81+ const base = {
82+ id ,
83+ actor: { login: actor .login , avatar_url: actor .avatar_url },
84+ repo: repo .name ,
85+ timestamp: formatDate (created_at )
86+ };
87+
88+ if (type === " PullRequestEvent" || type === " PullRequestReviewEvent" ) {
89+ const pr = (payload as any ).pull_request ;
90+ const prKey = ` ${repo .name }#${pr .number } ` ;
91+ if (! pr || processedPRs .has (prKey )) continue ;
92+
93+ let verb = " " ;
94+ if (type === " PullRequestEvent" && (payload as any ).action === " closed" && pr .merged ) {
95+ verb = " merged" ;
96+ } else if (type === " PullRequestReviewEvent" ) {
97+ const state = (payload as any ).review .state ?.toLowerCase ();
98+ if (state === " commented" ) continue ;
99+ verb = state .replace (" _" , " " );
100+ } else if (type === " PullRequestEvent" && allowedActions .includes ((payload as any ).action )) {
101+ verb = (payload as any ).action ;
102+ } else continue ;
103+
104+ const details = await fetchDetails (pr .url );
105+ processedPRs .add (prKey );
106+ events .push ({ ... base , verb: verb + " pull request" , object: ` ${details .title } (#${pr .number }) ` , description: details .body , url: details .url });
107+ } else if (type === " IssuesEvent" ) {
108+ const issue = (payload as any ).issue ;
109+ if (! issue ) continue ;
110+ const details = await fetchDetails (issue .url );
111+ events .push ({ ... base , verb: (payload as any ).action + " issue" , object: ` ${details .title } (#${issue .number }) ` , description: details .body , url: details .url });
112+ } else if (type === " WatchEvent" ) {
113+ events .push ({ ... base , verb: " starred" , object: repo .name , url: ` https://github.com/${repo .name } ` });
114+ } else if (type === " ForkEvent" ) {
115+ const forkee = (payload as any ).forkee ;
116+ if (! forkee ) continue ;
117+ events .push ({ ... base , verb: " forked" , object: repo .name , description: ` Original repository created by ${forkee .full_name } ` , url: forkee .html_url });
118+ }
106119 }
120+ } catch (err ) {
121+ console .error (" GitHub fetch error:" , err );
107122 }
108- } catch (err ) {
109- console .error (" GitHub fetch error:" , err );
123+
124+ return events ;
125+ }
126+
127+ // Check cache and fetch if expired
128+ let events: DisplayEvent [] = [];
129+ const now = Date .now ();
130+
131+ if (eventsCache .data && now - eventsCache .timestamp < eventsCache .TTL ) {
132+ // Use cached data
133+ events = eventsCache .data ;
134+ console .log (" Using cached GitHub events" );
135+ } else {
136+ // Fetch fresh data and update cache
137+ events = await fetchGitHubEvents ();
138+ eventsCache .data = events ;
139+ eventsCache .timestamp = now ;
140+ console .log (" Fetched fresh GitHub events" );
110141}
111142---
112143
0 commit comments