Skip to content

Commit c78eea0

Browse files
committed
feat: axios-cache-interceptor
Signed-off-by: Adam Setch <[email protected]>
1 parent 7badde8 commit c78eea0

File tree

4 files changed

+7
-43
lines changed

4 files changed

+7
-43
lines changed

src/renderer/components/Sidebar.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { APPLICATION } from '../../shared/constants';
1616

1717
import { Constants } from '../constants';
1818
import { AppContext } from '../context/App';
19-
import { clearFullApiCache } from '../utils/api/request';
2019
import { quitApp } from '../utils/comms';
2120
import {
2221
openGitHubIssues,
@@ -64,8 +63,6 @@ export const Sidebar: FC = () => {
6463
const refreshNotifications = () => {
6564
navigate('/', { replace: true });
6665

67-
// Clear client cache so we fetch fresh data when user manually refreshes
68-
clearFullApiCache();
6966
fetchNotifications();
7067
};
7168

src/renderer/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export const Constants = {
2020

2121
ALL_READ_EMOJIS: ['🎉', '🎊', '🥳', '👏', '🙌', '😎', '🏖️', '🚀', '✨', '🏆'],
2222

23-
DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS: 60 * 1000, // 1 minute
24-
MIN_FETCH_NOTIFICATIONS_INTERVAL_MS: 60 * 1000, // 1 minute
23+
DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS: 5 * 1000, // 1 minute
24+
MIN_FETCH_NOTIFICATIONS_INTERVAL_MS: 5 * 1000, // 1 minute
2525
MAX_FETCH_NOTIFICATIONS_INTERVAL_MS: 60 * 60 * 1000, // 1 hour
2626
FETCH_NOTIFICATIONS_INTERVAL_STEP_MS: 60 * 1000, // 1 minute
2727

src/renderer/context/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import type {
2828
import { FetchType } from '../types';
2929
import type { Notification } from '../typesGitHub';
3030
import { headNotifications } from '../utils/api/client';
31-
import { clearFullApiCache } from '../utils/api/request';
3231
import type {
3332
LoginOAuthAppOptions,
3433
LoginPersonalAccessTokenOptions,
@@ -136,7 +135,6 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
136135

137136
// biome-ignore lint/correctness/useExhaustiveDependencies: We only want fetchNotifications to be called for particular state changes
138137
useEffect(() => {
139-
clearFullApiCache();
140138
fetchNotifications({ auth, settings });
141139
}, [
142140
auth.accounts,

src/renderer/utils/api/request.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,19 @@ import { getNextURLFromLinkHeader } from './utils';
1313

1414
type AxiosRequestConfigWithAccount = AxiosRequestConfig & { account: Account };
1515

16-
const MUTATION_HTTP_METHODS: Set<Method> = new Set(['PATCH', 'PUT', 'DELETE']);
17-
1816
const instance = Axios.create();
1917
const axios = setupCache(instance, {
2018
location: 'client',
2119

22-
// Respect ETags and cache headers from GitHub API
2320
interpretHeader: true,
2421

25-
// Set a reasonable TTL to ensure cache freshness (60 seconds)
26-
// This ensures external changes (GitHub web/mobile) are picked up periodically
27-
// ttl: 1000 * 60, // 60 seconds
22+
methods: ['get'],
2823

2924
cachePredicate: {
30-
ignoreUrls: ['/login/oauth/access_token'],
25+
ignoreUrls: ['login/oauth/access_token', 'notifications'],
3126
},
3227

33-
methods: ['get'],
34-
28+
// Generate unique cache keys per account to prevent cross-account pollution
3529
generateKey: buildKeyGenerator((request: AxiosRequestConfigWithAccount) => {
3630
return {
3731
method: request.method,
@@ -41,24 +35,6 @@ const axios = setupCache(instance, {
4135
}),
4236
});
4337

44-
// Invalidate cache on mutating requests (PATCH, PUT, DELETE)
45-
// Only clears cache entries for the same account that made the mutation
46-
axios.interceptors.response.use(
47-
async (response) => {
48-
const method = response.config.method?.toUpperCase() as Method;
49-
const config = response.config as AxiosRequestConfigWithAccount;
50-
51-
if (MUTATION_HTTP_METHODS.has(method) && config.account) {
52-
await clearFullApiCache();
53-
}
54-
return response;
55-
},
56-
(error: Error) => {
57-
// Pass through errors without clearing cache
58-
return Promise.reject(error);
59-
},
60-
);
61-
6238
/**
6339
* Perform an unauthenticated API request
6440
*
@@ -145,14 +121,15 @@ export async function apiRequestAuth(
145121
/**
146122
* Construct headers for API requests
147123
*
148-
* @param username
149124
* @param token
125+
* @param skipCache - If true, adds cache-control: no-cache to force fresh data
150126
* @returns
151127
*/
152128
async function getHeaders(token?: Token) {
153129
const headers: Record<string, string> = {
154130
Accept: 'application/json',
155131
'Content-Type': 'application/json',
132+
'Cache-Control': 'no-cache',
156133
};
157134

158135
if (token) {
@@ -163,11 +140,3 @@ async function getHeaders(token?: Token) {
163140

164141
return headers;
165142
}
166-
167-
export async function clearFullApiCache(): Promise<void> {
168-
try {
169-
axios.storage.clear();
170-
} catch (err) {
171-
rendererLogError('clearFullApiCache', 'Failed to clear API cache', err);
172-
}
173-
}

0 commit comments

Comments
 (0)