1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
import { QueryClient } from "@tanstack/react-query";
import { persistQueryClient } from "@tanstack/react-query-persist-client";
import { createTRPCClient, httpBatchLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import superjson from "superjson";
import type { AppRouter } from "@karakeep/trpc/routers/_app";
import { getPluginSettings } from "./settings";
import { createChromeStorage } from "./storagePersister";
export const api = createTRPCReact<AppRouter>();
let apiClient: ReturnType<typeof createTRPCClient<AppRouter>> | null = null;
let queryClient: QueryClient | null = null;
let currentSettings: {
address: string;
apiKey: string;
badgeCacheExpireMs: number;
useBadgeCache: boolean;
customHeaders: Record<string, string>;
} | null = null;
export async function initializeClients() {
const { address, apiKey, badgeCacheExpireMs, useBadgeCache, customHeaders } =
await getPluginSettings();
if (currentSettings) {
const addressChanged = currentSettings.address !== address;
const apiKeyChanged = currentSettings.apiKey !== apiKey;
const cacheTimeChanged =
currentSettings.badgeCacheExpireMs !== badgeCacheExpireMs;
const useBadgeCacheChanged =
currentSettings.useBadgeCache !== useBadgeCache;
const customHeadersChanged =
JSON.stringify(currentSettings.customHeaders) !==
JSON.stringify(customHeaders);
if (!address || !apiKey) {
// Invalid configuration, clean
const persisterForCleanup = createChromeStorage();
await persisterForCleanup.removeClient();
cleanupApiClient();
return;
}
if (addressChanged || apiKeyChanged || customHeadersChanged) {
// Switch context completely → discard the old instance and wipe persisted cache
const persisterForCleanup = createChromeStorage();
await persisterForCleanup.removeClient();
cleanupApiClient();
} else if ((cacheTimeChanged || useBadgeCacheChanged) && queryClient) {
// Change the cache policy only → Clean up the data, but reuse the instance
queryClient.clear();
}
// If there is already existing and there is no major change in settings, reuse it
if (
queryClient &&
apiClient &&
currentSettings &&
!addressChanged &&
!apiKeyChanged &&
!cacheTimeChanged &&
!useBadgeCacheChanged &&
!customHeadersChanged
) {
return;
}
}
if (address && apiKey) {
// Store current settings
currentSettings = {
address,
apiKey,
badgeCacheExpireMs,
useBadgeCache,
customHeaders,
};
// Create new QueryClient with updated settings
queryClient = new QueryClient();
const persister = createChromeStorage();
if (useBadgeCache) {
persistQueryClient({
queryClient,
persister,
// Avoid restoring very old data and bust on policy changes
maxAge: badgeCacheExpireMs * 2,
buster: `badge:${address}:${badgeCacheExpireMs}`,
});
} else {
// Ensure disk cache is cleared when caching is disabled
await persister.removeClient();
}
apiClient = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: `${address}/api/trpc`,
headers() {
return {
Authorization: `Bearer ${apiKey}`,
...customHeaders,
};
},
transformer: superjson,
}),
],
});
}
}
export async function getApiClient() {
if (!apiClient) {
await initializeClients();
}
return apiClient;
}
export async function getQueryClient() {
// Check if settings have changed and reinitialize if needed
await initializeClients();
return queryClient;
}
export function cleanupApiClient() {
apiClient = null;
queryClient = null;
currentSettings = null;
}
|