From b179031f2820d42fc861ec23120a89d1083a759d Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:34:41 -0600 Subject: [PATCH 1/3] wip --- AGENTS.md | 4 +- package.json | 2 + pnpm-lock.yaml | 45 +++++++++++ src/app.d.ts | 12 +++ src/lib/components/Sidebar.svelte | 102 ++++++++++++++++--------- src/lib/components/sidebar-context.ts | 10 +++ src/lib/utils/time.ts | 28 +++++++ src/routes/notes/+layout.svelte | 82 ++++++++++++++++++++ src/routes/{ => notes}/+page.server.ts | 0 src/routes/{ => notes}/+page.svelte | 30 ++++++-- src/routes/notes/[id]/+layout.svelte | 16 ---- 11 files changed, 269 insertions(+), 62 deletions(-) create mode 100644 src/lib/components/sidebar-context.ts create mode 100644 src/lib/utils/time.ts create mode 100644 src/routes/notes/+layout.svelte rename src/routes/{ => notes}/+page.server.ts (100%) rename src/routes/{ => notes}/+page.svelte (66%) delete mode 100644 src/routes/notes/[id]/+layout.svelte diff --git a/AGENTS.md b/AGENTS.md index eb6cda6..a431c80 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -154,7 +154,7 @@ export const [getLinkContext, setLinkContext] = createContext(); Wrap in `$derived` for reactivity. ```svelte - + + + +
+ {#if data.user} + + {/if} + + {@render children()} +
diff --git a/src/routes/+page.server.ts b/src/routes/notes/+page.server.ts similarity index 100% rename from src/routes/+page.server.ts rename to src/routes/notes/+page.server.ts diff --git a/src/routes/+page.svelte b/src/routes/notes/+page.svelte similarity index 66% rename from src/routes/+page.svelte rename to src/routes/notes/+page.svelte index 7d2c9b0..405ad63 100644 --- a/src/routes/+page.svelte +++ b/src/routes/notes/+page.svelte @@ -1,10 +1,15 @@ -
+

Dashboard

@@ -31,9 +36,11 @@ {data.randomNote.title}

- Last updated: {new Date( - data.randomNote.updatedAt, - ).toLocaleDateString()} + Last updated: {formatRelativeTime( + Temporal.Instant.fromEpochMilliseconds( + data.randomNote.updatedAt.getTime(), + ), + )}

@@ -57,9 +64,16 @@

- Create New Note + {#if sidebar.isCollapsed} + + {:else} +

+ Use the sidebar to create your first note +

+ {/if}
diff --git a/src/routes/notes/[id]/+layout.svelte b/src/routes/notes/[id]/+layout.svelte deleted file mode 100644 index c30ffe0..0000000 --- a/src/routes/notes/[id]/+layout.svelte +++ /dev/null @@ -1,16 +0,0 @@ - - -
- {#if data.user} - - {/if} - - {@render children()} -
From bbbdd110821e93d1cda46edd5005ed99717fd14a Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:34:45 -0600 Subject: [PATCH 2/3] wip --- src/hooks.server.ts | 4 +++ src/lib/components/Sidebar.svelte | 23 ++++++++++------ src/lib/loro.ts | 3 ++- src/lib/remote/accounts.remote.ts | 10 ++++--- src/lib/remote/notes.remote.ts | 10 ++----- src/lib/remote/notes.schemas.ts | 1 + src/lib/server/auth.ts | 3 ++- src/lib/server/db/columns.ts | 42 ++++++++++++++++++++++++++++++ src/lib/server/db/relations.ts | 7 ----- src/lib/server/db/schema.ts | 37 +++++--------------------- src/routes/+layout.server.ts | 4 +-- src/routes/+page.server.ts | 8 ++++++ src/routes/notes/[id]/+page.svelte | 5 ++++ 13 files changed, 96 insertions(+), 61 deletions(-) create mode 100644 src/lib/server/db/columns.ts create mode 100644 src/routes/+page.server.ts diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 7ce13ee..11f8a8d 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,6 +1,10 @@ import type { Handle } from "@sveltejs/kit"; import * as auth from "$lib/server/auth"; +process.on("unhandledRejection", (reason, promise) => { + console.log("err", reason, "\nprom:", promise); +}); + const handleAuth: Handle = async ({ event, resolve }) => { const sessionToken = event.cookies.get(auth.sessionCookieName); diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index a09fb05..8c9b379 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -28,6 +28,8 @@ import { onMount } from "svelte"; import { SvelteSet } from "svelte/reactivity"; import ProfilePicture from "./ProfilePicture.svelte"; + import { LoroDoc } from "loro-crdt"; + import { getEncryptedSnapshot } from "$lib/loro.ts"; import TreeItem from "./TreeItem.svelte"; interface ContextState { @@ -181,11 +183,17 @@ // Encrypt note key with user's public key const encryptedKey = await encryptKeyForUser(noteKey, publicKey); + const encryptedSnapshot = await getEncryptedSnapshot( + new LoroDoc(), + noteKey, + ); + const newNote = await createNote({ title, encryptedKey, parentId, isFolder, + encryptedSnapshot, }).updates( // TODO: add optimistic update. getNotes(), @@ -325,19 +333,18 @@ {#if contextMenu.isFolder} diff --git a/src/lib/loro.ts b/src/lib/loro.ts index 38521d3..f43ffcd 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -4,6 +4,7 @@ import { sync } from "$lib/remote/sync.remote.ts"; import { Chunk, Effect, Fiber, Function, PubSub, Schema, Stream } from "effect"; import diff from "fast-diff"; import { LoroDoc, type LoroText, type Frontiers } from "loro-crdt"; +import { unawaited } from "./unawaited.ts"; export type Doc = LoroDoc<{ content: LoroText; @@ -137,7 +138,7 @@ export class LoroNoteManager { for (const update of data.updates) { const updateBytes = Uint8Array.fromBase64(update); - void emit(Effect.succeed(Chunk.make(updateBytes))); + unawaited(emit(Effect.succeed(Chunk.make(updateBytes)))); } } catch (error) { console.error("Failed to process sync message:", error); diff --git a/src/lib/remote/accounts.remote.ts b/src/lib/remote/accounts.remote.ts index cdbe154..0eb376a 100644 --- a/src/lib/remote/accounts.remote.ts +++ b/src/lib/remote/accounts.remote.ts @@ -7,6 +7,8 @@ import { fail, invalid, redirect } from "@sveltejs/kit"; import { eq } from "drizzle-orm"; import { Redacted, Schema } from "effect"; import { loginSchema, signupSchema } from "./accounts.schema.ts"; +import { resolve } from "$app/paths"; +import { Temporal } from "temporal-polyfill"; export const login = form( loginSchema, @@ -41,7 +43,7 @@ export const login = form( const session = await auth.createSession(sessionToken, existingUser.id); auth.setSessionTokenCookie(cookies, sessionToken, session.expiresAt); - return redirect(302, "/"); + return redirect(302, resolve("/notes/")); }, ); @@ -66,7 +68,7 @@ export const signup = form( passwordHash, publicKey, privateKeyEncrypted, - createdAt: new Date(), + createdAt: Temporal.Now.instant(), } satisfies table.User); const sessionToken = auth.generateSessionToken(); @@ -75,7 +77,7 @@ export const signup = form( } catch { return fail(500, { message: "An error has occurred" }); } - redirect(302, "/"); + redirect(302, resolve("/notes")); }, ); @@ -87,6 +89,6 @@ export const logout = form( await auth.invalidateSession(authData.session.userId); auth.deleteSessionTokenCookie(cookies); - redirect(302, "/login"); + redirect(302, resolve("/login")); }, ); diff --git a/src/lib/remote/notes.remote.ts b/src/lib/remote/notes.remote.ts index dd20848..14f6b73 100644 --- a/src/lib/remote/notes.remote.ts +++ b/src/lib/remote/notes.remote.ts @@ -11,8 +11,6 @@ import { reorderNotesSchema, updateNoteSchema, } from "./notes.schemas.ts"; -import { LoroDoc } from "loro-crdt"; -import { getEncryptedSnapshot } from "$lib/loro.ts"; export const getNotes = query(async (): Promise => { const { user } = requireLogin(); @@ -43,23 +41,19 @@ export const createNote = command( encryptedKey, parentId, isFolder, + encryptedSnapshot, }): Promise> => { const { user } = requireLogin(); try { const id = crypto.randomUUID(); - const loroSnapshot = await getEncryptedSnapshot( - new LoroDoc(), - encryptedKey, - ); - await db.insert(notes).values({ id, title, ownerId: user.id, encryptedKey, - loroSnapshot, + loroSnapshot: encryptedSnapshot, parentId, isFolder, createdAt: new Date(), diff --git a/src/lib/remote/notes.schemas.ts b/src/lib/remote/notes.schemas.ts index 2ee1bee..f41d0e7 100644 --- a/src/lib/remote/notes.schemas.ts +++ b/src/lib/remote/notes.schemas.ts @@ -6,6 +6,7 @@ export const CreateNoteSchema = Schema.Struct({ parentId: Schema.String.pipe(Schema.NullOr), isFolder: Schema.Boolean, encryptedKey: Uint8ArrayFromSelfSchema, + encryptedSnapshot: Uint8ArrayFromSelfSchema, }); export const createNoteSchema = CreateNoteSchema.pipe(Schema.standardSchemaV1); diff --git a/src/lib/server/auth.ts b/src/lib/server/auth.ts index fbbafbb..7a37e52 100644 --- a/src/lib/server/auth.ts +++ b/src/lib/server/auth.ts @@ -6,6 +6,7 @@ import { db } from "$lib/server/db"; import * as table from "$lib/server/db/schema"; import type { User } from "$lib/schema.ts"; import { getRequestEvent } from "$app/server"; +import { resolve } from "$app/paths"; const DAY_IN_MS = 1000 * 60 * 60 * 24; @@ -120,7 +121,7 @@ export function guardLogin(): SomeAuthData { } = getRequestEvent(); if (!user || !session) { - redirect(302, "/login"); + redirect(302, resolve("/login")); } return { user, session }; diff --git a/src/lib/server/db/columns.ts b/src/lib/server/db/columns.ts new file mode 100644 index 0000000..b7353dd --- /dev/null +++ b/src/lib/server/db/columns.ts @@ -0,0 +1,42 @@ +import { customType } from "drizzle-orm/sqlite-core"; +import { Temporal } from "temporal-polyfill"; +import { SQL } from "drizzle-orm"; + +// https://github.com/drizzle-team/drizzle-orm/issues/4419#issuecomment-2885561863 +export const instant = customType<{ + data: Temporal.Instant; + driverData: number; +}>({ + dataType: () => { + return "timestamp"; + }, + fromDriver: (value) => { + return Temporal.Instant.fromEpochMilliseconds(value); + }, + toDriver: (value: Temporal.Instant | SQL) => { + if (value instanceof SQL) { + return value; + } + + return value.epochMilliseconds; + }, +}); + +export const uint8array = customType<{ + data: Uint8Array; + driverData: Buffer; +}>({ + dataType: () => { + return "blob"; + }, + fromDriver: (value) => { + return new Uint8Array(value); + }, + toDriver: (value: Uint8Array | SQL) => { + if (value instanceof SQL) { + return value; + } + + return Buffer.from(value); + }, +}); diff --git a/src/lib/server/db/relations.ts b/src/lib/server/db/relations.ts index 0d1b8c4..2ae3272 100644 --- a/src/lib/server/db/relations.ts +++ b/src/lib/server/db/relations.ts @@ -17,7 +17,6 @@ export const relations = defineRelations(schema, (r) => ({ from: r.notes.ownerId, to: r.users.id, }), - shares: r.many.noteShares(), parent: r.one.notes({ from: r.notes.parentId, to: r.notes.id, @@ -29,10 +28,4 @@ export const relations = defineRelations(schema, (r) => ({ to: r.notes.parentId, }), }, - noteShares: { - note: r.one.notes({ - from: r.noteShares.noteId, - to: r.notes.id, - }), - }, })); diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts index a1a8d3a..a5a9a23 100644 --- a/src/lib/server/db/schema.ts +++ b/src/lib/server/db/schema.ts @@ -1,18 +1,13 @@ -import { sqliteTable, text, integer, blob } from "drizzle-orm/sqlite-core"; +import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; +import { instant, uint8array } from "./columns.ts"; export const users = sqliteTable("users", { id: text("id").primaryKey(), username: text("username").notNull().unique(), passwordHash: text("password_hash").notNull(), - publicKey: blob("public_key", { mode: "buffer" }) - .$type>() - .notNull(), - privateKeyEncrypted: blob("private_key_encrypted", { mode: "buffer" }) - .$type>() - .notNull(), - createdAt: integer("created_at", { mode: "timestamp" }) - .notNull() - .$defaultFn(() => new Date()), + publicKey: uint8array("public_key").notNull(), + privateKeyEncrypted: uint8array("private_key_encrypted").notNull(), + createdAt: instant("created_at").notNull(), }); export const sessions = sqliteTable("sessions", { @@ -29,12 +24,8 @@ export const notes = sqliteTable("notes", { ownerId: text("owner_id") .notNull() .references(() => users.id), - encryptedKey: blob("encrypted_key", { mode: "buffer" }) - .$type>() - .notNull(), - loroSnapshot: blob("loro_snapshot", { mode: "buffer" }) - .$type>() - .notNull(), + encryptedKey: uint8array("encrypted_key").notNull(), + loroSnapshot: uint8array("loro_snapshot").notNull(), parentId: text("parent_id"), isFolder: integer("is_folder", { mode: "boolean" }).notNull().default(false), order: integer("order").notNull().default(0), @@ -46,20 +37,6 @@ export const notes = sqliteTable("notes", { .$defaultFn(() => new Date()), }); -export const noteShares = sqliteTable("note_shares", { - id: text("id").primaryKey(), - noteId: text("note_id") - .notNull() - .references(() => notes.id), - sharedWithUser: text("shared_with_user").notNull(), - encryptedKey: text("encrypted_key").notNull(), - permissions: text("permissions").notNull().default("read"), - createdAt: integer("created_at", { mode: "timestamp" }) - .notNull() - .$defaultFn(() => new Date()), -}); - export type User = typeof users.$inferSelect; export type Session = typeof sessions.$inferSelect; export type Note = typeof notes.$inferSelect; -export type NoteShare = typeof noteShares.$inferSelect; diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index f31faa5..ea4a208 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -24,8 +24,8 @@ export const load = async ({ locals }): Promise => { ? { id: user.id, username: user.username, - publicKey: user.publicKey, - privateKeyEncrypted: user.privateKeyEncrypted, + publicKey: new Uint8Array(user.publicKey), + privateKeyEncrypted: new Uint8Array(user.privateKeyEncrypted), } : undefined, }; diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts new file mode 100644 index 0000000..2da0765 --- /dev/null +++ b/src/routes/+page.server.ts @@ -0,0 +1,8 @@ +import { resolve } from "$app/paths"; +import { redirect } from "@sveltejs/kit"; + +export const load = (event): void => { + if (event.locals.user) { + redirect(302, resolve("/notes/")); + } +}; diff --git a/src/routes/notes/[id]/+page.svelte b/src/routes/notes/[id]/+page.svelte index d8d3897..53b0ef1 100644 --- a/src/routes/notes/[id]/+page.svelte +++ b/src/routes/notes/[id]/+page.svelte @@ -38,6 +38,11 @@ key = await decryptKey(note.encryptedKey, userPrivateKey); } catch (e) { console.error("Failed to decrypt key:", e); + console.debug("Debug info:", { + encryptedKeyLen: note.encryptedKey.byteLength, + userPrivateKeyLen: userPrivateKey?.byteLength, + noteId: note.id, + }); } } From 65ab96aaf4feb192fcbdb017ec927f48dfe2eda9 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:29:52 -0600 Subject: [PATCH 3/3] fixes --- src/hooks.server.ts | 6 +---- src/lib/components/Sidebar.svelte | 25 ++++++++--------- src/lib/loro.ts | 2 +- src/lib/remote/notes.remote.ts | 39 ++++++++++----------------- src/lib/server/db/columns.ts | 4 ++- src/routes/(auth)/signup/+page.svelte | 2 +- src/routes/+layout.server.ts | 27 +++++++++---------- src/routes/notes/+layout.svelte | 7 +---- src/routes/notes/+page.svelte | 4 +-- src/routes/notes/[id]/+page.svelte | 2 +- 10 files changed, 49 insertions(+), 69 deletions(-) diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 11f8a8d..7e3485d 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,10 +1,6 @@ import type { Handle } from "@sveltejs/kit"; import * as auth from "$lib/server/auth"; -process.on("unhandledRejection", (reason, promise) => { - console.log("err", reason, "\nprom:", promise); -}); - const handleAuth: Handle = async ({ event, resolve }) => { const sessionToken = event.cookies.get(auth.sessionCookieName); @@ -35,7 +31,7 @@ const handleAuth: Handle = async ({ event, resolve }) => { auth.deleteSessionTokenCookie(event.cookies); // Redirect to login if session invalid - if (event.url.pathname === "/") { + if (!event.route.id?.startsWith("/(auth)")) { return new Response("Redirect", { status: 303, headers: { Location: "/login" }, diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index 8c9b379..004c8e0 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -2,7 +2,7 @@ import { goto } from "$app/navigation"; import { resolve } from "$app/paths"; import { page } from "$app/state"; - import { encryptKeyForUser, generateNoteKey } from "$lib/crypto"; + import { encryptKeyForUser, generateNoteKey } from "$lib/crypto.ts"; import { logout } from "$lib/remote/accounts.remote.ts"; import { createNote, @@ -11,7 +11,7 @@ reorderNotes, updateNote, } from "$lib/remote/notes.remote.ts"; - import type { NoteOrFolder, User } from "$lib/schema.ts"; + import type { User } from "$lib/schema.ts"; import { unawaited } from "$lib/unawaited.ts"; import { buildNotesTree } from "$lib/utils/tree.ts"; import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; @@ -41,23 +41,23 @@ interface Props { user: User | undefined; - notesList: NoteOrFolder[]; isCollapsed: boolean; toggleSidebar: () => void; } - let { user, notesList, isCollapsed, toggleSidebar }: Props = $props(); + let { user, isCollapsed, toggleSidebar }: Props = $props(); + let expandedFolders = new SvelteSet(); let renamingId = $state(null); let renameTitle = $state(""); let contextMenu = $state(); let renameModal: HTMLDialogElement; - let notesTree = $derived(buildNotesTree(notesList)); - let rootContainer: HTMLElement; let isRootDropTarget = $state(false); + let notesListQuery = $derived(getNotes()); + // Set up root drop target onMount(() => { const cleanup = dropTargetForElements({ @@ -181,12 +181,10 @@ const noteKey = await generateNoteKey(); // Encrypt note key with user's public key - const encryptedKey = await encryptKeyForUser(noteKey, publicKey); - - const encryptedSnapshot = await getEncryptedSnapshot( - new LoroDoc(), - noteKey, - ); + const [encryptedKey, encryptedSnapshot] = await Promise.all([ + encryptKeyForUser(noteKey, publicKey), + getEncryptedSnapshot(new LoroDoc(), noteKey), + ]); const newNote = await createNote({ title, @@ -211,6 +209,9 @@ renameModal.close(); } }); + + let notesList = $derived(await notesListQuery); + let notesTree = $derived(buildNotesTree(notesList)); diff --git a/src/lib/loro.ts b/src/lib/loro.ts index f43ffcd..b50a8ce 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -1,4 +1,4 @@ -import { decryptData, encryptData } from "$lib/crypto"; +import { decryptData, encryptData } from "$lib/crypto.ts"; import { syncSchemaJson } from "$lib/remote/notes.schemas.ts"; import { sync } from "$lib/remote/sync.remote.ts"; import { Chunk, Effect, Fiber, Function, PubSub, Schema, Stream } from "effect"; diff --git a/src/lib/remote/notes.remote.ts b/src/lib/remote/notes.remote.ts index 14f6b73..e93eaaf 100644 --- a/src/lib/remote/notes.remote.ts +++ b/src/lib/remote/notes.remote.ts @@ -15,11 +15,10 @@ import { export const getNotes = query(async (): Promise => { const { user } = requireLogin(); - const userNotes = await db.query.notes.findMany({ - where: { - ownerId: user.id, - }, - }); + const userNotes = await db + .select() + .from(notes) + .where(eq(notes.ownerId, user.id)); return userNotes.map( (n) => @@ -60,11 +59,7 @@ export const createNote = command( updatedAt: new Date(), } satisfies typeof notes.$inferInsert); - const note = await db.query.notes.findFirst({ - where: { - id: id, - }, - }); + const [note] = await db.select().from(notes).where(eq(notes.id, id)); if (!note) throw new Error("Failed to find newly created note!"); @@ -84,11 +79,7 @@ export const deleteNote = command( try { // Verify ownership - const note = await db.query.notes.findFirst({ - where: { - id: noteId, - }, - }); + const [note] = await db.select().from(notes).where(eq(notes.id, noteId)); if (!note || note.ownerId !== user.id) error(404, "Not found"); @@ -112,11 +103,10 @@ export const updateNote = command( try { // Verify ownership - const existingNote = await db.query.notes.findFirst({ - where: { - id: noteId, - }, - }); + const [existingNote] = await db + .select() + .from(notes) + .where(eq(notes.id, noteId)); if (!existingNote || existingNote.ownerId !== user.id) { error(404, "Not found"); @@ -133,11 +123,10 @@ export const updateNote = command( }) .where(eq(notes.id, noteId)); - const updated = await db.query.notes.findFirst({ - where: { - id: noteId, - }, - }); + const [updated] = await db + .select() + .from(notes) + .where(eq(notes.id, noteId)); if (!updated) throw new Error("Failed to find newly created note!"); diff --git a/src/lib/server/db/columns.ts b/src/lib/server/db/columns.ts index b7353dd..d58712a 100644 --- a/src/lib/server/db/columns.ts +++ b/src/lib/server/db/columns.ts @@ -30,7 +30,9 @@ export const uint8array = customType<{ return "blob"; }, fromDriver: (value) => { - return new Uint8Array(value); + // Buffer.buffer can be a shared ArrayBuffer larger than the actual data. + // Copy to a new Uint8Array with its own ArrayBuffer to avoid SharedArrayBuffer issues. + return Uint8Array.from(value); }, toDriver: (value: Uint8Array | SQL) => { if (value instanceof SQL) { diff --git a/src/routes/(auth)/signup/+page.svelte b/src/routes/(auth)/signup/+page.svelte index 6e28e32..9d17de6 100644 --- a/src/routes/(auth)/signup/+page.svelte +++ b/src/routes/(auth)/signup/+page.svelte @@ -79,7 +79,7 @@ submitter.form!.requestSubmit(submitter); }} > - {signup.pending !== 0 ? "Logging in..." : "Log In"} + {signup.pending !== 0 ? "Signing up..." : "Sign up"} diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index ea4a208..9751ec1 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -1,5 +1,7 @@ import type { User } from "$lib/schema.ts"; import { db } from "$lib/server/db"; +import * as table from "$lib/server/db/schema.ts"; +import { eq } from "drizzle-orm"; export interface Data { user: User | undefined; @@ -13,20 +15,15 @@ export const load = async ({ locals }): Promise => { } // Get user with private key from database - const user = await db.query.users.findFirst({ - where: { - id: localUser.id, - }, - }); + const [user] = await db + .select({ + id: table.users.id, + username: table.users.username, + publicKey: table.users.publicKey, + privateKeyEncrypted: table.users.privateKeyEncrypted, + }) + .from(table.users) + .where(eq(table.users.id, localUser.id)); - return { - user: user - ? { - id: user.id, - username: user.username, - publicKey: new Uint8Array(user.publicKey), - privateKeyEncrypted: new Uint8Array(user.privateKeyEncrypted), - } - : undefined, - }; + return { user }; }; diff --git a/src/routes/notes/+layout.svelte b/src/routes/notes/+layout.svelte index 7a14ec4..d8c3df2 100644 --- a/src/routes/notes/+layout.svelte +++ b/src/routes/notes/+layout.svelte @@ -1,13 +1,10 @@
{#if data.user} - + {/if} {@render children()} diff --git a/src/routes/notes/+page.svelte b/src/routes/notes/+page.svelte index 405ad63..7aa4421 100644 --- a/src/routes/notes/+page.svelte +++ b/src/routes/notes/+page.svelte @@ -9,11 +9,11 @@ const sidebar = getSidebarContext(); -
+

Dashboard

-
+
diff --git a/src/routes/notes/[id]/+page.svelte b/src/routes/notes/[id]/+page.svelte index 53b0ef1..effe922 100644 --- a/src/routes/notes/[id]/+page.svelte +++ b/src/routes/notes/[id]/+page.svelte @@ -5,7 +5,7 @@ import { LoroNoteManager } from "$lib/loro.ts"; import { getNotes, updateNote } from "$lib/remote/notes.remote.ts"; import { unawaited } from "$lib/unawaited.ts"; - import { decryptKey } from "$lib/crypto"; + import { decryptKey } from "$lib/crypto.ts"; import { FilePlus, Folder } from "@lucide/svelte"; const { data } = $props();