diff --git a/src/lib/components/SettingsModal.svelte b/src/lib/components/SettingsModal.svelte index b0a04b8..cad9d27 100644 --- a/src/lib/components/SettingsModal.svelte +++ b/src/lib/components/SettingsModal.svelte @@ -8,15 +8,15 @@ getOpenAi, chatModels, } from "$lib/stores/stores"; - import { DB_NAME } from "$lib/constants"; import AutosizeTextarea from "./AutosizeTextarea.svelte"; import { getSystem } from "$lib/gui"; import { onMount } from "svelte"; - import { ChatMessage, Thread } from "$lib/db"; + import { ChatMessage, Thread, getLatestDbName } from "$lib/db"; import { mapKeys, toCamelCase } from "$lib/utils"; import CloseButton from "./CloseButton.svelte"; import type OpenAI from "openai"; + let dbName = ""; let schema; let migrationVersion; onMount(async () => { @@ -32,7 +32,10 @@ .filter((x) => x.id.startsWith("gpt")) .sort((a, b) => a.id.localeCompare(b.id)); } + + dbName = getLatestDbName() || ""; }); + let showAdvanced = false; @@ -285,7 +288,7 @@
- {DB_NAME}/{$openAiConfig.siteId} + {dbName}/{$openAiConfig.siteId}
Database identifier used locally for persistent storage.
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index a9e4f9b..e69de29 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -1,26 +0,0 @@
-/**
- * A record of the databases we expect to be accessible to the app. Although
- * clearly not enforced, this list should be treated as append-only. This does
- * not mean the db version can't be moved backwards, just do so by appending.
- *
- * Appending a new db name effectively resets the db, without data loss since
- * you can change it back. This is good for testing as if on a new system.
- */
-export const DB_NAMES = [
- "chat_db-v1",
- "chat_db-v2",
- "chat_db-v3",
- "chat_db-v4",
- "chat_db-v5",
- "chat_db-v8.1",
- "chat_db-v8.2", // Testing out migration fixes
- "chat_db-v8.1", // Moving back to 8.1 now that migrations are fixed. No data changed, just migration code
- "chat_db-v9.1", // Starting fresh in dev
- "chat_db-v9.2", // QA importing
- "chat_db-v10", // Corrupted db
- "chat_db-v10.1", // Testing syncing
- "chat_db-v11", // fts
- "chat_db-v11.11", // fts
-];
-
-export const DB_NAME = DB_NAMES.at(-1);
diff --git a/src/lib/db.ts b/src/lib/db.ts
index 53be2c0..490d377 100644
--- a/src/lib/db.ts
+++ b/src/lib/db.ts
@@ -1,7 +1,6 @@
import initWasm, { SQLite3, DB } from "@vlcn.io/crsqlite-wasm";
import type { TXAsync } from "@vlcn.io/xplat-api";
import wasmUrl from "@vlcn.io/crsqlite-wasm/crsqlite.wasm?url";
-import { DB_NAME } from "../lib/constants";
import {
db,
sqlite,
@@ -20,6 +19,67 @@ import { basename, debounce, groupBy, sha1sum, toCamelCase, toSnakeCase } from "
import { extractFragments } from "./markdown";
import tblrx, { TblRx } from "@vlcn.io/rx-tbl";
+const legacyDbNames = [
+ "chat_db-v1",
+ "chat_db-v2",
+ "chat_db-v3",
+ "chat_db-v4",
+ "chat_db-v5",
+ "chat_db-v8.1",
+ "chat_db-v8.2", // Testing out migration fixes
+ "chat_db-v8.1", // Moving back to 8.1 now that migrations are fixed. No data changed, just migration code
+ "chat_db-v9.1", // Starting fresh in dev
+ "chat_db-v9.2", // QA importing
+ "chat_db-v10", // Corrupted db
+ "chat_db-v10.1", // Testing syncing
+ "chat_db-v11", // fts
+ "chat_db-v11.11", // fts
+];
+
+const lsKey = "prompta--dbNames";
+
+/**
+ * Get a record of the databases we expect to be accessible to the app. Although
+ * clearly not enforced, this list should be treated as append-only. This does
+ * not mean the db version can't be moved backwards, just do so by appending.
+ *
+ * Appending a new db name effectively resets the db, without data loss since
+ * you can change it back. This is good for testing as if on a new system.
+ */
+const getDbNames = () => {
+ if (typeof localStorage === "undefined") {
+ throw new Error("localStorage is not available");
+ }
+
+ let _dbNames = localStorage.getItem(lsKey);
+
+ if (!_dbNames) {
+ _dbNames = JSON.stringify(legacyDbNames);
+ localStorage.setItem(lsKey, _dbNames);
+ }
+
+ let dbNames: string[] = [];
+
+ if (_dbNames) {
+ dbNames = JSON.parse(_dbNames);
+ }
+
+ return dbNames;
+};
+
+export const getLatestDbName = () => {
+ return getDbNames().at(-1);
+};
+
+export const incrementDbName = () => {
+ const v = (getDbNames().length + 1).toString().padStart(3, "0");
+ const next = `chat_db-v${v}`;
+
+ localStorage.setItem(lsKey, JSON.stringify([...getDbNames(), next]));
+
+ return next;
+};
+
// ========================================================================================
// Rudimentary Migration System
// ========================================================================================
@@ -112,17 +172,21 @@ const migrateDb = async (db: DB) => {
}
};
-export const initDb = async () => {
+export const initDb = async (dbName: string) => {
if (_db) {
console.debug("DB already initialized");
return;
}
+ if (!dbName) {
+ throw new Error("No database name provided");
+ }
+
// @note This only works in the browser. Don't use SSR anywhere where you need this
_sqlite = await initWasm(() => wasmUrl);
sqlite.set(_sqlite);
- _db = await _sqlite.open(DB_NAME);
+ _db = await _sqlite.open(dbName);
db.set(_db);
await migrateDb(_db);
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 031b17c..55e122b 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -115,3 +115,9 @@ export const sha1sum = async (s: string) => {
export const isPWAInstalled = () => {
return globalThis.matchMedia("(display-mode: standalone)").matches;
};
+
+export function wrapError(innerError: Error, newMessage: string): Error {
+ const wrappedError = new Error(newMessage + "\n" + innerError.message);
+ wrappedError.stack = `${newMessage}\nCaused by: ${innerError.stack}`;
+ return wrappedError;
+}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index a253364..3c59e00 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -2,7 +2,7 @@
import "../app.postcss";
import { openAiConfig, syncStore, showInitScreen } from "../lib/stores/stores";
import { onMount } from "svelte";
- import { DatabaseMeta, initDb } from "$lib/db";
+ import { DatabaseMeta, getLatestDbName, incrementDbName, initDb } from "$lib/db";
import SettingsModal from "$lib/components/SettingsModal.svelte";
import { getSystem } from "$lib/gui";
import classNames from "classnames";
@@ -10,10 +10,10 @@
import Toaster from "$lib/toast/Toaster.svelte";
import { assets } from "$app/paths";
import FullScreenError from "$lib/components/FullScreenError.svelte";
+ import { wrapError } from "$lib/utils";
const sys = getSystem();
let startupError: Error | null = null;
- startupError = new Error("Test error");
let appReady = false;
const handleHardReset = async () => {
@@ -23,9 +23,14 @@
if (!confirmed) return;
- await sys.alert("TODO: Reset the database");
+ appReady = false;
- // await DatabaseMeta.hardReset();
+ incrementDbName();
+
+ // Reloading the window should cause handleStartup to be called again on app
+ // mount, using the new db name. Using a new db name is equivalent to using
+ // a new db. The old db will not be removed, but the app will have no
+ // existing data.
location.reload();
};
@@ -39,18 +44,14 @@
try {
const start = performance.now();
console.debug("Initializing database");
- await initDb();
+ await initDb(getLatestDbName() || "");
console.debug(`Database initialized in ${performance.now() - start}ms`);
} catch (err: any) {
- await sys.alert(
- `There was an error initializing the database. Please try again. If the problem persists, please report it on GitHub.` +
- err.message
- );
- throw err;
+ throw wrapError(err, `There was an error initializing the database.`);
+ } finally {
+ clearTimeout(_timeout);
}
- clearTimeout(_timeout);
-
if (!$openAiConfig.apiKey) {
$showInitScreen = true;
console.warn(`No API key found. Please enter one in the settings.`);
@@ -171,12 +172,11 @@
})}
>
{#if startupError}
-
+ The app could not be initialized
-
What can you do?
-
+