From 558457d711654727d36f6d638415075d47f3c618 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 11:32:00 -0600 Subject: [PATCH 01/14] Add sidebar to dashboard and fix broken /notes route --- src/routes/+layout.svelte | 18 ++++++++++++++++-- src/routes/+page.svelte | 8 ++++---- src/routes/notes/[id]/+layout.svelte | 15 ++------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 70dac07..e8d9710 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -3,8 +3,13 @@ import { onNavigate } from "$app/navigation"; import favicon from "$lib/assets/favicon.svg"; + import Sidebar from "$lib/components/Sidebar.svelte"; + import { getNotes } from "$lib/remote/notes.remote.ts"; + + let { children, data } = $props(); + + const notesList = $derived(data.user ? await getNotes() : []); - let { children } = $props(); onNavigate((navigation) => { const { promise, resolve } = Promise.withResolvers(); @@ -21,4 +26,13 @@ -{@render children()} +{#if data.user} +
+ +
+ {@render children()} +
+
+{:else} + {@render children()} +{/if} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 7d2c9b0..7fb90ac 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -4,7 +4,7 @@ let { data } = $props(); -
+

Dashboard

@@ -57,9 +57,9 @@

- Create New Note +

+ Use the sidebar to create your first note +

diff --git a/src/routes/notes/[id]/+layout.svelte b/src/routes/notes/[id]/+layout.svelte index c30ffe0..4b7cb06 100644 --- a/src/routes/notes/[id]/+layout.svelte +++ b/src/routes/notes/[id]/+layout.svelte @@ -1,16 +1,5 @@ -
- {#if data.user} - - {/if} - - {@render children()} -
+{@render children()} From bf14a89f8848d9b0e97383fd44e71a930df2d616 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 11:38:41 -0600 Subject: [PATCH 02/14] Fix signup/login redirect serialization error --- src/lib/remote/accounts.remote.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/remote/accounts.remote.ts b/src/lib/remote/accounts.remote.ts index 11ef790..b4e75fe 100644 --- a/src/lib/remote/accounts.remote.ts +++ b/src/lib/remote/accounts.remote.ts @@ -41,7 +41,7 @@ export const login = form( const session = await auth.createSession(sessionToken, existingUser.id); auth.setSessionTokenCookie(cookies, sessionToken, session.expiresAt); - return redirect(302, "/"); + throw redirect(302, "/"); }, ); @@ -75,7 +75,7 @@ export const signup = form( } catch { return fail(500, { message: "An error has occurred" }); } - redirect(302, "/"); + throw redirect(302, "/"); }, ); From 0b0b7286f89835faaa91a18d2435a8ae63d0fb6a Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 11:53:50 -0600 Subject: [PATCH 03/14] Add sleek history panel for Loro version tracking --- src/lib/components/HistoryPanel.svelte | 176 ++++++++++++++++++++ src/lib/components/codemirror/Editor.svelte | 18 +- src/lib/loro.ts | 21 +++ 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/lib/components/HistoryPanel.svelte diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte new file mode 100644 index 0000000..b8567ab --- /dev/null +++ b/src/lib/components/HistoryPanel.svelte @@ -0,0 +1,176 @@ + + +{#if isOpen} +
+ +
+
+ +

Version History

+
+ +
+ + +
+ {#if history.length === 0} +
+
+ +

No history available

+
+
+ {:else} +
+ {#each history as entry, i (entry.version)} + + {/each} +
+ {/if} +
+ + + {#if selectedVersion !== null && selectedVersion !== history[0]?.version} +
+ +
+ {/if} +
+ + + +{/if} diff --git a/src/lib/components/codemirror/Editor.svelte b/src/lib/components/codemirror/Editor.svelte index 056e71c..22a5d71 100644 --- a/src/lib/components/codemirror/Editor.svelte +++ b/src/lib/components/codemirror/Editor.svelte @@ -13,9 +13,11 @@ List, ListOrdered, Strikethrough, + Clock, } from "@lucide/svelte"; import { LoroExtensions } from "loro-codemirror"; import Codemirror from "./Codemirror.svelte"; + import HistoryPanel from "$lib/components/HistoryPanel.svelte"; import { coreExtensions, boldCommand, @@ -47,6 +49,7 @@ // svelte-ignore non_reactive_update let editorView: EditorView; + let isHistoryOpen = $state(false); /** Custom theme */ const editorTheme = EditorView.theme({ @@ -193,11 +196,24 @@ icon: ListOrdered, }, ], + [ + { + onclick: () => (isHistoryOpen = !isHistoryOpen), + title: "Version History", + icon: Clock, + }, + ], ]; -
+
+ + (isHistoryOpen = false)} + />
diff --git a/src/lib/loro.ts b/src/lib/loro.ts index 35f44d5..7c6a13a 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -139,4 +139,25 @@ export class LoroNoteManager { const encrypted = await encryptData(snapshot, this.#noteKey); return encrypted.toBase64(); } + + /** + * Get the current version/frontiers of the document + */ + getVersion() { + return this.doc.version(); + } + + /** + * Get frontiers (latest version points) of the document + */ + getFrontiers() { + return this.doc.frontiers(); + } + + /** + * Get the text content + */ + getText(): string { + return this.#text.toString(); + } } From 331c6e153dd53adaa3e5f62266e89f2be875a6c3 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 11:56:10 -0600 Subject: [PATCH 04/14] Make toolbar compact and responsive for smaller screens --- src/lib/components/codemirror/Toolbar.svelte | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib/components/codemirror/Toolbar.svelte b/src/lib/components/codemirror/Toolbar.svelte index 918ac3f..80b5b07 100644 --- a/src/lib/components/codemirror/Toolbar.svelte +++ b/src/lib/components/codemirror/Toolbar.svelte @@ -16,16 +16,23 @@ const { tools }: Props = $props(); -
+
{#each tools as toolset, index (index)} -
+
{#each toolset as tool (tool.title)} {@const Icon = tool.icon} - {/each}
-
+
{/each}
From 3b651afcd68462deb077ffe6f662be4d8b6176ab Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 11:58:43 -0600 Subject: [PATCH 05/14] Add live-synced per-user history tracking with Loro CRDTs --- src/lib/components/HistoryPanel.svelte | 46 ++++++++++++++------------ src/lib/loro.ts | 37 +++++++++++++++++++++ 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index b8567ab..1152f10 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -14,38 +14,40 @@ interface HistoryEntry { version: number; timestamp: Date; - author?: string; preview: string; } let history = $state([]); let selectedVersion = $state(null); + let unsubscribe: (() => void) | null = null; - // Get history from Loro document + // Load history from Loro document function loadHistory() { - if (!manager) return; + if (!manager) { + history = []; + return; + } - const frontiers = manager.doc.frontiers(); - const versions: HistoryEntry[] = []; - - // Get all versions by traversing the version graph - // For now, we'll create a simple version list - // In a real implementation, you'd traverse the Loro version graph - const currentVersion = manager.doc.version(); - - // Create a simple history based on the current state - // This is a simplified version - Loro's actual history is more complex - versions.push({ - version: 0, - timestamp: new Date(), - preview: manager.doc.getText("content").toString().slice(0, 100), - }); - - history = versions; + history = manager.getHistory(); } - onMount(() => { - loadHistory(); + // Subscribe to live updates + $effect(() => { + if (manager && isOpen) { + loadHistory(); + + // Subscribe to document changes for live updates + unsubscribe = manager.subscribeToHistory(() => { + loadHistory(); + }); + } + + return () => { + if (unsubscribe) { + unsubscribe(); + unsubscribe = null; + } + }; }); function restoreVersion(version: number) { diff --git a/src/lib/loro.ts b/src/lib/loro.ts index 7c6a13a..0713233 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -160,4 +160,41 @@ export class LoroNoteManager { getText(): string { return this.#text.toString(); } + + /** + * Get version history with user attribution + * Returns an array of version snapshots + */ + getHistory(): Array<{ + version: number; + timestamp: Date; + preview: string; + }> { + const history: Array<{ + version: number; + timestamp: Date; + preview: string; + }> = []; + + // Get current version + const currentVersion = this.doc.version(); + const currentText = this.#text.toString(); + + // For now, just return the current version + // In a full implementation, you'd traverse the oplog + history.push({ + version: currentVersion.get(this.doc.peerId) || 0, + timestamp: new Date(), + preview: currentText.slice(0, 100), + }); + + return history; + } + + /** + * Subscribe to history changes (live updates) + */ + subscribeToHistory(callback: () => void): () => void { + return this.doc.subscribe(callback); + } } From f2e76b9c0a601c00a90b56b931823c55d7f62c35 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 12:04:26 -0600 Subject: [PATCH 06/14] Add debug logging for real-time sync troubleshooting --- src/lib/loro.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/loro.ts b/src/lib/loro.ts index 0713233..d9c2d9e 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -39,8 +39,10 @@ export class LoroNoteManager { // Subscribe to changes this.doc.subscribeLocalUpdates((update) => { console.debug( - "Loro document changed. Preview:", + "[Loro] Local update detected. Preview:", this.#text.toString().slice(0, 20), + "Update size:", + update.length, ); // Persist changes @@ -48,6 +50,7 @@ export class LoroNoteManager { // Send local changes immediately if (this.#isSyncing) { + console.debug("[Loro] Sending local update to server"); unawaited(this.#sendUpdate(update)); } }); @@ -99,10 +102,16 @@ export class LoroNoteManager { this.#eventSource = new EventSource(`/api/sync/${this.#noteId}`); this.#eventSource.onmessage = (event: MessageEvent): void => { + console.debug("[Loro] Received SSE message:", event.data.slice(0, 100)); try { const data = Schema.decodeSync(syncSchemaJson)(event.data); const updateBytes = Uint8Array.fromBase64(data.update); + console.debug( + "[Loro] Applying remote update, size:", + updateBytes.length, + ); this.doc.import(updateBytes); + console.debug("[Loro] Remote update applied successfully"); } catch (error) { console.error("Failed to process sync message:", error); } From cc2229516787ff063434766bfef6e6bae138a21e Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 12:06:10 -0600 Subject: [PATCH 07/14] Fix SSE connection drops with keep-alive mechanism --- src/routes/api/sync/[noteId]/+server.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/routes/api/sync/[noteId]/+server.ts b/src/routes/api/sync/[noteId]/+server.ts index 152ca3f..0581705 100644 --- a/src/routes/api/sync/[noteId]/+server.ts +++ b/src/routes/api/sync/[noteId]/+server.ts @@ -28,15 +28,28 @@ export const GET = async ({ params, locals }) => { // Create a stream for SSE let controller: ReadableStreamDefaultController>; + let keepAliveInterval: NodeJS.Timeout; + const stream = new ReadableStream>({ start(c) { controller = c; addClient(noteId, controller); + // Send initial connection message const encoder = new TextEncoder(); c.enqueue(encoder.encode(`event: connected\n`)); + + // Send keep-alive comment every 15 seconds to prevent timeout + keepAliveInterval = setInterval(() => { + try { + c.enqueue(encoder.encode(`: keep-alive\n\n`)); + } catch (e) { + clearInterval(keepAliveInterval); + } + }, 15000); }, cancel() { + clearInterval(keepAliveInterval); removeClient(noteId, controller); }, }); From 62b06e11ac6a705da23fbda8f363f4d6d2586024 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 14:01:51 -0600 Subject: [PATCH 08/14] feat: add collapsible sidebar with toggle button and dropdown toolbar --- src/lib/components/Sidebar.svelte | 166 ++++++++++-------- src/lib/components/codemirror/Toolbar.svelte | 175 +++++++++++++++++-- src/lib/loro.ts | 2 +- src/routes/+layout.svelte | 51 +++++- 4 files changed, 304 insertions(+), 90 deletions(-) diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index ff2b721..6d1035e 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -10,6 +10,8 @@ Plus, Trash2, Pencil, + ChevronLeft, + ChevronRight, } from "@lucide/svelte"; import type { User } from "$lib/schema.ts"; import ProfilePicture from "./ProfilePicture.svelte"; @@ -39,9 +41,11 @@ interface Props { user: User | undefined; notesList: NoteOrFolder[]; + isCollapsed: boolean; + toggleSidebar: () => void; } - let { user, notesList }: Props = $props(); + let { user, notesList, isCollapsed, toggleSidebar }: Props = $props(); let expandedFolders = new SvelteSet(); let renamingId = $state(null); let renameTitle = $state(""); @@ -205,84 +209,108 @@ diff --git a/src/lib/components/codemirror/Toolbar.svelte b/src/lib/components/codemirror/Toolbar.svelte index 80b5b07..0b1bc92 100644 --- a/src/lib/components/codemirror/Toolbar.svelte +++ b/src/lib/components/codemirror/Toolbar.svelte @@ -1,5 +1,11 @@
- {#each tools as toolset, index (index)} -
- {#each toolset as tool (tool.title)} - {@const Icon = tool.icon} - - {/each} -
-
+ + {#if toggleSidebar && isCollapsed} + +
+ {/if} + + + {#each sortedGroups as group, index (index)} + {#if shouldShowAsButtons(index)} +
+ {#each group.tools as tool (tool.title)} + {@const Icon = tool.icon} + + {/each} +
+
+ {/if} {/each} + + + {#if collapsedGroups.length > 0} + + {/if}
diff --git a/src/lib/loro.ts b/src/lib/loro.ts index d9c2d9e..b80e759 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -192,7 +192,7 @@ export class LoroNoteManager { // For now, just return the current version // In a full implementation, you'd traverse the oplog history.push({ - version: currentVersion.get(this.doc.peerId) || 0, + version: currentVersion.get(this.doc.peerId) ?? 0, timestamp: new Date(), preview: currentText.slice(0, 100), }); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e8d9710..d2a3cc5 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,6 +2,7 @@ import "./layout.css"; import { onNavigate } from "$app/navigation"; + import { onMount } from "svelte"; import favicon from "$lib/assets/favicon.svg"; import Sidebar from "$lib/components/Sidebar.svelte"; import { getNotes } from "$lib/remote/notes.remote.ts"; @@ -10,6 +11,54 @@ const notesList = $derived(data.user ? await getNotes() : []); + // Sidebar collapse state + let isCollapsed = $state(false); + + // Initialize from localStorage and handle responsive behavior + onMount(() => { + // Load saved state from localStorage + const saved = localStorage.getItem("sidebarCollapsed"); + if (saved !== null) { + isCollapsed = saved === "true"; + } else { + // Auto-collapse on mobile screens + isCollapsed = window.innerWidth < 768; + } + + // Handle window resize for automatic collapse + const handleResize = () => { + if (window.innerWidth < 768 && !isCollapsed) { + isCollapsed = true; + } + }; + + window.addEventListener("resize", handleResize); + + // Keyboard shortcut: Ctrl+B (or Cmd+B on Mac) + const handleKeydown = (e: KeyboardEvent) => { + if ((e.ctrlKey || e.metaKey) && e.key === "b") { + e.preventDefault(); + toggleSidebar(); + } + }; + + window.addEventListener("keydown", handleKeydown); + + return () => { + window.removeEventListener("resize", handleResize); + window.removeEventListener("keydown", handleKeydown); + }; + }); + + // Save to localStorage whenever state changes + $effect(() => { + localStorage.setItem("sidebarCollapsed", String(isCollapsed)); + }); + + function toggleSidebar() { + isCollapsed = !isCollapsed; + } + onNavigate((navigation) => { const { promise, resolve } = Promise.withResolvers(); @@ -28,7 +77,7 @@ {#if data.user}
- +
{@render children()}
From 88491ca0a6111bd670903cde3932aa85a4b5950c Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 14:17:32 -0600 Subject: [PATCH 09/14] refactor: centralize sidebar state management with Svelte context, redesign sidebar UI, and update editor toolbar tool group structure. --- src/lib/components/Sidebar.svelte | 74 ++++----- src/lib/components/codemirror/Editor.svelte | 153 ++++++++++--------- src/lib/components/codemirror/Toolbar.svelte | 21 ++- src/lib/components/sidebar-context.ts | 6 + src/routes/+layout.svelte | 21 ++- 5 files changed, 159 insertions(+), 116 deletions(-) create mode 100644 src/lib/components/sidebar-context.ts diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index 6d1035e..bcb01ca 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -12,6 +12,8 @@ Pencil, ChevronLeft, ChevronRight, + PanelLeftClose, + LogOut, } from "@lucide/svelte"; import type { User } from "$lib/schema.ts"; import ProfilePicture from "./ProfilePicture.svelte"; @@ -54,11 +56,14 @@ let notesTree = $derived(buildNotesTree(notesList)); - let rootContainer: HTMLElement; + let rootContainer = $state(); let isRootDropTarget = $state(false); // Set up root drop target - onMount(() => { + // Set up root drop target + $effect(() => { + if (!rootContainer) return; + const cleanup = dropTargetForElements({ element: rootContainer, onDragEnter: () => { @@ -210,46 +215,47 @@ diff --git a/src/lib/components/codemirror/Editor.svelte b/src/lib/components/codemirror/Editor.svelte index 22a5d71..571ab34 100644 --- a/src/lib/components/codemirror/Editor.svelte +++ b/src/lib/components/codemirror/Editor.svelte @@ -136,78 +136,95 @@ ]; const tools = [ - [ - { - title: "Bold (⌘+B)", - onclick: () => boldCommand(editorView), - icon: Bold, - }, - { - title: "Italic (⌘+I)", - onclick: () => italicCommand(editorView), - icon: Italic, - }, - { - title: "Strikethrough (⌘+Shift+X)", - onclick: () => strikethroughCommand(editorView), - icon: Strikethrough, - }, - { - title: "Code (⌘+E)", - onclick: () => codeCommand(editorView), - icon: Code, - }, - ], - [ - { - title: "Link (⌘+K)", - onclick: () => linkCommand(editorView), - icon: Link, - }, - ], - [ - { - title: "Heading 1", - onclick: () => heading1Command(editorView), - icon: Heading1, - }, - { - title: "Heading 2", - onclick: () => heading2Command(editorView), - icon: Heading2, - }, - { - title: "Heading 3", - onclick: () => heading3Command(editorView), - icon: Heading3, - }, - ], - [ - { - onclick: () => bulletListCommand(editorView), - title: "Bullet List", - - icon: List, - }, - { - onclick: () => orderedListCommand(editorView), - title: "Numbered List", - - icon: ListOrdered, - }, - ], - [ - { - onclick: () => (isHistoryOpen = !isHistoryOpen), - title: "Version History", - icon: Clock, - }, - ], + { + priority: 1, + tools: [ + { + title: "Bold (⌘+B)", + onclick: () => boldCommand(editorView), + icon: Bold, + }, + { + title: "Italic (⌘+I)", + onclick: () => italicCommand(editorView), + icon: Italic, + }, + { + title: "Strikethrough (⌘+Shift+X)", + onclick: () => strikethroughCommand(editorView), + icon: Strikethrough, + }, + { + title: "Code (⌘+E)", + onclick: () => codeCommand(editorView), + icon: Code, + }, + ], + }, + { + priority: 2, + tools: [ + { + title: "Link (⌘+K)", + onclick: () => linkCommand(editorView), + icon: Link, + }, + ], + }, + { + priority: 10, + label: "Headings", + tools: [ + { + title: "Heading 1", + onclick: () => heading1Command(editorView), + icon: Heading1, + }, + { + title: "Heading 2", + onclick: () => heading2Command(editorView), + icon: Heading2, + }, + { + title: "Heading 3", + onclick: () => heading3Command(editorView), + icon: Heading3, + }, + ], + }, + { + priority: 5, + label: "Lists", + tools: [ + { + onclick: () => bulletListCommand(editorView), + title: "Bullet List", + + icon: List, + }, + { + onclick: () => orderedListCommand(editorView), + title: "Numbered List", + + icon: ListOrdered, + }, + ], + }, + { + priority: 100, + tools: [ + { + onclick: () => (isHistoryOpen = !isHistoryOpen), + title: "Version History", + icon: Clock, + }, + ], + }, ];
- + diff --git a/src/lib/components/codemirror/Toolbar.svelte b/src/lib/components/codemirror/Toolbar.svelte index 0b1bc92..12c6579 100644 --- a/src/lib/components/codemirror/Toolbar.svelte +++ b/src/lib/components/codemirror/Toolbar.svelte @@ -4,8 +4,13 @@ ChevronRight, ChevronDown, MoreHorizontal, + PanelLeftOpen, } from "@lucide/svelte"; - import { onMount } from "svelte"; + import { onMount, getContext } from "svelte"; + import { + SIDEBAR_CONTEXT_KEY, + type SidebarContext, + } from "$lib/components/sidebar-context"; interface Tool { title: string; @@ -21,11 +26,11 @@ interface Props { toolGroups: ToolGroup[]; - toggleSidebar?: () => void; - isCollapsed?: boolean; } - const { toolGroups, toggleSidebar, isCollapsed = false }: Props = $props(); + const { toolGroups }: Props = $props(); + + const sidebarCtx = getContext(SIDEBAR_CONTEXT_KEY); let toolbarElement: HTMLDivElement; // Initialize with all groups visible by default @@ -56,7 +61,7 @@ let availableWidth = containerWidth - - (toggleSidebar && isCollapsed ? buttonWidth + groupSpacing : 0); + (sidebarCtx?.isCollapsed ? buttonWidth + groupSpacing : 0); let currentVisibleGroups: number[] = []; // Try to fit groups by priority @@ -102,14 +107,14 @@ class="flex items-center gap-1 border-b border-base-content/10 px-2 py-1.5 sm:gap-2 sm:px-4" > - {#if toggleSidebar && isCollapsed} + {#if sidebarCtx?.isCollapsed}
{/if} diff --git a/src/lib/components/sidebar-context.ts b/src/lib/components/sidebar-context.ts new file mode 100644 index 0000000..bd8c70c --- /dev/null +++ b/src/lib/components/sidebar-context.ts @@ -0,0 +1,6 @@ +export const SIDEBAR_CONTEXT_KEY = Symbol("sidebar-context"); + +export interface SidebarContext { + isCollapsed: boolean; + toggleSidebar: () => void; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d2a3cc5..ce00c64 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -6,14 +6,27 @@ import favicon from "$lib/assets/favicon.svg"; import Sidebar from "$lib/components/Sidebar.svelte"; import { getNotes } from "$lib/remote/notes.remote.ts"; + import { setContext } from "svelte"; + import { SIDEBAR_CONTEXT_KEY } from "$lib/components/sidebar-context"; let { children, data } = $props(); - const notesList = $derived(data.user ? await getNotes() : []); - // Sidebar collapse state let isCollapsed = $state(false); + function toggleSidebar() { + isCollapsed = !isCollapsed; + } + + setContext(SIDEBAR_CONTEXT_KEY, { + get isCollapsed() { + return isCollapsed; + }, + toggleSidebar, + }); + + const notesList = $derived(data.user ? await getNotes() : []); + // Initialize from localStorage and handle responsive behavior onMount(() => { // Load saved state from localStorage @@ -55,10 +68,6 @@ localStorage.setItem("sidebarCollapsed", String(isCollapsed)); }); - function toggleSidebar() { - isCollapsed = !isCollapsed; - } - onNavigate((navigation) => { const { promise, resolve } = Promise.withResolvers(); From d03ccb48cf0dbd80e4f16d99f32172ab1c4374d2 Mon Sep 17 00:00:00 2001 From: ParkerH27 Date: Mon, 8 Dec 2025 14:45:40 -0600 Subject: [PATCH 10/14] fix: Update sidebar collapse button class from `btn-sq` to `btn-square`. --- src/lib/components/Sidebar.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index bcb01ca..4e9540c 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -251,7 +251,7 @@
{/if} - - {#each sortedGroups as group, index (index)} - {#if shouldShowAsButtons(index)} -
- {#each group.tools as tool (tool.title)} - {@const Icon = tool.icon} - - {/each} -
-
+ + {#each sortedGroups as group, i (group.label ?? group.priority)} + {@const isLast = i === sortedGroups.length - 1} + {@const priorityClass = + group.priority === 1 + ? "" + : group.priority === 2 + ? "hidden @md:flex" + : "hidden @lg:flex"} +
+ {#each group.tools as tool (tool.title)} + {@const Icon = tool.icon} + + {/each} +
+ {#if !isLast} +
{/if} {/each} - - {#if collapsedGroups.length > 0} - diff --git a/src/lib/components/sidebar-context.ts b/src/lib/components/sidebar-context.ts index bd8c70c..f874446 100644 --- a/src/lib/components/sidebar-context.ts +++ b/src/lib/components/sidebar-context.ts @@ -1,6 +1,9 @@ -export const SIDEBAR_CONTEXT_KEY = Symbol("sidebar-context"); +import { createContext } from "svelte"; export interface SidebarContext { isCollapsed: boolean; toggleSidebar: () => void; } + +export const [getSidebarContext, setSidebarContext] = + createContext(); diff --git a/src/lib/loro.ts b/src/lib/loro.ts index b80e759..9377ed1 100644 --- a/src/lib/loro.ts +++ b/src/lib/loro.ts @@ -174,16 +174,16 @@ export class LoroNoteManager { * Get version history with user attribution * Returns an array of version snapshots */ - getHistory(): Array<{ + getHistory(): { version: number; timestamp: Date; preview: string; - }> { - const history: Array<{ + }[] { + const history: { version: number; timestamp: Date; preview: string; - }> = []; + }[] = []; // Get current version const currentVersion = this.doc.version(); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index ce00c64..33f416d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -6,8 +6,7 @@ import favicon from "$lib/assets/favicon.svg"; import Sidebar from "$lib/components/Sidebar.svelte"; import { getNotes } from "$lib/remote/notes.remote.ts"; - import { setContext } from "svelte"; - import { SIDEBAR_CONTEXT_KEY } from "$lib/components/sidebar-context"; + import { setSidebarContext } from "$lib/components/sidebar-context.js"; let { children, data } = $props(); @@ -18,7 +17,7 @@ isCollapsed = !isCollapsed; } - setContext(SIDEBAR_CONTEXT_KEY, { + setSidebarContext({ get isCollapsed() { return isCollapsed; }, From 9a47db6e1946f89a879f34da897ce9a049ec1a77 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:06:57 -0600 Subject: [PATCH 12/14] feat: versions and times and shtuffies --- package.json | 1 + pnpm-lock.yaml | 15 ++++++ src/lib/components/HistoryPanel.svelte | 36 ++++----------- src/lib/loro.ts | 64 +++++++++++++++++--------- src/lib/remote/accounts.remote.ts | 4 +- src/lib/utils/time.ts | 28 +++++++++++ src/routes/+page.svelte | 10 ++-- 7 files changed, 106 insertions(+), 52 deletions(-) create mode 100644 src/lib/utils/time.ts diff --git a/package.json b/package.json index fbc690a..59b5f9c 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "loro-codemirror": "^0.3.3", "loro-crdt": "^1.10.0", "svelte": "^5.44.0", + "temporal-polyfill": "^0.3.0", "tiptap-markdown": "^0.9.0", "typescript-svelte-plugin": "^0.3.50" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9b6e78..3663c2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,6 +143,9 @@ importers: svelte: specifier: ^5.44.0 version: 5.44.0 + temporal-polyfill: + specifier: ^0.3.0 + version: 0.3.0 tiptap-markdown: specifier: ^0.9.0 version: 0.9.0(@tiptap/core@3.11.0(@tiptap/pm@3.11.0)) @@ -3175,6 +3178,12 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + temporal-polyfill@0.3.0: + resolution: {integrity: sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==} + + temporal-spec@0.3.0: + resolution: {integrity: sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -6609,6 +6618,12 @@ snapshots: tapable@2.3.0: {} + temporal-polyfill@0.3.0: + dependencies: + temporal-spec: 0.3.0 + + temporal-spec@0.3.0: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index 1152f10..9b63bdc 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -1,7 +1,7 @@ {#if isOpen} @@ -114,20 +95,22 @@
- {#if entry.author} + {#if entry.peerId}
- {entry.author[0].toUpperCase()} + {entry.peerId.slice(0, 2).toUpperCase()}
- {entry.author} + {entry.peerId.slice(0, 8)} {:else} Unknown {/if}
- {formatTime(entry.timestamp)} + {formatRelativeTime(entry.timestamp)}
@@ -157,9 +140,10 @@ {#if selectedVersion !== null && selectedVersion !== history[0]?.version} + {@const cachedVersion = selectedVersion}
From f5991912c6da9034102ae1fc1763c1526b5e2289 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Tue, 9 Dec 2025 23:00:53 -0600 Subject: [PATCH 13/14] feat: enhance sidebar logic --- .vscode/mcp.json | 36 +- package.json | 3 +- pnpm-lock.yaml | 672 ++--------------------- src/lib/components/ProfilePicture.svelte | 2 +- src/routes/+layout.svelte | 93 ++-- src/routes/api/sync/[noteId]/+server.ts | 2 +- 6 files changed, 106 insertions(+), 702 deletions(-) diff --git a/.vscode/mcp.json b/.vscode/mcp.json index a808733..600e2de 100644 --- a/.vscode/mcp.json +++ b/.vscode/mcp.json @@ -6,14 +6,21 @@ }, "ESLint": { "type": "stdio", - "command": "npx", - "args": ["@eslint/mcp@latest"] + "command": "pnpm", + "args": [ + "dlx", + "--package=jiti", + "--package=@eslint/mcp@latest", + "-s", + "mcp" + ] }, "io.github.upstash/context7": { "type": "stdio", - "command": "npx", + "command": "pnpm", "args": [ - "-y", + "dlx", + "-s", "@upstash/context7-mcp@latest", "--api-key", "${input:CONTEXT7_API_KEY}" @@ -21,26 +28,13 @@ }, "io.github.ChromeDevTools/chrome-devtools-mcp": { "type": "stdio", - "command": "npx", - "args": ["chrome-devtools-mcp@0.10.2"] - }, - "oraios/serena": { - "type": "stdio", - "command": "uvx", - "args": [ - "--from", - "git+https://github.com/oraios/serena", - "serena", - "start-mcp-server", - "serena==latest", - "--context", - "ide-assistant" - ] + "command": "pnpm", + "args": ["dlx", "-s", "chrome-devtools-mcp@0.10.2"] }, "socket-mcp": { "type": "stdio", - "command": "npx", - "args": ["@socketsecurity/mcp@latest"], + "command": "pnpm", + "args": ["dlx", "-s", "@socketsecurity/mcp@latest"], "env": { "SOCKET_API_KEY": "${input:socket_api_key}" } diff --git a/package.json b/package.json index 59b5f9c..c28c672 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "eslint": "^9.39.1", "eslint-plugin-svelte": "^3.13.0", "globals": "^16.5.0", + "jiti": "^2.6.1", "playwright": "^1.56.1", "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", @@ -75,7 +76,6 @@ "@milkdown/preset-gfm": "^7.17.1", "@milkdown/theme-nord": "^7.17.1", "@milkdown/utils": "^7.17.1", - "@modelcontextprotocol/sdk": "^1.22.0", "@node-rs/argon2": "^2.0.2", "@prosemark/core": "^0.0.4", "@prosemark/paste-rich-text": "^0.0.2", @@ -93,6 +93,7 @@ "katex": "^0.16.25", "loro-codemirror": "^0.3.3", "loro-crdt": "^1.10.0", + "runed": "^0.37.0", "svelte": "^5.44.0", "temporal-polyfill": "^0.3.0", "tiptap-markdown": "^0.9.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3663c2a..17c2faf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,9 +86,6 @@ importers: '@milkdown/utils': specifier: ^7.17.1 version: 7.17.1 - '@modelcontextprotocol/sdk': - specifier: ^1.22.0 - version: 1.22.0 '@node-rs/argon2': specifier: ^2.0.2 version: 2.0.2 @@ -140,6 +137,9 @@ importers: loro-crdt: specifier: ^1.10.0 version: 1.10.0 + runed: + specifier: ^0.37.0 + version: 0.37.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.44.0)(zod@4.1.13) svelte: specifier: ^5.44.0 version: 5.44.0 @@ -204,6 +204,9 @@ importers: globals: specifier: ^16.5.0 version: 16.5.0 + jiti: + specifier: ^2.6.1 + version: 2.6.1 playwright: specifier: ^1.56.1 version: 1.56.1 @@ -917,15 +920,6 @@ packages: '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} - '@modelcontextprotocol/sdk@1.22.0': - resolution: {integrity: sha512-VUpl106XVTCpDmTBil2ehgJZjhyLY2QZikzF8NvTXtLRF1CvO5iEE2UNZdVIUer35vFOwMKYeUGbjJtvPWan3g==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] @@ -1693,10 +1687,6 @@ packages: resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1707,14 +1697,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -1749,10 +1731,6 @@ packages: bind-event-listener@3.0.0: resolution: {integrity: sha512-PJvH288AWQhKs2v9zyfYdPzlPqf5bXbGMmhmUIY9x4dAUGIWgomO771oBQNwJnMQSnUIXhKu6sgzpBRXTlvb8Q==} - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1766,18 +1744,6 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1821,30 +1787,10 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -1886,10 +1832,6 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2011,23 +1953,12 @@ packages: sqlite3: optional: true - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - effect@3.19.6: resolution: {integrity: sha512-Eh1E/CI+xCAcMSDC5DtyE29yWJINC0zwBbwHappQPorjKyS69rCA8qzpsHpfhKnPDYgxdg8zkknii8mZ+6YMQA==} emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} @@ -2036,18 +1967,6 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -2063,9 +1982,6 @@ packages: engines: {node: '>=18'} hasBin: true - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -2132,28 +2048,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} - extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -2201,10 +2095,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} - find-my-way-ts@0.1.6: resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==} @@ -2223,14 +2113,6 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2241,17 +2123,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} @@ -2271,10 +2142,6 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2285,26 +2152,6 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - iconv-lite@0.7.0: - resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} - engines: {node: '>=0.10.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2321,13 +2168,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2344,9 +2184,6 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -2505,6 +2342,10 @@ packages: loro-crdt@1.10.0: resolution: {integrity: sha512-Fms27q9IaDANUe5OACQL6qLMhJasMXzjRkyK+NAIiPQXGBK2VAp6C7pAr9fzuKbL71YyDgA4Pv69RGwiScWSPg==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2518,10 +2359,6 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} @@ -2561,14 +2398,6 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2661,14 +2490,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2710,10 +2531,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -2731,21 +2548,6 @@ packages: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2765,10 +2567,6 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2777,9 +2575,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2791,10 +2586,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} - engines: {node: '>=16.20.0'} - playwright-core@1.56.1: resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} engines: {node: '>=18'} @@ -2975,10 +2766,6 @@ packages: prosemirror-view@1.41.3: resolution: {integrity: sha512-SqMiYMUQNNBP9kfPhLO8WXEk/fon47vc52FQsUiJzTBuyjKgEcoAwMyF04eQ4WZ2ArMn7+ReypYL60aKngbACQ==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -2990,24 +2777,12 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} raf-schd@4.0.3: resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -3050,20 +2825,25 @@ packages: rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + runed@0.37.0: + resolution: {integrity: sha512-zphHjvLZEpcJiV3jezT96SnNwePaUIEd1HEMuPGZ6DwOMao9S2ZAUCYJPKquRM5J22AwAOpGj0KmxOkQdkBfwQ==} + peerDependencies: + '@sveltejs/kit': ^2.21.0 + svelte: ^5.7.0 + zod: ^4.1.0 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + zod: + optional: true + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - scule@1.3.0: resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} @@ -3072,20 +2852,9 @@ packages: engines: {node: '>=10'} hasBin: true - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} - set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3094,22 +2863,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -3129,10 +2882,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -3197,10 +2946,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -3224,10 +2969,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - typescript-eslint@8.47.0: resolution: {integrity: sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3268,10 +3009,6 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -3286,10 +3023,6 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -3375,9 +3108,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -3406,13 +3136,8 @@ packages: zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} - zod-to-json-schema@3.25.0: - resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} - peerDependencies: - zod: ^3.25 || ^4 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -4251,24 +3976,6 @@ snapshots: '@mixmark-io/domino@2.2.0': {} - '@modelcontextprotocol/sdk@1.22.0': - dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - content-type: 1.0.5 - cors: 2.8.5 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) - transitivePeerDependencies: - - supports-color - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -4985,21 +4692,12 @@ snapshots: '@typescript-eslint/types': 8.47.0 eslint-visitor-keys: 4.2.1 - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} - ajv-formats@3.0.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -5032,20 +4730,6 @@ snapshots: bind-event-listener@3.0.0: {} - body-parser@2.2.0: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.6.3 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -5061,18 +4745,6 @@ snapshots: buffer-from@1.1.2: {} - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsites@3.1.0: {} ccount@2.0.1: {} @@ -5112,21 +4784,8 @@ snapshots: concat-map@0.0.1: {} - content-disposition@1.0.1: {} - - content-type@1.0.5: {} - - cookie-signature@1.2.2: {} - cookie@0.6.0: {} - cookie@0.7.2: {} - - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - crelt@1.0.6: {} cross-spawn@7.0.6: @@ -5155,8 +4814,6 @@ snapshots: deepmerge@4.3.1: {} - depd@2.0.0: {} - dequal@2.0.3: {} detect-libc@2.0.2: {} @@ -5188,14 +4845,6 @@ snapshots: optionalDependencies: '@libsql/client': 0.15.15 - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ee-first@1.1.1: {} - effect@3.19.6: dependencies: '@standard-schema/spec': 1.0.0 @@ -5203,8 +4852,6 @@ snapshots: emojilib@2.4.0: {} - encodeurl@2.0.0: {} - enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 @@ -5212,14 +4859,6 @@ snapshots: entities@4.5.0: {} - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - esbuild-register@3.6.0(esbuild@0.25.12): dependencies: debug: 4.4.3 @@ -5281,8 +4920,6 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - escape-html@1.0.3: {} - escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -5379,50 +5016,6 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} - - eventsource-parser@3.0.6: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.0.6 - - express-rate-limit@7.5.1(express@5.1.0): - dependencies: - express: 5.1.0 - - express@5.1.0: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.1 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.0 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - extend@3.0.2: {} fast-check@3.23.2: @@ -5466,17 +5059,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.0: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - find-my-way-ts@0.1.6: {} find-up@5.0.0: @@ -5495,36 +5077,12 @@ snapshots: dependencies: fetch-blob: 3.2.0 - forwarded@0.2.0: {} - - fresh@2.0.0: {} - fsevents@2.3.2: optional: true fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -5541,36 +5099,12 @@ snapshots: globals@16.5.0: {} - gopd@1.2.0: {} - graceful-fs@4.2.11: {} graphemer@1.4.0: {} has-flag@4.0.0: {} - has-symbols@1.1.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - iconv-lite@0.7.0: - dependencies: - safer-buffer: 2.1.2 - ignore@5.3.2: {} ignore@7.0.5: {} @@ -5582,10 +5116,6 @@ snapshots: imurmurhash@0.1.4: {} - inherits@2.0.4: {} - - ipaddr.js@1.9.1: {} - is-extglob@2.1.1: {} is-glob@4.0.3: @@ -5596,8 +5126,6 @@ snapshots: is-plain-obj@4.1.0: {} - is-promise@4.0.0: {} - is-reference@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -5729,6 +5257,8 @@ snapshots: loro-crdt@1.10.0: {} + lz-string@1.5.0: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -5746,8 +5276,6 @@ snapshots: markdown-table@3.0.4: {} - math-intrinsics@1.1.0: {} - mdast-util-definitions@6.0.0: dependencies: '@types/mdast': 4.0.4 @@ -5858,10 +5386,6 @@ snapshots: mdurl@2.0.0: {} - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - merge2@1.4.1: {} micromark-core-commonmark@2.0.3: @@ -6060,12 +5584,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.54.0: {} - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -6104,8 +5622,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@1.0.0: {} - node-domexception@1.0.0: {} node-emoji@2.2.0: @@ -6126,18 +5642,6 @@ snapshots: detect-libc: 2.1.2 optional: true - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6161,22 +5665,16 @@ snapshots: dependencies: callsites: 3.1.0 - parseurl@1.3.3: {} - path-exists@4.0.0: {} path-key@3.1.1: {} - path-to-regexp@8.3.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} - pkce-challenge@5.0.0: {} - playwright-core@1.56.1: {} playwright@1.56.1: @@ -6341,34 +5839,16 @@ snapshots: prosemirror-state: 1.4.4 prosemirror-transform: 1.10.5 - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - punycode.js@2.3.1: {} punycode@2.3.1: {} pure-rand@6.1.0: {} - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - queue-microtask@1.2.3: {} raf-schd@4.0.3: {} - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.0 - unpipe: 1.0.0 - readdirp@4.1.2: {} remark-gfm@4.0.1: @@ -6450,93 +5930,36 @@ snapshots: rope-sequence@1.3.4: {} - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.3.0 - transitivePeerDependencies: - - supports-color - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + runed@0.37.0(@sveltejs/kit@2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.44.0)(zod@4.1.13): + dependencies: + dequal: 2.0.3 + esm-env: 1.2.2 + lz-string: 1.5.0 + svelte: 5.44.0 + optionalDependencies: + '@sveltejs/kit': 2.49.0(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.44.0)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + zod: 4.1.13 + sade@1.8.1: dependencies: mri: 1.2.0 - safer-buffer@2.1.2: {} - scule@1.3.0: {} semver@7.7.3: {} - send@1.2.0: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.0: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.0 - transitivePeerDependencies: - - supports-color - set-cookie-parser@2.7.2: {} - setprototypeof@1.2.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -6556,8 +5979,6 @@ snapshots: source-map@0.6.1: {} - statuses@2.0.2: {} - strip-json-comments@3.1.1: {} style-mod@4.1.3: {} @@ -6641,8 +6062,6 @@ snapshots: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - totalist@3.0.1: {} trough@2.2.0: {} @@ -6662,12 +6081,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - typescript-eslint@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) @@ -6724,8 +6137,6 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - unpipe@1.0.0: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -6736,8 +6147,6 @@ snapshots: uuid@11.1.0: {} - vary@1.1.2: {} - vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 @@ -6797,8 +6206,6 @@ snapshots: word-wrap@1.2.5: {} - wrappy@1.0.2: {} - ws@8.18.3: {} yaml@1.10.2: {} @@ -6810,10 +6217,7 @@ snapshots: zimmerframe@1.1.4: {} - zod-to-json-schema@3.25.0(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.25.76: {} + zod@4.1.13: + optional: true zwitch@2.0.4: {} diff --git a/src/lib/components/ProfilePicture.svelte b/src/lib/components/ProfilePicture.svelte index 4237a18..f14b84b 100644 --- a/src/lib/components/ProfilePicture.svelte +++ b/src/lib/components/ProfilePicture.svelte @@ -7,7 +7,7 @@
{name[0]?.toUpperCase()}
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 33f416d..78d1a24 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,70 +2,73 @@ import "./layout.css"; import { onNavigate } from "$app/navigation"; - import { onMount } from "svelte"; import favicon from "$lib/assets/favicon.svg"; import Sidebar from "$lib/components/Sidebar.svelte"; import { getNotes } from "$lib/remote/notes.remote.ts"; import { setSidebarContext } from "$lib/components/sidebar-context.js"; + import { PersistedState } from "runed"; let { children, data } = $props(); - // Sidebar collapse state - let isCollapsed = $state(false); + // User's explicit preference (persisted to localStorage) + const collapsedDesktop = new PersistedState("sidebarCollapsed", false); + // Mobile state (always starts collapsed) + let collapsedMobile = $state(true); - function toggleSidebar() { - isCollapsed = !isCollapsed; - } + // Track window width + let innerWidth = $state(0); + let isDesktop = $derived(innerWidth >= 768); - setSidebarContext({ - get isCollapsed() { - return isCollapsed; - }, - toggleSidebar, - }); + // Derived visual state + let isCollapsed = $derived( + isDesktop ? collapsedDesktop.current : collapsedMobile, + ); - const notesList = $derived(data.user ? await getNotes() : []); + // Handle transitions between breakpoints + let wasDesktop = $state(true); - // Initialize from localStorage and handle responsive behavior - onMount(() => { - // Load saved state from localStorage - const saved = localStorage.getItem("sidebarCollapsed"); - if (saved !== null) { - isCollapsed = saved === "true"; - } else { - // Auto-collapse on mobile screens - isCollapsed = window.innerWidth < 768; + $effect(() => { + if (innerWidth === 0) return; + + // Desktop -> Mobile: Always collapse + if (wasDesktop && !isDesktop) { + collapsedMobile = true; } - // Handle window resize for automatic collapse - const handleResize = () => { - if (window.innerWidth < 768 && !isCollapsed) { - isCollapsed = true; + // Mobile -> Desktop: If mobile was open, keep open + if (!wasDesktop && isDesktop) { + if (!collapsedMobile) { + collapsedDesktop.current = false; } - }; + } - window.addEventListener("resize", handleResize); + wasDesktop = isDesktop; + }); - // Keyboard shortcut: Ctrl+B (or Cmd+B on Mac) - const handleKeydown = (e: KeyboardEvent) => { - if ((e.ctrlKey || e.metaKey) && e.key === "b") { - e.preventDefault(); - toggleSidebar(); - } - }; + function toggleSidebar() { + if (isDesktop) { + collapsedDesktop.current = !collapsedDesktop.current; + } else { + collapsedMobile = !collapsedMobile; + } + } - window.addEventListener("keydown", handleKeydown); + // Keyboard shortcut: Ctrl+\ (or Cmd+\ on Mac) + function handleKeydown(e: KeyboardEvent) { + if ((e.ctrlKey || e.metaKey) && e.key === "\\") { + e.preventDefault(); + toggleSidebar(); + } + } - return () => { - window.removeEventListener("resize", handleResize); - window.removeEventListener("keydown", handleKeydown); - }; + setSidebarContext({ + get isCollapsed() { + return isCollapsed; + }, + toggleSidebar, }); - // Save to localStorage whenever state changes - $effect(() => { - localStorage.setItem("sidebarCollapsed", String(isCollapsed)); - }); + const notesList = $derived(data.user ? await getNotes() : []); onNavigate((navigation) => { const { promise, resolve } = Promise.withResolvers(); @@ -79,6 +82,8 @@ }); + + diff --git a/src/routes/api/sync/[noteId]/+server.ts b/src/routes/api/sync/[noteId]/+server.ts index 0581705..9c794a9 100644 --- a/src/routes/api/sync/[noteId]/+server.ts +++ b/src/routes/api/sync/[noteId]/+server.ts @@ -43,7 +43,7 @@ export const GET = async ({ params, locals }) => { keepAliveInterval = setInterval(() => { try { c.enqueue(encoder.encode(`: keep-alive\n\n`)); - } catch (e) { + } catch { clearInterval(keepAliveInterval); } }, 15000); From a8e469e42f5109968ead88b08f58fec83bb8ceb8 Mon Sep 17 00:00:00 2001 From: Eli <88557639+lishaduck@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:30:26 -0600 Subject: [PATCH 14/14] feat: improve history --- AGENTS.md | 39 +------- src/lib/components/HistoryPanel.svelte | 105 +++++++++++++++----- src/lib/components/ProfilePicture.svelte | 4 +- src/lib/components/Sidebar.svelte | 2 +- src/lib/components/codemirror/Editor.svelte | 53 +++++----- 5 files changed, 109 insertions(+), 94 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2db9ea2..ddafa9b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -183,39 +183,6 @@ Lints specified files and returns errors/warnings. Use this to validate your cod **Usage:** `mcp_eslint_lint-files` with an array of absolute file paths. -### 4. Serena MCP Server (`mcp_oraios_serena_*`) - -Intelligent code navigation and symbolic editing: - -#### Code Exploration - -- `get_symbols_overview` - Get high-level view of symbols in a file (use this FIRST) -- `find_symbol` - Find and read specific symbols by name path -- `find_referencing_symbols` - Find where symbols are used -- `search_for_pattern` - Flexible regex-based code search - -#### Code Editing - -- `replace_symbol_body` - Replace entire symbol body (methods, classes, etc.) -- `insert_after_symbol` - Insert code after a symbol -- `insert_before_symbol` - Insert code before a symbol -- `rename_symbol` - Rename symbols throughout codebase - -#### Memory Management - -- `write_memory` - Save project information for future reference -- `read_memory` - Retrieve saved project context -- `edit_memory` - Update existing memories -- `delete_memory` - Remove outdated memories - -#### Project Management - -- `activate_project` - Switch between registered projects -- `get_current_config` - View current configuration - -> [!TIP] -> Use symbolic tools to read only necessary code. Start with `get_symbols_overview` before reading full files. - ### 5. Socket MCP Server (`mcp__extension_so_depscore`) Dependency security and quality scoring: @@ -504,14 +471,14 @@ Since Svelte 5.25, you can reassign `$derived` values to temporarily override th When using SvelteKit remote functions, you can use `.updates()` with `.withOverride()` to optimistically update the cache of a query. ```typescript -import { getPosts, createPost } from '$lib/remote/posts.remote'; +import { getPosts, createPost } from "$lib/remote/posts.remote"; async function handleSubmit() { - const newPost = { id: 'temp', title: 'New Post' }; + const newPost = { id: "temp", title: "New Post" }; // Optimistically update the getPosts query cache await createPost(newPost).updates( - getPosts().withOverride((posts) => [newPost, ...posts]) + getPosts().withOverride((posts) => [newPost, ...posts]), ); } ``` diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index 9b63bdc..39ea839 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -2,18 +2,22 @@ import { Clock, RotateCcw, User } from "@lucide/svelte"; import type { HistoryEntry, LoroNoteManager } from "$lib/loro.ts"; import { formatRelativeTime } from "$lib/utils/time.ts"; + import ProfilePicture from "./ProfilePicture.svelte"; interface Props { manager: LoroNoteManager | undefined; isOpen: boolean; - onClose: () => void; } - let { manager, isOpen, onClose }: Props = $props(); + let { manager, isOpen = $bindable() }: Props = $props(); let history = $state([]); let selectedVersion = $state(null); - let unsubscribe: (() => void) | null = null; + let unsubscribe: (() => void) | undefined; + let drawerDialog: HTMLDialogElement; + let restoreDialog: HTMLDialogElement; + let versionToRestore = $state(null); + let isClosing = $state(false); // Load history from Loro document function loadHistory() { @@ -37,22 +41,53 @@ } return () => { - if (unsubscribe) { - unsubscribe(); - unsubscribe = null; - } + unsubscribe?.(); + unsubscribe = undefined; }; }); - function restoreVersion(version: number) { - // TODO: Implement version restoration using Loro's checkout functionality - console.log("Restoring version:", version); + // Sync isOpen with dialog + $effect(() => { + if (isOpen) { + isClosing = false; + if (!drawerDialog.open) drawerDialog.showModal(); + } else { + if (drawerDialog.open) { + isClosing = true; + setTimeout(() => { + drawerDialog.close(); + isClosing = false; + }, 300); + } + } + }); + + function promptRestore(version: number) { + versionToRestore = version; + restoreDialog.showModal(); + } + + function confirmRestore() { + if (versionToRestore !== null) { + // TODO: Implement version restoration using Loro's checkout functionality + console.log("Restoring version:", versionToRestore); + versionToRestore = null; + } } -{#if isOpen} + { + isOpen = false; + }} +>
Version History
{/if}
+ + - - -{/if} + + + + diff --git a/src/lib/components/ProfilePicture.svelte b/src/lib/components/ProfilePicture.svelte index f14b84b..4094981 100644 --- a/src/lib/components/ProfilePicture.svelte +++ b/src/lib/components/ProfilePicture.svelte @@ -7,7 +7,7 @@
- {name[0]?.toUpperCase()} + {name.toUpperCase()}
diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index ccf0f62..7232818 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -225,7 +225,7 @@ role="button" class="btn h-auto min-h-0 gap-3 rounded-lg px-3 py-2 normal-case btn-ghost hover:bg-base-200" > - + {user?.username ?? "Anonymous"} diff --git a/src/lib/components/codemirror/Editor.svelte b/src/lib/components/codemirror/Editor.svelte index 571ab34..1f2969f 100644 --- a/src/lib/components/codemirror/Editor.svelte +++ b/src/lib/components/codemirror/Editor.svelte @@ -106,34 +106,35 @@ }, }); - let loroExtensions: Extension; - if (manager !== undefined && user !== undefined) { - const ephemeral = new EphemeralStore(); - const undoManager = new UndoManager(manager.doc, {}); - - onDestroy(() => { - ephemeral.destroy(); - }); - - loroExtensions = LoroExtensions( - manager.doc, - { - ephemeral, - user: { name: user.username, colorClassName: "bg-primary" }, - }, - undoManager, - LoroNoteManager.getTextFromDoc, - ); - } else { - loroExtensions = []; - } + let loroExtensions = $state([]); + + $effect.pre(() => { + if (manager !== undefined && user !== undefined) { + const ephemeral = new EphemeralStore(); + const undoManager = new UndoManager(manager.doc, {}); + + onDestroy(() => { + ephemeral.destroy(); + }); + + loroExtensions = LoroExtensions( + manager.doc, + { + ephemeral, + user: { name: user.username, colorClassName: "bg-primary" }, + }, + undoManager, + LoroNoteManager.getTextFromDoc, + ); + } + }); - const extensions: Extension[] = [ + const extensions: Extension[] = $derived([ coreExtensions, wikilinksExtension(notesList), loroExtensions, editorTheme, - ]; + ]); const tools = [ { @@ -228,9 +229,5 @@ - (isHistoryOpen = false)} - /> +