Skip to content

Commit f6a749d

Browse files
committed
refactor: extract backend settings schema
1 parent 1bfe51c commit f6a749d

2 files changed

Lines changed: 368 additions & 350 deletions

File tree

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
import { getDefaultPluginConfig } from "../config.js";
2+
import type { PluginConfig } from "../types.js";
3+
4+
export type BackendToggleSettingKey =
5+
| "liveAccountSync"
6+
| "sessionAffinity"
7+
| "proactiveRefreshGuardian"
8+
| "retryAllAccountsRateLimited"
9+
| "parallelProbing"
10+
| "storageBackupEnabled"
11+
| "preemptiveQuotaEnabled"
12+
| "fastSession"
13+
| "sessionRecovery"
14+
| "autoResume"
15+
| "perProjectAccounts";
16+
17+
export type BackendNumberSettingKey =
18+
| "liveAccountSyncDebounceMs"
19+
| "liveAccountSyncPollMs"
20+
| "sessionAffinityTtlMs"
21+
| "sessionAffinityMaxEntries"
22+
| "proactiveRefreshIntervalMs"
23+
| "proactiveRefreshBufferMs"
24+
| "parallelProbingMaxConcurrency"
25+
| "fastSessionMaxInputItems"
26+
| "networkErrorCooldownMs"
27+
| "serverErrorCooldownMs"
28+
| "fetchTimeoutMs"
29+
| "streamStallTimeoutMs"
30+
| "tokenRefreshSkewMs"
31+
| "preemptiveQuotaRemainingPercent5h"
32+
| "preemptiveQuotaRemainingPercent7d"
33+
| "preemptiveQuotaMaxDeferralMs";
34+
35+
export type BackendSettingFocusKey =
36+
| BackendToggleSettingKey
37+
| BackendNumberSettingKey
38+
| null;
39+
40+
export interface BackendToggleSettingOption {
41+
key: BackendToggleSettingKey;
42+
label: string;
43+
description: string;
44+
}
45+
46+
export interface BackendNumberSettingOption {
47+
key: BackendNumberSettingKey;
48+
label: string;
49+
description: string;
50+
min: number;
51+
max: number;
52+
step: number;
53+
unit: "ms" | "percent" | "count";
54+
}
55+
56+
export type BackendCategoryKey =
57+
| "session-sync"
58+
| "rotation-quota"
59+
| "refresh-recovery"
60+
| "performance-timeouts";
61+
62+
export interface BackendCategoryOption {
63+
key: BackendCategoryKey;
64+
label: string;
65+
description: string;
66+
toggleKeys: BackendToggleSettingKey[];
67+
numberKeys: BackendNumberSettingKey[];
68+
}
69+
70+
export type BackendCategoryConfigAction =
71+
| { type: "toggle"; key: BackendToggleSettingKey }
72+
| { type: "bump"; key: BackendNumberSettingKey; direction: -1 | 1 }
73+
| { type: "reset-category" }
74+
| { type: "back" };
75+
76+
export type BackendSettingsHubAction =
77+
| { type: "open-category"; key: BackendCategoryKey }
78+
| { type: "reset" }
79+
| { type: "save" }
80+
| { type: "cancel" };
81+
82+
export const BACKEND_TOGGLE_OPTIONS: BackendToggleSettingOption[] = [
83+
{
84+
key: "liveAccountSync",
85+
label: "Enable Live Sync",
86+
description: "Keep accounts synced when files change in another window.",
87+
},
88+
{
89+
key: "sessionAffinity",
90+
label: "Enable Session Affinity",
91+
description: "Try to keep each conversation on the same account.",
92+
},
93+
{
94+
key: "proactiveRefreshGuardian",
95+
label: "Enable Token Refresh Guard",
96+
description: "Refresh tokens early in the background.",
97+
},
98+
{
99+
key: "retryAllAccountsRateLimited",
100+
label: "Retry When All Rate-Limited",
101+
description: "If all accounts are limited, wait and try again.",
102+
},
103+
{
104+
key: "parallelProbing",
105+
label: "Enable Parallel Probing",
106+
description: "Check multiple accounts at the same time.",
107+
},
108+
{
109+
key: "storageBackupEnabled",
110+
label: "Enable Storage Backups",
111+
description: "Create a backup before account data changes.",
112+
},
113+
{
114+
key: "preemptiveQuotaEnabled",
115+
label: "Enable Quota Deferral",
116+
description: "Delay requests before limits are fully exhausted.",
117+
},
118+
{
119+
key: "fastSession",
120+
label: "Enable Fast Session Mode",
121+
description: "Use lighter request handling for faster responses.",
122+
},
123+
{
124+
key: "sessionRecovery",
125+
label: "Enable Session Recovery",
126+
description: "Restore recoverable sessions after restart.",
127+
},
128+
{
129+
key: "autoResume",
130+
label: "Enable Auto Resume",
131+
description: "Resume the most recent recoverable session automatically.",
132+
},
133+
{
134+
key: "perProjectAccounts",
135+
label: "Enable Per-Project Accounts",
136+
description: "Use repo-specific account storage instead of a global pool.",
137+
},
138+
];
139+
140+
export const BACKEND_NUMBER_OPTIONS: BackendNumberSettingOption[] = [
141+
{
142+
key: "liveAccountSyncDebounceMs",
143+
label: "Live Sync Debounce",
144+
description: "Delay before reacting to file changes.",
145+
min: 50,
146+
max: 60_000,
147+
step: 50,
148+
unit: "ms",
149+
},
150+
{
151+
key: "liveAccountSyncPollMs",
152+
label: "Live Sync Poll Interval",
153+
description: "Polling fallback interval for external file changes.",
154+
min: 500,
155+
max: 120_000,
156+
step: 500,
157+
unit: "ms",
158+
},
159+
{
160+
key: "sessionAffinityTtlMs",
161+
label: "Session Affinity TTL",
162+
description: "How long affinity survives without activity.",
163+
min: 1_000,
164+
max: 86_400_000,
165+
step: 60_000,
166+
unit: "ms",
167+
},
168+
{
169+
key: "sessionAffinityMaxEntries",
170+
label: "Session Affinity Max Entries",
171+
description: "Upper bound for tracked affinity sessions.",
172+
min: 8,
173+
max: 10_000,
174+
step: 8,
175+
unit: "count",
176+
},
177+
{
178+
key: "proactiveRefreshIntervalMs",
179+
label: "Refresh Guard Interval",
180+
description: "How often the guard scans for refresh work.",
181+
min: 5_000,
182+
max: 3_600_000,
183+
step: 5_000,
184+
unit: "ms",
185+
},
186+
{
187+
key: "proactiveRefreshBufferMs",
188+
label: "Refresh Guard Buffer",
189+
description: "How early tokens should refresh before expiry.",
190+
min: 30_000,
191+
max: 7_200_000,
192+
step: 30_000,
193+
unit: "ms",
194+
},
195+
{
196+
key: "parallelProbingMaxConcurrency",
197+
label: "Parallel Probe Concurrency",
198+
description: "Maximum simultaneous account probes.",
199+
min: 1,
200+
max: 32,
201+
step: 1,
202+
unit: "count",
203+
},
204+
{
205+
key: "fastSessionMaxInputItems",
206+
label: "Fast Session Max Inputs",
207+
description: "Maximum prompt items kept in fast-session mode.",
208+
min: 8,
209+
max: 200,
210+
step: 2,
211+
unit: "count",
212+
},
213+
{
214+
key: "networkErrorCooldownMs",
215+
label: "Network Error Cooldown",
216+
description: "Cooldown applied after network failures.",
217+
min: 0,
218+
max: 300_000,
219+
step: 1_000,
220+
unit: "ms",
221+
},
222+
{
223+
key: "serverErrorCooldownMs",
224+
label: "Server Error Cooldown",
225+
description: "Cooldown applied after upstream server failures.",
226+
min: 0,
227+
max: 300_000,
228+
step: 1_000,
229+
unit: "ms",
230+
},
231+
{
232+
key: "fetchTimeoutMs",
233+
label: "Request Timeout",
234+
description: "Max time to wait for a request.",
235+
min: 1_000,
236+
max: (10 * 60 * 60_000) / 60,
237+
step: 5_000,
238+
unit: "ms",
239+
},
240+
{
241+
key: "streamStallTimeoutMs",
242+
label: "Stream Stall Timeout",
243+
description: "Max wait before a stuck stream is retried.",
244+
min: 1_000,
245+
max: (10 * 60 * 60_000) / 60,
246+
step: 5_000,
247+
unit: "ms",
248+
},
249+
{
250+
key: "tokenRefreshSkewMs",
251+
label: "Token Refresh Buffer",
252+
description: "Refresh this long before token expiry.",
253+
min: 0,
254+
max: (10 * 60 * 60_000) / 60,
255+
step: 10_000,
256+
unit: "ms",
257+
},
258+
{
259+
key: "preemptiveQuotaRemainingPercent5h",
260+
label: "5h Remaining Threshold",
261+
description: "Start delaying when 5h remaining reaches this percent.",
262+
min: 0,
263+
max: 100,
264+
step: 1,
265+
unit: "percent",
266+
},
267+
{
268+
key: "preemptiveQuotaRemainingPercent7d",
269+
label: "7d Remaining Threshold",
270+
description: "Start delaying when weekly remaining reaches this percent.",
271+
min: 0,
272+
max: 100,
273+
step: 1,
274+
unit: "percent",
275+
},
276+
{
277+
key: "preemptiveQuotaMaxDeferralMs",
278+
label: "Max Preemptive Deferral",
279+
description: "Maximum time allowed for quota-based delay.",
280+
min: 1_000,
281+
max: 24 * 60 * 60_000,
282+
step: 60_000,
283+
unit: "ms",
284+
},
285+
];
286+
287+
export const BACKEND_CATEGORY_OPTIONS: BackendCategoryOption[] = [
288+
{
289+
key: "session-sync",
290+
label: "Session & Sync",
291+
description: "Sync and session behavior.",
292+
toggleKeys: [
293+
"liveAccountSync",
294+
"sessionAffinity",
295+
"perProjectAccounts",
296+
"sessionRecovery",
297+
"autoResume",
298+
],
299+
numberKeys: [
300+
"liveAccountSyncDebounceMs",
301+
"liveAccountSyncPollMs",
302+
"sessionAffinityTtlMs",
303+
"sessionAffinityMaxEntries",
304+
],
305+
},
306+
{
307+
key: "rotation-quota",
308+
label: "Rotation & Quota",
309+
description: "Quota and retry behavior.",
310+
toggleKeys: ["preemptiveQuotaEnabled", "retryAllAccountsRateLimited"],
311+
numberKeys: [
312+
"preemptiveQuotaRemainingPercent5h",
313+
"preemptiveQuotaRemainingPercent7d",
314+
"preemptiveQuotaMaxDeferralMs",
315+
],
316+
},
317+
{
318+
key: "refresh-recovery",
319+
label: "Refresh & Recovery",
320+
description: "Token refresh and recovery safety.",
321+
toggleKeys: ["storageBackupEnabled"],
322+
numberKeys: ["proactiveRefreshBufferMs", "tokenRefreshSkewMs"],
323+
},
324+
{
325+
key: "performance-timeouts",
326+
label: "Performance & Timeouts",
327+
description: "Speed, probing, and timeout controls.",
328+
toggleKeys: ["fastSession", "parallelProbing"],
329+
numberKeys: [
330+
"fastSessionMaxInputItems",
331+
"parallelProbingMaxConcurrency",
332+
"fetchTimeoutMs",
333+
"streamStallTimeoutMs",
334+
"networkErrorCooldownMs",
335+
"serverErrorCooldownMs",
336+
],
337+
},
338+
];
339+
340+
export const BACKEND_DEFAULTS: PluginConfig = getDefaultPluginConfig();
341+
342+
export const BACKEND_TOGGLE_OPTION_BY_KEY = new Map<
343+
BackendToggleSettingKey,
344+
BackendToggleSettingOption
345+
>(BACKEND_TOGGLE_OPTIONS.map((option) => [option.key, option]));
346+
347+
export const BACKEND_NUMBER_OPTION_BY_KEY = new Map<
348+
BackendNumberSettingKey,
349+
BackendNumberSettingOption
350+
>(BACKEND_NUMBER_OPTIONS.map((option) => [option.key, option]));

0 commit comments

Comments
 (0)