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
|
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;
} | null = null;
export async function initializeClients() {
const { address, apiKey, badgeCacheExpireMs, useBadgeCache } =
await getPluginSettings();
if (currentSettings) {
const addressChanged = currentSettings.address !== address;
const apiKeyChanged = currentSettings.apiKey !== apiKey;
const cacheTimeChanged =
currentSettings.badgeCacheExpireMs !== badgeCacheExpireMs;
const useBadgeCacheChanged =
currentSettings.useBadgeCache !== useBadgeCache;
if (!address || !apiKey) {
// Invalid configuration, clean
const persisterForCleanup = createChromeStorage();
await persisterForCleanup.removeClient();
cleanupApiClient();
return;
}
if (addressChanged || apiKeyChanged) {
// 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
) {
return;
}
}
if (address && apiKey) {
// Store current settings
currentSettings = { address, apiKey, badgeCacheExpireMs, useBadgeCache };
// 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}`,
};
},
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;
}
|