File size: 4,093 Bytes
8176282 d7761f1 8176282 d7761f1 8176282 4331e77 8176282 4331e77 e67ab0e 8176282 b639829 8f18bce 4331e77 9b4ba04 8176282 cafb235 9645f4e 31b3f19 a9c6dde 31b3f19 9645f4e 8176282 9645f4e 8176282 31b3f19 8176282 31b3f19 7bdd079 8176282 31b3f19 8176282 cafb235 31b3f19 8176282 31b3f19 8176282 31b3f19 8176282 31b3f19 a9c6dde 31b3f19 a9c6dde 31b3f19 9645f4e 8176282 9645f4e 31b3f19 8176282 9645f4e 8176282 |
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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
import { browser } from "$app/environment";
import { invalidate } from "$app/navigation";
import { base } from "$app/paths";
import { UrlDependency } from "$lib/types/UrlDependency";
import { getContext, setContext } from "svelte";
import { type Writable, writable, get } from "svelte/store";
type SettingsStore = {
shareConversationsWithModelAuthors: boolean;
welcomeModalSeen: boolean;
welcomeModalSeenAt: Date | null;
activeModel: string;
customPrompts: Record<string, string>;
multimodalOverrides: Record<string, boolean>;
toolsOverrides: Record<string, boolean>;
recentlySaved: boolean;
disableStream: boolean;
directPaste: boolean;
hidePromptExamples: Record<string, boolean>;
billingOrganization?: string;
};
type SettingsStoreWritable = Writable<SettingsStore> & {
instantSet: (settings: Partial<SettingsStore>) => Promise<void>;
initValue: <K extends keyof SettingsStore>(
key: K,
nestedKey: string,
value: string | boolean
) => Promise<void>;
};
export function useSettingsStore() {
return getContext<SettingsStoreWritable>("settings");
}
export function createSettingsStore(initialValue: Omit<SettingsStore, "recentlySaved">) {
const baseStore = writable({ ...initialValue, recentlySaved: false });
let timeoutId: NodeJS.Timeout;
let showSavedOnNextSync = false;
async function setSettings(settings: Partial<SettingsStore>) {
baseStore.update((s) => ({
...s,
...settings,
}));
if (browser) {
showSavedOnNextSync = true; // User edit, should show "Saved"
clearTimeout(timeoutId);
timeoutId = setTimeout(async () => {
await fetch(`${base}/settings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(get(baseStore)),
});
invalidate(UrlDependency.ConversationList);
if (showSavedOnNextSync) {
// set savedRecently to true for 3s
baseStore.update((s) => ({
...s,
recentlySaved: true,
}));
setTimeout(() => {
baseStore.update((s) => ({
...s,
recentlySaved: false,
}));
}, 3000);
}
showSavedOnNextSync = false;
}, 300);
// debounce server calls by 300ms
}
}
async function initValue<K extends keyof SettingsStore>(
key: K,
nestedKey: string,
value: string | boolean
) {
const currentStore = get(baseStore);
const currentNestedObject = currentStore[key] as Record<string, string | boolean>;
// Only initialize if undefined
if (currentNestedObject?.[nestedKey] !== undefined) {
return;
}
// Update the store
const newNestedObject = {
...(currentNestedObject || {}),
[nestedKey]: value,
};
baseStore.update((s) => ({
...s,
[key]: newNestedObject,
}));
// Save to server (debounced) - note: we don't set showSavedOnNextSync
if (browser) {
clearTimeout(timeoutId);
timeoutId = setTimeout(async () => {
await fetch(`${base}/settings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(get(baseStore)),
});
invalidate(UrlDependency.ConversationList);
if (showSavedOnNextSync) {
baseStore.update((s) => ({
...s,
recentlySaved: true,
}));
setTimeout(() => {
baseStore.update((s) => ({
...s,
recentlySaved: false,
}));
}, 3000);
}
showSavedOnNextSync = false;
}, 300);
}
}
async function instantSet(settings: Partial<SettingsStore>) {
baseStore.update((s) => ({
...s,
...settings,
}));
if (browser) {
await fetch(`${base}/settings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...get(baseStore),
...settings,
}),
});
invalidate(UrlDependency.ConversationList);
}
}
const newStore = {
subscribe: baseStore.subscribe,
set: setSettings,
instantSet,
initValue,
update: (fn: (s: SettingsStore) => SettingsStore) => {
setSettings(fn(get(baseStore)));
},
} satisfies SettingsStoreWritable;
setContext("settings", newStore);
return newStore;
}
|